bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if(!&creature) return true; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED | UNIT_STAT_ON_VEHICLE)) return true; // prevent a crash at empty waypoint path. if(!i_path || i_path->empty()) return true; // i_path was modified by chat commands for example if(i_path->size() != i_hasDone.size()) i_hasDone.resize(i_path->size()); if(i_currentNode >= i_path->size()) i_currentNode = 0; CreatureTraveller traveller(creature); i_nextMoveTime.Update(diff); i_destinationHolder.UpdateTraveller(traveller, diff, false, true); // creature has been stopped in middle of the waypoint segment if (!i_destinationHolder.HasArrived() && creature.IsStopped()) { if( i_nextMoveTime.Passed()) // Timer has elapsed, meaning this part controlled it { SetStoppedByPlayer(false); // Now we re-set destination to same node and start travel creature.addUnitState(UNIT_STAT_ROAMING); if (creature.canFly()) creature.AddMonsterMoveFlag(MONSTER_MOVE_FLY); const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); } else // if( !i_nextMoveTime.Passed()) { // unexpected end of timer && creature stopped && not at end of segment if (!IsStoppedByPlayer()) { // Put 30 seconds delay i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); SetStoppedByPlayer(true); // Mark we did it } } return true; // Abort here this update } if( creature.IsStopped()) { uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (!i_hasDone[idx]) { if (i_path->at(idx).orientation !=100) creature.SetOrientation(i_path->at(idx).orientation); if(WaypointBehavior *behavior = i_path->at(idx).behavior) { if(behavior->emote != 0) creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,behavior->emote); if(behavior->spell != 0) creature.CastSpell(&creature,behavior->spell, false); if(behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if(behavior->textid[0]) { // Not only one text is set if( behavior->textid[1] ) { // Select one from max 5 texts (0 and 1 laready checked) int i = 2; for( ; i < MAX_WAYPOINT_TEXT; ++i ) if( !behavior->textid[i] ) break; creature.Say(behavior->textid[rand() % i], 0, 0); } else creature.Say(behavior->textid[0], 0, 0); } } // wpBehaviour found i_hasDone[idx] = true; MovementInform(creature); } // HasDone == false } // i_creature.IsStopped() if( i_nextMoveTime.Passed() ) // This is at the end of waypoint segment or has been stopped by player { if( creature.IsStopped() ) // If stopped then begin a new move segment { creature.addUnitState(UNIT_STAT_ROAMING); if (creature.canFly()) creature.AddMonsterMoveFlag(MONSTER_MOVE_FLY); const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (i_path->at(idx).orientation !=100) creature.SetOrientation(i_path->at(idx).orientation); if(WaypointBehavior *behavior = i_path->at(idx).behavior ) { i_hasDone[idx] = false; if(behavior->model2 != 0) creature.SetDisplayId(behavior->model2); creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); } } else // If not stopped then stop it and set the reset of TimeTracker to waittime { creature.StopMoving(); SetStoppedByPlayer(false); i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); ++i_currentNode; if( i_currentNode >= i_path->size() ) i_currentNode = 0; } } return true; }
void WorldSession::SendListInventory( uint64 vendorguid ) { sLog.outDebug( "WORLD: Sent SMSG_LIST_INVENTORY" ); Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, vendorguid,UNIT_NPC_FLAG_VENDOR); if (!pCreature) { sLog.outDebug( "WORLD: SendListInventory - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) ); _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); return; } // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); // Stop the npc if moving pCreature->StopMoving(); VendorItemData const* vItems = pCreature->GetVendorItems(); if(!vItems) { _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); return; } uint8 numitems = vItems->GetItemCount(); uint8 count = 0; WorldPacket data( SMSG_LIST_INVENTORY, (8+1+numitems*8*4) ); data << uint64(vendorguid); data << uint8(numitems); float discountMod = _player->GetReputationPriceDiscount(pCreature); for(int i = 0; i < numitems; ++i ) { if(VendorItem const* crItem = vItems->GetItem(i)) { if(ItemPrototype const *pProto = objmgr.GetItemPrototype(crItem->item)) { if((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster()) continue; ++count; // reputation discount uint32 price = uint32(floor(pProto->BuyPrice * discountMod)); data << uint32(count); data << uint32(crItem->item); data << uint32(pProto->DisplayInfoID); data << uint32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem)); data << uint32(price); data << uint32(pProto->MaxDurability); data << uint32(pProto->BuyCount); data << uint32(crItem->ExtendedCost); } } } if ( count == 0 || data.size() != 8 + 1 + size_t(count) * 8 * 4 ) return; data.put<uint8>(8, count); SendPacket( &data ); }
void WorldSession::HandleGossipHelloOpcode(WorldPacket & recvData) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GOSSIP_HELLO"); #endif uint64 guid; recvData >> guid; Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); if (!unit) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); #endif return; } // xinef: check if we have ANY npc flags if (unit->GetUInt32Value(UNIT_NPC_FLAGS) == UNIT_NPC_FLAG_NONE) return; // xinef: do not allow to open gossip when npc is in combat if (unit->GetUInt32Value(UNIT_NPC_FLAGS) == UNIT_NPC_FLAG_GOSSIP && unit->IsInCombat()) // should work on all flags? return; // set faction visible if needed if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction())) _player->GetReputationMgr().SetVisible(factionTemplateEntry); GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); // remove fake death //if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) // GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); // xinef: and if he has pure gossip or is banker and moves or is tabard designer? //if (unit->IsArmorer() || unit->IsCivilian() || unit->IsQuestGiver() || unit->IsServiceProvider() || unit->IsGuard()) { //if (!unit->GetTransport()) // pussywizard: reverted with new spline (old: without this check, npc would stay in place and the transport would continue moving, so the npc falls off. NPCs on transports don't have waypoints, so stopmoving is not needed) unit->StopMoving(); } // If spiritguide, no need for gossip menu, just put player into resurrect queue if (unit->IsSpiritGuide()) { Battleground* bg = _player->GetBattleground(); if (bg) { bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID()); sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID()); return; } } if (!sScriptMgr->OnGossipHello(_player, unit)) { // _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); _player->PrepareGossipMenu(unit, unit->GetCreatureTemplate()->GossipMenuId, true); _player->SendPreparedGossip(unit); } unit->AI()->sGossipHello(_player); }
void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GOSSIP_HELLO"); ObjectGuid guid; guid[2] = recvData.ReadBit(); guid[3] = recvData.ReadBit(); guid[0] = recvData.ReadBit(); guid[7] = recvData.ReadBit(); guid[5] = recvData.ReadBit(); guid[4] = recvData.ReadBit(); guid[6] = recvData.ReadBit(); guid[1] = recvData.ReadBit(); recvData.ReadByteSeq(guid[2]); recvData.ReadByteSeq(guid[6]); recvData.ReadByteSeq(guid[0]); recvData.ReadByteSeq(guid[3]); recvData.ReadByteSeq(guid[1]); recvData.ReadByteSeq(guid[5]); recvData.ReadByteSeq(guid[7]); recvData.ReadByteSeq(guid[4]); Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); if (!unit) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); return; } // set faction visible if needed if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction())) _player->GetReputationMgr().SetVisible(factionTemplateEntry); GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); // remove fake death //if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) // GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); if (unit->IsArmorer() || unit->IsCivilian() || unit->IsQuestGiver() || unit->IsServiceProvider() || unit->IsGuard()) unit->StopMoving(); // If spiritguide, no need for gossip menu, just put player into resurrect queue if (unit->IsSpiritGuide()) { Battleground* bg = _player->GetBattleground(); if (bg) { bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID()); sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID()); return; } } if (!sScriptMgr->OnGossipHello(_player, unit)) { // _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); _player->PrepareGossipMenu(unit, unit->GetCreatureTemplate()->GossipMenuId, true); _player->SendPreparedGossip(unit); } unit->AI()->sGossipHello(_player); }
void WorldSession::SendListInventory(ObjectGuid vendorguid) { DEBUG_LOG("WORLD: Sent SMSG_LIST_INVENTORY"); Creature* pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); if (!pCreature) { DEBUG_LOG("WORLD: SendListInventory - %s not found or you can't interact with him.", vendorguid.GetString().c_str()); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, ObjectGuid(), 0); return; } // remove fake death if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); // Stop the npc if moving pCreature->StopMoving(); VendorItemData const* vItems = pCreature->GetVendorItems(); VendorItemData const* tItems = pCreature->GetVendorTemplateItems(); uint8 customitems = vItems ? vItems->GetItemCount() : 0; uint8 numitems = customitems + (tItems ? tItems->GetItemCount() : 0); std::vector<bool> bitFlags; float discountMod = _player->GetReputationPriceDiscount(pCreature); uint8 count = 0; ByteBuffer buffer; for (uint8 vendorslot = 0; vendorslot < numitems; ++vendorslot) { VendorItem const* crItem = vendorslot < customitems ? vItems->GetItem(vendorslot) : tItems->GetItem(vendorslot - customitems); if (crItem) { uint32 price, displayId, buyCount, maxDurability; int32 maxCount; if (crItem->type == VENDOR_ITEM_TYPE_ITEM) { ItemPrototype const * pProto = ObjectMgr::GetItemPrototype(crItem->item); if (!pProto) continue; if (!_player->isGameMaster()) { // class wrong item skip only for bindable case if ((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP) continue; // race wrong item skip always if ((pProto->Flags2 & ITEM_FLAG2_HORDE_ONLY) && _player->GetTeam() != HORDE) continue; if ((pProto->Flags2 & ITEM_FLAG2_ALLIANCE_ONLY) && _player->GetTeam() != ALLIANCE) continue; if ((pProto->AllowableRace & _player->getRaceMask()) == 0) continue; if (crItem->conditionId && !sObjectMgr.IsPlayerMeetToCondition(crItem->conditionId, _player, pCreature->GetMap(), pCreature, CONDITION_FROM_VENDOR)) continue; } // possible item coverting for BoA case if (pProto->Flags & ITEM_FLAG_BOA) { // convert if can use and then buy if (pProto->RequiredReputationFaction && uint32(_player->GetReputationRank(pProto->RequiredReputationFaction)) >= pProto->RequiredReputationRank) { // checked at convert data loading as existed if (uint32 newItemId = sObjectMgr.GetItemConvert(crItem->item, _player->getRaceMask())) pProto = ObjectMgr::GetItemPrototype(newItemId); } } ++count; if (count >= MAX_VENDOR_ITEMS) break; // reputation discount maxDurability = pProto->MaxDurability; price = (crItem->ExtendedCost == 0 || pProto->Flags2 & ITEM_FLAG2_EXT_COST_REQUIRES_GOLD) ? uint32(floor(pProto->BuyPrice * discountMod)) : 0; displayId = pProto->DisplayInfoID; maxCount = crItem->maxcount <= 0 ? -1 : int32(pCreature->GetVendorItemCurrentCount(crItem)); buyCount = pProto->BuyCount; } else if (crItem->type == VENDOR_ITEM_TYPE_CURRENCY) { CurrencyTypesEntry const * pCurrency = sCurrencyTypesStore.LookupEntry(crItem->item); if (!pCurrency) continue; if (pCurrency->Category == CURRENCY_CATEGORY_META) continue; ++count; if (count >= MAX_VENDOR_ITEMS) break; maxDurability = 0; price = 0; displayId = 0; maxCount = -1; buyCount = crItem->maxcount; } else continue; bitFlags.push_back(crItem->ExtendedCost == 0); bitFlags.push_back(true); // unk buffer << uint32(vendorslot + 1); // client size expected counting from 1 buffer << uint32(maxDurability); if (crItem->ExtendedCost) buffer << uint32(crItem->ExtendedCost); buffer << uint32(crItem->item); buffer << uint32(crItem->type); buffer << uint32(price); buffer << uint32(displayId); buffer << int32(maxCount); buffer << uint32(buyCount); } } WorldPacket data(SMSG_VENDOR_INVENTORY, (8 + 3 + 1 + 1 + numitems * 8 * 4)); data.WriteGuidMask<1, 0>(vendorguid); data.WriteBits(count, 21); data.WriteGuidMask<3, 6, 5, 2, 7>(vendorguid); for (uint32 i = 0; i < bitFlags.size(); ++i) data.WriteBit(bitFlags[i]); data.WriteGuidMask<4>(vendorguid); data.FlushBits(); data.append(buffer); data.WriteGuidBytes<5, 4, 1, 0, 6>(vendorguid); data << uint8(count == 0); data.WriteGuidBytes<2, 3, 7>(vendorguid); SendPacket(&data); }
void WorldSession::SendListInventory(uint64 vendorGuid) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_LIST_INVENTORY"); Creature* vendor = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_VENDOR); if (!vendor) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorGuid))); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); // Stop the npc if moving if (vendor->HasUnitState(UNIT_STAT_MOVING)) vendor->StopMoving(); VendorItemData const* items = vendor->GetVendorItems(); if (!items) { WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + 1); data << uint64(vendorGuid); data << uint8(0); // count == 0, next will be error code data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } uint8 itemCount = items->GetItemCount(); uint8 count = 0; WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + itemCount * 8 * 4); data << uint64(vendorGuid); size_t countPos = data.wpos(); data << uint8(count); float discountMod = _player->GetReputationPriceDiscount(vendor); for (uint8 slot = 0; slot < itemCount; ++slot) { if (VendorItem const* item = items->GetItem(slot)) { if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item->item)) { if (!(itemTemplate->AllowableClass & _player->getClassMask()) && itemTemplate->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster()) continue; // Only display items in vendor lists for the team the // player is on. If GM on, display all items. if (!_player->isGameMaster() && ((itemTemplate->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE) || (itemTemplate->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE))) continue; uint32 leftInStock = !item->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(item); ++count; // reputation discount int32 price = item->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->BuyPrice * discountMod)) : 0; data << uint32(slot + 1); // client expects counting to start at 1 data << uint32(item->item); data << uint32(itemTemplate->DisplayInfoID); data << int32(leftInStock); data << uint32(price); data << uint32(itemTemplate->MaxDurability); data << uint32(itemTemplate->BuyCount); data << uint32(item->ExtendedCost); } } } if (count == 0) { data << uint8(0); SendPacket(&data); return; } data.put<uint8>(countPos, count); SendPacket(&data); }
void WorldSession::SendListInventory(uint64 vendorguid) { sLog.outDebug("WORLD: Sent SMSG_LIST_INVENTORY"); Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR); if (!pCreature) { sLog.outDebug("WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); return; } // remove fake death if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); // Stop the npc if moving pCreature->StopMoving(); VendorItemData const* vItems = pCreature->GetVendorItems(); if (!vItems) { WorldPacket data(SMSG_LIST_INVENTORY, (8+1+1)); data << uint64(vendorguid); data << uint8(0); // count==0, next will be error code data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } uint8 numitems = vItems->GetItemCount(); uint8 count = 0; WorldPacket data(SMSG_LIST_INVENTORY, (8+1+numitems*8*4)); data << uint64(vendorguid); size_t count_pos = data.wpos(); data << uint8(count); float discountMod = _player->GetReputationPriceDiscount(pCreature); for (uint8 vendorslot = 0; vendorslot < numitems; ++vendorslot ) { if (VendorItem const* crItem = vItems->GetItem(vendorslot)) { if (ItemPrototype const *pProto = sObjectMgr.GetItemPrototype(crItem->item)) { if ((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster()) continue; // Only display items in vendor lists for the team the // player is on. If GM on, display all items. if (!_player->isGameMaster() && ((pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE) || (pProto->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE))) continue; ++count; // reputation discount int32 price = crItem->IsGoldRequired(pProto) ? uint32(floor(pProto->BuyPrice * discountMod)) : 0; data << uint32(vendorslot+1); // client expects counting to start at 1 data << uint32(1); // unknow value 4.0.1, always 1 data << uint32(crItem->item); data << uint32(pProto->DisplayInfoID); data << int32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem)); data << uint32(price); data << uint32(pProto->MaxDurability); data << uint32(pProto->BuyCount); data << uint32(crItem->ExtendedCost); data << uint8(0); // unk 4.0.1 } } } //TODO: add error messages. /*switch ( v13 ) { case 2: ConsoleWrite(v7, a2, (int)"You are too far away", 0); break; case 1: ConsoleWrite(v7, a2, (int)"I don't think he likes you very much", 0); break; case 0: ConsoleWrite(v7, a2, (int)"Vendor has no inventory", 0); break; case 3: ConsoleWrite(v7, a2, (int)"Vendor is dead", 0); break; case 4: ConsoleWrite(v7, a2, (int)"You can't shop while dead.", 0); break; default: break; }*/ if (count == 0) { data << uint8(0); SendPacket(&data); return; } data.put<uint8>(count_pos, count); SendPacket(&data); }
void WorldSession::SendListInventory(ObjectGuid vendorguid) { DEBUG_LOG("WORLD: Sent SMSG_LIST_INVENTORY"); Creature* pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); if (!pCreature) { DEBUG_LOG("WORLD: SendListInventory - %s not found or you can't interact with him.", vendorguid.GetString().c_str()); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, ObjectGuid(), 0); return; } // remove fake death if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) { GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); } // Stop the npc if moving pCreature->StopMoving(); VendorItemData const* vItems = pCreature->GetVendorItems(); VendorItemData const* tItems = pCreature->GetVendorTemplateItems(); if (!vItems && !tItems) { WorldPacket data(SMSG_LIST_INVENTORY, (8 + 1 + 1)); data << ObjectGuid(vendorguid); data << uint8(0); // count==0, next will be error code data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } uint8 customitems = vItems ? vItems->GetItemCount() : 0; uint8 numitems = customitems + (tItems ? tItems->GetItemCount() : 0); uint8 count = 0; WorldPacket data(SMSG_LIST_INVENTORY, (8 + 1 + numitems * 7 * 4)); data << ObjectGuid(vendorguid); size_t count_pos = data.wpos(); data << uint8(count); float discountMod = _player->GetReputationPriceDiscount(pCreature); for (int i = 0; i < numitems; ++i) { VendorItem const* crItem = i < customitems ? vItems->GetItem(i) : tItems->GetItem(i - customitems); if (crItem) { uint32 itemId = crItem->item; ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemId); if (pProto) { if (!_player->isGameMaster()) { // class wrong item skip only for bindable case if ((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP) { continue; } // race wrong item skip always if ((pProto->AllowableRace & _player->getRaceMask()) == 0) { continue; } // when no faction required but rank > 0 will be used faction id from the vendor faction template to compare the rank if (!pProto->RequiredReputationFaction && pProto->RequiredReputationRank > 0 && ReputationRank(pProto->RequiredReputationRank) > _player->GetReputationRank(pCreature->getFactionTemplateEntry()->faction)) { continue; } if (crItem->conditionId && !sObjectMgr.IsPlayerMeetToCondition(crItem->conditionId, _player, pCreature->GetMap(), pCreature, CONDITION_FROM_VENDOR)) { continue; } } ++count; uint32 price = 0; // check if the item to sell is a mount switch (itemId) { case 1132: // all regular mounts case 2411: case 2414: case 5655: case 5656: case 5665: case 5668: case 5864: case 5872: case 5873: case 8563: case 8588: case 8591: case 8592: case 8595: case 8629: case 8631: case 8632: case 12325: case 12326: case 12327: case 13321: case 13322: case 13331: case 13332: case 13333: case 15277: case 15290: case 18241: case 18242: case 18243: case 18244: case 18245: case 18246: case 18247: case 18248: // apply discount for regular mount and set price price = uint32(floor(AccountTypes(sWorld.getConfig(CONFIG_UINT32_MOUNT_COST)) * discountMod)); break; case 12302: // all epic mounts case 12303: case 12330: case 12351: case 12353: case 12354: case 13086: case 13326: case 13327: case 13328: case 13329: case 13334: case 13335: case 18766: case 18767: case 18768: case 18772: case 18773: case 18774: case 18776: case 18777: case 18778: case 18785: case 18786: case 18787: case 18788: case 18789: case 18790: case 18791: case 18793: case 18794: case 18795: case 18796: case 18797: case 18798: case 18902: // apply discount for epic mount and set price price = uint32(floor(AccountTypes(sWorld.getConfig(CONFIG_UINT32_EPIC_MOUNT_COST)) * discountMod)); break; default: // any other items price = uint32(floor(pProto->BuyPrice * discountMod)); break; } data << uint32(count); data << uint32(itemId); data << uint32(pProto->DisplayInfoID); data << uint32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem)); data << uint32(price); data << uint32(pProto->MaxDurability); data << uint32(pProto->BuyCount); } } } if (count == 0) { data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } data.put<uint8>(count_pos, count); SendPacket(&data); }
bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) { WorldSession* session = player->GetSession(); player->PlayerTalkClass->ClearMenus(); switch(sender) { case SENDER_SELECT_VENDOR: // action = slot { Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action); if (!item) { if (const char* slotname = getSlotName(action)) session->SendNotification("No item equipped in %s slot", slotname); OnGossipHello(player, creature); return true; } const ItemTemplate * itemTemplate = item->GetTemplate(); optionData* oM = &optionMap[(itemTemplate->Class == ITEM_CLASS_WEAPON ? MAX_ITEM_SUBCLASS_WEAPON : 0)+itemTemplate->SubClass][getCorrectInvType(itemTemplate->InventoryType)]; if (!oM->size()) { if (const char* slotname = getSlotName(action)) session->SendNotification("No transmogrifications available for %s", slotname); OnGossipHello(player, creature); return true; } player->ADD_GOSSIP_ITEM(GOSSIP_ICON_INTERACT_1, (std::string)"Update selected; "+getItemName(itemTemplate, session), sender, action); for(optionData::iterator it = oM->begin(); it != oM->end(); ++it) { if (!TransmogDisplayVendorMgr::AllowedQuality(it->first)) // skip not allowed qualities continue; for(uint32 count = 0; count*MAX_VENDOR_ITEMS < it->second.size(); ++count) { std::ostringstream ss; ss << getQualityName(it->first); if (count) ss << " [" << count << "]"; player->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, ss.str().c_str(), it->first, count*MAX_VENDOR_ITEMS); } } if (player->PlayerTalkClass->GetGossipMenu().GetMenuItemCount() <= 1) { if (const char* slotname = getSlotName(action)) session->SendNotification("No transmogrifications available for %s", slotname); player->PlayerTalkClass->ClearMenus(); OnGossipHello(player, creature); return true; } selDataStruct temp = {action, 0, 0}; // slot, offset, quality selData[player->GetGUIDLow()] = temp; player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TALK, "Back..", SENDER_BACK, 0); player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID()); } break; case SENDER_BACK: // Back { OnGossipHello(player, creature); } break; case SENDER_REMOVE_ALL: // Remove TransmogDisplayVendorMgrs { bool removed = false; for (uint8 Slot = EQUIPMENT_SLOT_START; Slot < EQUIPMENT_SLOT_END; Slot++) { if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, Slot)) { if (TransmogDisplayVendorMgr::DeleteFakeEntry(newItem) && !removed) removed = true; } } if (removed) { session->SendAreaTriggerMessage("Transmogrifications removed from equipped items"); player->PlayDirectSound(3337); } else session->SendNotification("You have no transmogrified items equipped"); OnGossipSelect(player, creature, SENDER_REMOVE_MENU, 0); } break; case SENDER_REMOVE_ONE: // Remove TransmogDisplayVendorMgr from single item { const char* slotname = getSlotName(action); if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action)) { if (TransmogDisplayVendorMgr::DeleteFakeEntry(newItem)) { if (slotname) session->SendAreaTriggerMessage("%s transmogrification removed", slotname); player->PlayDirectSound(3337); } else if (slotname) session->SendNotification("No transmogrification on %s slot", slotname); } else if (slotname) session->SendNotification("No item equipped in %s slot", slotname); OnGossipSelect(player, creature, SENDER_REMOVE_MENU, 0); } break; case SENDER_REMOVE_MENU: { for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++) { const char* slotname = getSlotName(slot); if (!slotname) continue; std::ostringstream ss; ss << "Remove transmogrification from " << slotname << "?"; player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_INTERACT_1, (std::string)"Remove from "+slotname, SENDER_REMOVE_ONE, slot, ss.str().c_str(), 0, false); } player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_INTERACT_1, "Remove all transmogrifications", SENDER_REMOVE_ALL, 0, "Are you sure you want to remove all transmogrifications?", 0, false); player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TALK, "Back..", SENDER_BACK, 0); player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID()); } break; default: // Show items you can use { if (sender >= MAX_ITEM_QUALITY) // sender = quality, action = iterator return false; // cheat if (selData.find(player->GetGUIDLow()) == selData.end()) return false; // cheat if (selData[player->GetGUIDLow()].offset != 0 || selData[player->GetGUIDLow()].quality != 0) return false; // cheat (something is off) selData[player->GetGUIDLow()].offset = action; selData[player->GetGUIDLow()].quality = sender; uint32 slot = selData[player->GetGUIDLow()].slot; // slot if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) { if (!TransmogDisplayVendorMgr::AllowedQuality(item->GetTemplate()->Quality)) { session->SendNotification("Equipped item has wrong quality"); OnGossipSelect(player, creature, SENDER_SELECT_VENDOR, slot); return true; } optionDataList oM = optionMap[(item->GetTemplate()->Class == ITEM_CLASS_WEAPON ? MAX_ITEM_SUBCLASS_WEAPON : 0)+item->GetTemplate()->SubClass][getCorrectInvType(item->GetTemplate()->InventoryType)][sender]; uint32 itemCount = (oM.size()-action); if (itemCount > MAX_VENDOR_ITEMS) itemCount = MAX_VENDOR_ITEMS; if (!itemCount) { session->SendAreaTriggerMessage("No items found"); OnGossipSelect(player, creature, SENDER_SELECT_VENDOR, slot); return true; } player->CLOSE_GOSSIP_MENU(); TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_LIST_INVENTORY"); Creature* vendor = player->GetNPCIfCanInteractWith(creature->GetGUID(), UNIT_NPC_FLAG_VENDOR); if (!vendor) { TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", creature->GetGUIDLow()); player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); return true; } if (player->HasUnitState(UNIT_STATE_DIED)) player->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); if (vendor->HasUnitState(UNIT_STATE_MOVING)) vendor->StopMoving(); uint8 count = 0; WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + itemCount * 8 * 4); data << uint64(creature->GetGUID()); size_t countPos = data.wpos(); data << uint8(count); bool added = false; optionDataList::iterator it = oM.begin(); std::advance(it, action); for (; it != oM.end() && count < itemCount; ++it, ++count) { if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(*it)) { data << uint32(count + 1); data << uint32(itemTemplate->ItemId); data << uint32(itemTemplate->DisplayInfoID); data << int32(0xFFFFFFFF); data << uint32(0); data << uint32(itemTemplate->MaxDurability); data << uint32(itemTemplate->BuyCount); data << uint32(0); added = true; } } if (!added) { data << uint8(0); session->SendPacket(&data); } else { data.put<uint8>(countPos, count); session->SendPacket(&data); } } else { session->SendNotification("No item equipped"); OnGossipSelect(player, creature, SENDER_SELECT_VENDOR, slot); return true; } } break; } return true; }
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if(!&creature) return true; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED)) return true; // prevent crash at empty waypoint path. if(i_path.Empty()) { return true; } CreatureTraveller traveller(creature); /* if( npcIsStopped[creature.GetGUID()] ) { i_nextMoveTime.Update(40000); i_destinationHolder.UpdateTraveller(traveller, ((diff)-40000), false); npcIsStopped[creature.GetGUID()] = false; return true; } */ i_nextMoveTime.Update(diff); i_destinationHolder.UpdateTraveller(traveller, diff, false); if( creature.IsStopped() ) { uint32 wpB = i_currentNode > 0 ? i_currentNode-1 : i_wpBehaviour.size()-1; if( i_wpBehaviour[wpB] != NULL ) { struct WaypointBehavior *tmpBehavior = i_wpBehaviour[wpB]; if (!tmpBehavior->HasDone) { if(tmpBehavior->emote != 0) { creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,tmpBehavior->emote); } if(tmpBehavior->aiscript != "") { WPAIScript(creature, tmpBehavior->aiscript); } //sLog.outDebug("DEBUG: tmpBehavior->text[0] TEST"); if(tmpBehavior->text[0] != "") { //sLog.outDebug("DEBUG: tmpBehavior->text[0] != \"\""); // Only one text is set if( tmpBehavior->text[1] == "" ) { //sLog.outDebug("DEBUG: tmpBehavior->text[1] == NULL"); creature.Say(tmpBehavior->text[0].c_str(), 0, 0); } else { // Select one from max 5 texts for( int i = 0; i < 4; ++i ) { if( tmpBehavior->text[i] == "" ) { //sLog.outDebug("DEBUG: tmpBehavior->text[i] == \"\": %d", i); //sLog.outDebug("DEBUG: rand() % (i): %d", rand() % (i)); creature.Say(tmpBehavior->text[rand() % i].c_str(), 0, 0); break; } } } } if(tmpBehavior->spell != 0) { //sLog.outDebug("DEBUG: wpSys - spell"); creature.CastSpell(&creature,tmpBehavior->spell, false); } if (tmpBehavior->orientation !=100) { //sLog.outDebug("DEBUG: wpSys - orientation"); creature.SetOrientation(tmpBehavior->orientation); } if(tmpBehavior->model1 != 0) { //sLog.outDebug("DEBUG: wpSys - model1"); creature.SetUInt32Value(UNIT_FIELD_DISPLAYID, tmpBehavior->model1); } tmpBehavior->HasDone = true; } // HasDone == false } // wpBehaviour found } // i_creature.IsStopped() if( i_nextMoveTime.Passed() ) { if( creature.IsStopped() ) { assert( i_currentNode < i_path.Size() ); creature.addUnitState(UNIT_STAT_ROAMING); const Path::PathNode &node(i_path(i_currentNode)); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); uint32 wpB = i_currentNode > 0 ? i_currentNode-1 : i_wpBehaviour.size()-1; if( i_wpBehaviour[wpB] != NULL ) { struct WaypointBehavior *tmpBehavior = i_wpBehaviour[wpB]; tmpBehavior->HasDone = false; if(tmpBehavior->model2 != 0) { creature.SetUInt32Value(UNIT_FIELD_DISPLAYID, tmpBehavior->model2); } if (tmpBehavior->orientation !=100) { creature.SetOrientation(tmpBehavior->orientation); } creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); } } else { creature.StopMoving(); i_nextMoveTime.Reset(i_delays[i_currentNode]); ++i_currentNode; if( i_currentNode >= i_path.Size() ) i_currentNode = 0; } } return true; }
bool TargetedMovementGenerator::Update(Creature &owner, const uint32 & time_diff) { if( !&owner || !owner.isAlive() || !&i_target ) return true; if( owner.hasUnitState(UNIT_STAT_ROOT) || owner.hasUnitState(UNIT_STAT_STUNDED) || owner.hasUnitState(UNIT_STAT_FLEEING)) return true; if( !owner.isInCombat() && !owner.hasUnitState(UNIT_STAT_FOLLOW) ) { //owner.AIM_Initialize(); This case must be the one, when a creature aggroed you. By Initalized a new AI, we prevented to Ai::_stopAttack() to be executed properly. return true; } // prevent crash after creature killed pet if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != &i_target) return true; Traveller<Creature> traveller(owner); if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false)) { // put targeted movement generators on a higher priority if (owner.GetObjectSize()) i_destinationHolder.ResetUpdate(50); float dist = i_target.GetObjectSize() + owner.GetObjectSize() + OBJECT_CONTACT_DISTANCE; // try to counter precision differences if( i_destinationHolder.GetDistanceFromDestSq(i_target) > dist * dist + 0.1) _setTargetLocation(owner, 0); else if ( !owner.HasInArc( 0.1f, &i_target ) ) { owner.SetInFront(&i_target); if( i_target.GetTypeId() == TYPEID_PLAYER ) owner.SendUpdateToPlayer( (Player*)&i_target ); } if( !owner.IsStopped() && i_destinationHolder.HasArrived()) { owner.StopMoving(); if(owner.canReachWithAttack(&i_target) && !owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.Attack(&i_target); } } /* //SpellEntry* spellInfo; if( reach ) { if( owner.GetDistance2dSq( &i_target ) > 0.0f ) { DEBUG_LOG("MOVEMENT : Distance = %f",owner.GetDistance2dSq( &i_target )); owner.addUnitState(UNIT_STAT_CHASE); _setTargetLocation(owner, 0); } else if ( !owner.HasInArc( 0.0f, &i_target ) ) { DEBUG_LOG("MOVEMENT : Orientation = %f",owner.GetAngle(&i_target)); owner.SetInFront(&i_target); if( i_target.GetTypeId() == TYPEID_PLAYER ) owner.SendUpdateToPlayer( (Player*)&i_target ); } if( !owner.isInCombat() ) { owner.AIM_Initialize(); return; } } else if( i_target.isAlive() ) { if( !owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.isInCombat() ) { if( spellInfo = owner.reachWithSpellAttack( &i_target ) ) { _spellAtack(owner, spellInfo); return; } } if( owner.GetDistance2dSq( &i_target ) > 0.0f ) { DEBUG_LOG("MOVEMENT : Distance = %f",owner.GetDistance2dSq( &i_target )); owner.addUnitState(UNIT_STAT_CHASE); _setTargetLocation(owner, 0); } } else if( !i_targetedHome ) { if( !owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.isInCombat() && (spellInfo = owner.reachWithSpellAttack(&i_target)) ) { _spellAtack(owner, spellInfo); return; } _setTargetLocation(owner, 0); if(reach) { if( reach && owner.canReachWithAttack(&i_target) ) { owner.StopMoving(); if(!owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.Attack(&i_target); owner.clearUnitState(UNIT_STAT_CHASE); DEBUG_LOG("UNIT IS THERE"); } else { _setTargetLocation(owner, 0); DEBUG_LOG("Continue to chase"); } } }*/ return true; }
void WorldSession::SendListInventory(uint64 vendorguid) { DEBUG_LOG("WORLD: Sent SMSG_LIST_INVENTORY"); Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); if (!pCreature) { DEBUG_LOG("WORLD: SendListInventory - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid))); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); return; } // remove fake death if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); // Stop the npc if moving if (!pCreature->IsStopped()) pCreature->StopMoving(); VendorItemData const* vItems = pCreature->GetVendorItems(); if (!vItems) { WorldPacket data( SMSG_LIST_INVENTORY, (8+1+1) ); data << uint64(vendorguid); data << uint8(0); // count==0, next will be error code data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } uint8 numitems = vItems->GetItemCount(); uint8 count = 0; WorldPacket data( SMSG_LIST_INVENTORY, (8+1+numitems*8*4) ); data << uint64(vendorguid); size_t count_pos = data.wpos(); data << uint8(count); // placeholder, client limit 150 items (as of 3.3.3) float discountMod = _player->GetReputationPriceDiscount(pCreature); for(uint8 vendorslot = 0; vendorslot < numitems; ++vendorslot ) { if (VendorItem const* crItem = vItems->GetItem(vendorslot)) { if (ItemPrototype const *pProto = ObjectMgr::GetItemPrototype(crItem->item)) { if (!_player->isGameMaster()) { // class wrong item skip only for bindable case if ((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP) continue; // race wrong item skip always if ((pProto->Flags2 & ITEM_FLAGS2_HORDE_ONLY) && _player->GetTeam() != HORDE) continue; if ((pProto->Flags2 & ITEM_FLAGS2_ALLIANCE_ONLY) && _player->GetTeam() != ALLIANCE) continue; if ((pProto->AllowableRace & _player->getRaceMask()) == 0) continue; } ++count; // reputation discount uint32 price = (crItem->ExtendedCost == 0 || pProto->Flags2 & ITEM_FLAGS2_EXT_COST_REQUIRES_GOLD) ? uint32(floor(pProto->BuyPrice * discountMod)) : 0; data << uint32(vendorslot +1); // client size expected counting from 1 data << uint32(crItem->item); data << uint32(pProto->DisplayInfoID); data << uint32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem)); data << uint32(price); data << uint32(pProto->MaxDurability); data << uint32(pProto->BuyCount); data << uint32(crItem->ExtendedCost); } } } if (count == 0) { data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } data.put<uint8>(count_pos, count); SendPacket(&data); }
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if (!&creature) return true; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if (creature.hasUnitState(UNIT_STAT_NOT_MOVE)) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } // prevent a crash at empty waypoint path. if (!i_path || i_path->empty()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } if (i_currentNode >= i_path->size()) i_currentNode = 0; CreatureTraveller traveller(creature); i_nextMoveTime.Update(diff); if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true)) { if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost } // creature has been stopped in middle of the waypoint segment if (!i_destinationHolder.HasArrived() && creature.IsStopped()) { // Timer has elapsed, meaning this part controlled it if (i_nextMoveTime.Passed()) { SetStoppedByPlayer(false); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); // Now we re-set destination to same node and start travel MoveToNextNode(traveller); } else // if( !i_nextMoveTime.Passed()) { // unexpected end of timer && creature stopped && not at end of segment if (!IsStoppedByPlayer()) { // Put 30 seconds delay i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); SetStoppedByPlayer(true); // Mark we did it } } return true; // Abort here this update } if (creature.IsStopped()) { if (!m_isArrivalDone) { if (i_path->at(i_currentNode).orientation != 100) creature.SetOrientation(i_path->at(i_currentNode).orientation); if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior) { if (behavior->emote != 0) creature.HandleEmoteCommand(behavior->emote); if (behavior->spell != 0) { creature.CastSpell(&creature, behavior->spell, false); if (!IsActive(creature)) // force stop processing (cast can change movegens list) return true; // not expire now, but already lost } if (behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if (behavior->textid[0]) { // Not only one text is set if (behavior->textid[1]) { // Select one from max 5 texts (0 and 1 already checked) int i = 2; for(; i < MAX_WAYPOINT_TEXT; ++i) { if (!behavior->textid[i]) break; } creature.Say(behavior->textid[rand() % i], 0, 0); } else creature.Say(behavior->textid[0], 0, 0); } } // wpBehaviour found // Can only do this once for the node m_isArrivalDone = true; MovementInform(creature); if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost // prevent a crash at empty waypoint path. if (!i_path || i_path->empty() || i_currentNode >= i_path->size()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } } } // i_creature.IsStopped() // This is at the end of waypoint segment or has been stopped by player if (i_nextMoveTime.Passed()) { // If stopped then begin a new move segment if (creature.IsStopped()) { creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); // Proceed with increment current node and then send to the next destination ++i_currentNode; // Oops, end of the line so need to start from the beginning if (i_currentNode >= i_path->size()) i_currentNode = 0; MoveToNextNode(traveller); if (i_path->at(i_currentNode).orientation != 100) creature.SetOrientation(i_path->at(i_currentNode).orientation); if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior) { if (behavior->model2 != 0) creature.SetDisplayId(behavior->model2); creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); } // behavior for "departure" of the current node is done m_isArrivalDone = false; } else { // If not stopped then stop it and set the reset of TimeTracker to waittime creature.StopMoving(); SetStoppedByPlayer(false); i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); ++i_currentNode; if (i_currentNode >= i_path->size()) i_currentNode = 0; } } return true; }
void WorldSession::SendListInventory(ObjectGuid vendorGuid) { Creature* vendor = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_VENDOR); if (!vendor) { TC_LOG_DEBUG("network", "WORLD: SendListInventory - %s not found or you can not interact with him.", vendorGuid.ToString().c_str()); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, ObjectGuid::Empty); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); // Stop the npc if moving if (vendor->HasUnitState(UNIT_STATE_MOVING)) vendor->StopMoving(); VendorItemData const* vendorItems = vendor->GetVendorItems(); uint32 rawItemCount = vendorItems ? vendorItems->GetItemCount() : 0; WorldPackets::NPC::VendorInventory packet; packet.Vendor = vendor->GetGUID(); packet.Items.resize(rawItemCount); const float discountMod = _player->GetReputationPriceDiscount(vendor); uint8 count = 0; for (uint32 slot = 0; slot < rawItemCount; ++slot) { VendorItem const* vendorItem = vendorItems->GetItem(slot); if (!vendorItem) continue; WorldPackets::NPC::VendorItem& item = packet.Items[count]; if (vendorItem->Type == ITEM_VENDOR_TYPE_ITEM) { ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(vendorItem->item); if (!itemTemplate) continue; int32 leftInStock = !vendorItem->maxcount ? -1 : vendor->GetVendorItemCurrentCount(vendorItem); if (!_player->IsGameMaster()) // ignore conditions if GM on { // Respect allowed class if (!(itemTemplate->GetAllowableClass() & _player->getClassMask()) && itemTemplate->GetBonding() == BIND_ON_ACQUIRE) continue; // Only display items in vendor lists for the team the player is on if ((itemTemplate->GetFlags2() & ITEM_FLAG2_FACTION_HORDE && _player->GetTeam() == ALLIANCE) || (itemTemplate->GetFlags2() & ITEM_FLAG2_FACTION_ALLIANCE && _player->GetTeam() == HORDE)) continue; // Items sold out are not displayed in list if (leftInStock == 0) continue; } if (!sConditionMgr->IsObjectMeetingVendorItemConditions(vendor->GetEntry(), vendorItem->item, _player, vendor)) { TC_LOG_DEBUG("condition", "SendListInventory: conditions not met for creature entry %u item %u", vendor->GetEntry(), vendorItem->item); continue; } int32 price = vendorItem->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->GetBuyPrice() * discountMod)) : 0; if (int32 priceMod = _player->GetTotalAuraModifier(SPELL_AURA_MOD_VENDOR_ITEMS_PRICES)) price -= CalculatePct(price, priceMod); item.MuID = slot + 1; // client expects counting to start at 1 item.Durability = itemTemplate->MaxDurability; item.ExtendedCostID = vendorItem->ExtendedCost; item.Type = vendorItem->Type; item.Quantity = leftInStock; item.StackCount = itemTemplate->GetBuyCount(); item.Price = price; item.Item.ItemID = vendorItem->item; } else if (vendorItem->Type == ITEM_VENDOR_TYPE_CURRENCY) { CurrencyTypesEntry const* currencyTemplate = sCurrencyTypesStore.LookupEntry(vendorItem->item); if (!currencyTemplate) continue; if (!vendorItem->ExtendedCost) continue; // there's no price defined for currencies, only extendedcost is used item.MuID = slot + 1; // client expects counting to start at 1 item.ExtendedCostID = vendorItem->ExtendedCost; item.Item.ItemID = vendorItem->item; item.Type = vendorItem->Type; item.StackCount = vendorItem->maxcount; } else continue; if (++count >= MAX_VENDOR_ITEMS) break; } // Resize vector to real size (some items can be skipped due to checks) packet.Items.resize(count); SendPacket(packet.Write()); }
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if (!&creature) return true; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if (creature.hasUnitState(UNIT_STAT_NOT_MOVE)) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } // prevent a crash at empty waypoint path. if (!i_path || i_path->empty()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } // i_path was modified by chat commands for example if (i_path->size() != i_hasDone.size()) i_hasDone.resize(i_path->size()); if (i_currentNode >= i_path->size()) i_currentNode = 0; CreatureTraveller traveller(creature); i_nextMoveTime.Update(diff); if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true)) { if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost } // creature has been stopped in middle of the waypoint segment if (!i_destinationHolder.HasArrived() && creature.IsStopped()) { // Timer has elapsed, meaning this part controlled it if (i_nextMoveTime.Passed()) { SetStoppedByPlayer(false); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); // Now we re-set destination to same node and start travel const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); } else // if ( !i_nextMoveTime.Passed()) { // unexpected end of timer && creature stopped && not at end of segment if (!IsStoppedByPlayer()) { // Put 30 seconds delay i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); SetStoppedByPlayer(true); // Mark we did it } } return true; // Abort here this update } if (creature.IsStopped()) { uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (!i_hasDone[idx]) { if (i_path->at(idx).orientation != 100) creature.SetOrientation(i_path->at(idx).orientation); if (i_path->at(idx).script_id) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for creature %u (entry %u).", i_path->at(idx).script_id, idx, creature.GetDBTableGUIDLow(), creature.GetEntry()); creature.GetMap()->ScriptsStart(sCreatureMovementScripts, i_path->at(idx).script_id, &creature, &creature); } if (WaypointBehavior *behavior = i_path->at(idx).behavior) { if (behavior->emote != 0) creature.HandleEmote(behavior->emote); if (behavior->spell != 0) { creature.CastSpell(&creature, behavior->spell, false); if (!IsActive(creature)) // force stop processing (cast can change movegens list) return true; // not expire now, but already lost } if (behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if (behavior->textid[0]) { // Not only one text is set if (behavior->textid[1]) { // Select one from max 5 texts (0 and 1 already checked) int i = 2; for (; i < MAX_WAYPOINT_TEXT; ++i) { if (!behavior->textid[i]) break; } creature.Say(behavior->textid[rand() % i], 0, 0); } else creature.Say(behavior->textid[0], 0, 0); } } // wpBehaviour found i_hasDone[idx] = true; MovementInform(creature); if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost // prevent a crash at empty waypoint path. if (!i_path || i_path->empty() || i_currentNode >= i_path->size()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } } // HasDone == false } // i_creature.IsStopped() // This is at the end of waypoint segment or has been stopped by player if (i_nextMoveTime.Passed()) { // If stopped then begin a new move segment if (creature.IsStopped()) { creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (i_path->at(idx).orientation != 100) creature.SetOrientation(i_path->at(idx).orientation); if (WaypointBehavior *behavior = i_path->at(idx).behavior) { i_hasDone[idx] = false; if (behavior->model2 != 0) creature.SetDisplayId(behavior->model2); creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); } } else { // If not stopped then stop it and set the reset of TimeTracker to waittime creature.StopMoving(); SetStoppedByPlayer(false); i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); ++i_currentNode; if (i_currentNode >= i_path->size()) i_currentNode = 0; } } return true; }
void WorldSession::SendListInventory(ObjectGuid vendorguid) { DEBUG_LOG("WORLD: Sent SMSG_LIST_INVENTORY"); Creature* pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); if (!pCreature) { DEBUG_LOG("WORLD: SendListInventory - %s not found or you can't interact with him.", vendorguid.GetString().c_str()); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, ObjectGuid(), 0); return; } // remove fake death if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); // Stop the npc if moving pCreature->StopMoving(); VendorItemData const* vItems = pCreature->GetVendorItems(); VendorItemData const* tItems = pCreature->GetVendorTemplateItems(); if (!vItems && !tItems) { WorldPacket data(SMSG_LIST_INVENTORY, (8 + 1 + 1)); data << ObjectGuid(vendorguid); data << uint8(0); // count==0, next will be error code data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } uint8 customitems = vItems ? vItems->GetItemCount() : 0; uint8 numitems = customitems + (tItems ? tItems->GetItemCount() : 0); uint8 count = 0; WorldPacket data(SMSG_LIST_INVENTORY, (8 + 1 + numitems * 7 * 4)); data << ObjectGuid(vendorguid); size_t count_pos = data.wpos(); data << uint8(count); float discountMod = _player->GetReputationPriceDiscount(pCreature); for (int i = 0; i < numitems; ++i) { VendorItem const* crItem = i < customitems ? vItems->GetItem(i) : tItems->GetItem(i - customitems); if (crItem) { uint32 itemId = crItem->item; ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(itemId); if (pProto) { if (!_player->isGameMaster()) { // class wrong item skip only for bindable case if ((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP) continue; // race wrong item skip always if ((pProto->AllowableRace & _player->getRaceMask()) == 0) continue; // when no faction required but rank > 0 will be used faction id from the vendor faction template to compare the rank if (!pProto->RequiredReputationFaction && pProto->RequiredReputationRank > 0 && ReputationRank(pProto->RequiredReputationRank) > _player->GetReputationRank(pCreature->getFactionTemplateEntry()->faction)) continue; if (crItem->conditionId && !sObjectMgr.IsPlayerMeetToCondition(crItem->conditionId, _player, pCreature->GetMap(), pCreature, CONDITION_FROM_VENDOR)) continue; } ++count; // reputation discount uint32 price = uint32(floor(pProto->BuyPrice * discountMod)); data << uint32(count); data << uint32(itemId); data << uint32(pProto->DisplayInfoID); data << uint32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem)); data << uint32(price); data << uint32(pProto->MaxDurability); data << uint32(pProto->BuyCount); } } } if (count == 0) { data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } data.put<uint8>(count_pos, count); SendPacket(&data); }
void WorldSession::SendListInventory(ObjectGuid vendorguid) { DEBUG_LOG("WORLD: Sent SMSG_LIST_INVENTORY"); Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR); if (!pCreature) { DEBUG_LOG("WORLD: SendListInventory - %s not found or you can't interact with him.", vendorguid.GetString().c_str()); _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); return; } // remove fake death if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); // Stop the npc if moving pCreature->StopMoving(); VendorItemData const* vItems = pCreature->GetVendorItems(); if(!vItems) { WorldPacket data( SMSG_LIST_INVENTORY, (8+1+1) ); data << ObjectGuid(vendorguid); data << uint8(0); // count==0, next will be error code data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } uint8 numitems = vItems->GetItemCount(); uint8 count = 0; WorldPacket data( SMSG_LIST_INVENTORY, (8+1+numitems*8*4) ); data << ObjectGuid(vendorguid); size_t count_pos = data.wpos(); data << uint8(count); float discountMod = _player->GetReputationPriceDiscount(pCreature); for(int i = 0; i < numitems; ++i ) { if (VendorItem const* crItem = vItems->GetItem(i)) { if (ItemPrototype const *pProto = ObjectMgr::GetItemPrototype(crItem->item)) { if (!_player->isGameMaster()) { // class wrong item skip only for bindable case if ((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP) continue; // race wrong item skip always if ((pProto->AllowableRace & _player->getRaceMask()) == 0) continue; } ++count; // reputation discount uint32 price = uint32(floor(pProto->BuyPrice * discountMod)); data << uint32(count); data << uint32(crItem->item); data << uint32(pProto->DisplayInfoID); data << uint32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem)); data << uint32(price); data << uint32(pProto->MaxDurability); data << uint32(pProto->BuyCount); data << uint32(crItem->ExtendedCost); } } } if (count == 0) { data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } data.put<uint8>(count_pos, count); SendPacket(&data); }