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;
}
Example #2
0
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);
}
Example #4
0
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);
}
Example #5
0
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);
}
Example #6
0
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);
}
Example #7
0
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);
}
Example #9
0
    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;
}
Example #12
0
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;
}
Example #14
0
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;
}
Example #16
0
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);
}
Example #17
0
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);
}