bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if (creature.HasUnitState(UNIT_STATE_NOT_MOVE)) { creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE); return true; } // prevent a crash at empty waypoint path. if (!i_path || i_path->empty()) return false; if (Stopped()) { if (CanMove(diff)) return StartMove(creature); } else { if (creature.IsStopped()) Stop(STOP_TIME_FOR_PLAYER); else if (creature.movespline->Finalized()) { OnArrived(creature); return StartMove(creature); } } return true; }
void HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner) { if (!&owner) return; if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) return; float x, y, z; owner.GetHomePosition(x, y, z, ori); CreatureTraveller traveller(owner); uint32 travel_time = i_destinationHolder.SetDestination(traveller, x, y, z); modifyTravelTime(travel_time); owner.ClearUnitState(uint32(UNIT_STAT_ALL_STATE & ~UNIT_STAT_EVADE)); }
bool RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 diff) { if (creature.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) { i_nextMoveTime.Reset(0); // Expire the timer creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE); return true; } if (creature.movespline->Finalized()) { i_nextMoveTime.Update(diff); if (i_nextMoveTime.Passed()) _setRandomLocation(creature); } return true; }
void HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner) { if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) return; Movement::MoveSplineInit init(owner); float x, y, z, o; // at apply we can select more nice return points base at current movegen //if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner, x, y, z)) //{ owner.GetHomePosition(x, y, z, o); init.SetFacing(o); //} init.MoveTo(x, y, z, true); init.SetWalk(false); init.Launch(); arrived = false; owner.ClearUnitState(UNIT_STATE_ALL_STATE & ~UNIT_STATE_EVADE); }
void CheckChannelers() { if (addYell) { if (!SelectTargetFromPlayerList(100.0f)) EnterEvadeMode(); return; } SummonChannelers(); for (uint8 i = 0; i < 5; ++i) { Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]); if (channeler && !channeler->HasUnitState(UNIT_STATE_CASTING) && !channeler->IsInCombat()) { Creature* target = ObjectAccessor::GetCreature(*me, channelers[(i+2)%5]); if (target) channeler->CastSpell(target, SPELL_CHANNELING, false); } } }
bool RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 diff) { if (creature.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) { i_nextMoveTime.Update(i_nextMoveTime.GetExpiry()); // Expire the timer creature.ClearUnitState(UNIT_STAT_ROAMING); return true; } i_nextMoveTime.Update(diff); if (i_destinationHolder.HasArrived() && !creature.IsStopped() && !creature.canFly()) creature.ClearUnitState(UNIT_STAT_ROAMING | UNIT_STAT_MOVE); if (!i_destinationHolder.HasArrived() && creature.IsStopped()) creature.AddUnitState(UNIT_STAT_ROAMING); CreatureTraveller traveller(creature); if (i_destinationHolder.UpdateTraveller(traveller, diff, true)) { if (i_nextMoveTime.Passed()) { if (irand(0, RUNNING_CHANCE_RANDOMMV) > 0) creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); _setRandomLocation(creature); } else if (creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(), PET_FOLLOW_DIST+2.5f)) { creature.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); _setRandomLocation(creature); } } return true; }
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_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); // Stop the npc if moving if (vendor->HasUnitState(UNIT_STATE_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; // Items sold out are not displayed in list uint32 leftInStock = !item->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(item); if (!_player->isGameMaster() && !leftInStock) continue; ++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); }
bool WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff) { if (!&unit) return true; if (!path_id) return false; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) return true; // Clear the generator if the path doesn't exist if (!waypoints || !waypoints->size()) return false; Traveller<Creature> traveller(unit); i_nextMoveTime.Update(diff); i_destinationHolder.UpdateTraveller(traveller, diff, true); if (i_nextMoveTime.GetExpiry() < TIMEDIFF_NEXT_WP) { if (unit.IsStopped()) { if (StopedByPlayer) { ASSERT(node); InitTraveller(unit, *node); i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); StopedByPlayer = false; return true; } if (i_currentNode == waypoints->size() - 1) // If that's our last waypoint { if (repeating) // If the movement is repeating i_currentNode = 0; // Start moving all over again else { unit.SetHomePosition(node->x, node->y, node->z, unit.GetOrientation()); unit.GetMotionMaster()->Initialize(); return false; // Clear the waypoint movement } } else ++i_currentNode; node = waypoints->at(i_currentNode); InitTraveller(unit, *node); i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); //Call for creature group update if (unit.GetFormation() && unit.GetFormation()->getLeader() == &unit) unit.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); } else { //Determine waittime if (node->delay) i_nextMoveTime.Reset(node->delay); //note: disable "start" for mtmap if (node->event_id && urand(0,99) < node->event_chance) unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/); i_destinationHolder.ResetTravelTime(); MovementInform(unit); unit.UpdateWaypointID(i_currentNode); unit.ClearUnitState(UNIT_STAT_ROAMING); unit.Relocate(node->x, node->y, node->z); } } else { if (unit.IsStopped() && !i_destinationHolder.HasArrived()) { if (!StopedByPlayer) { i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); StopedByPlayer = true; } } } return true; }
void WorldSession::SendListInventory(uint64 vendorguid) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_LIST_INVENTORY"); Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); if (!pCreature) { 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 (pCreature->HasUnitState(UNIT_STAT_MOVING)) pCreature->StopMoving(); VendorItemData const* vItems = pCreature->GetVendorItems(); if (!vItems) { WorldPacket data(SMSG_LIST_INVENTORY, (8 + 1 + 1 + 2), true); data << uint64(vendorguid); data << uint8(0); // count==0, next will be error code data << uint8(0); // "Vendor has no inventory" SendPacket(&data); return; } uint32 numitems = vItems->GetItemCount(); uint8 count = 0; WorldPacket data(SMSG_LIST_INVENTORY, (8 + 1 + numitems * 9 * 4 + 1 * numitems + 2), true); data << uint64(vendorguid); size_t count_pos = data.wpos(); data << uint8(count); float discountMod = _player->GetReputationPriceDiscount(pCreature); for (uint32 vendorslot = 0; vendorslot < numitems; ++vendorslot) { if (VendorItem const* crItem = vItems->GetItem(vendorslot)) { if (ItemPrototype const *pProto = ObjectMgr::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; if (count == 150) break; // client can only display 15 pages // 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) { 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 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; }
void CreatureGroup::LeaderMoveTo(float x, float y, float z, bool run) { //! To do: This should probably get its own movement generator or use WaypointMovementGenerator. //! If the leader's path is known, member's path can be plotted as well using formation offsets. if (!m_leader) return; uint8 groupAI = sFormationMgr->CreatureGroupMap[m_leader->GetDBTableGUIDLow()]->groupAI; if (groupAI == 5) return; float pathDist = m_leader->GetExactDist(x, y, z); float pathAngle = m_leader->GetAngle(x, y); for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { Creature* member = itr->first; if (member == m_leader || !member->IsAlive() || member->GetVictim()) continue; // Xinef: If member is stunned / rooted etc don't allow to move him if (member->HasUnitState(UNIT_STATE_NOT_MOVE)) continue; // Xinef: this should be automatized, if turn angle is greater than PI/2 (90°) we should swap formation angle if (M_PI - fabs(fabs(m_leader->GetOrientation() - pathAngle) - M_PI) > M_PI*0.50f) { // pussywizard: in both cases should be 2*M_PI - follow_angle // pussywizard: also, GetCurrentWaypointID() returns 0..n-1, while point_1 must be > 0, so +1 // pussywizard: db table waypoint_data shouldn't have point id 0 and shouldn't have any gaps for this to work! // if (m_leader->GetCurrentWaypointID()+1 == itr->second->point_1 || m_leader->GetCurrentWaypointID()+1 == itr->second->point_2) itr->second->follow_angle = Position::NormalizeOrientation(itr->second->follow_angle + M_PI); //(2 * M_PI) - itr->second->follow_angle; } float followAngle = itr->second->follow_angle; float followDist = itr->second->follow_dist; float dx = x + cos(followAngle + pathAngle) * followDist; float dy = y + sin(followAngle + pathAngle) * followDist; float dz = z; Trinity::NormalizeMapCoord(dx); Trinity::NormalizeMapCoord(dy); member->UpdateGroundPositionZ(dx, dy, dz); member->SetUnitMovementFlags(m_leader->GetUnitMovementFlags()); // pussywizard: setting the same movementflags is not enough, spline decides whether leader walks/runs, so spline param is now passed as "run" parameter to this function if (run && member->IsWalking()) member->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); else if (!run && !member->IsWalking()) member->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); // xinef: if we move members to position without taking care of sizes, we should compare distance without sizes // xinef: change members speed basing on distance - if too far speed up, if too close slow down UnitMoveType mtype = Movement::SelectSpeedType(member->GetUnitMovementFlags()); member->SetSpeedRate(mtype, m_leader->GetSpeedRate(mtype) * member->GetExactDist(dx, dy, dz) / pathDist); member->GetMotionMaster()->MovePoint(0, dx, dy, dz); member->SetHomePosition(dx, dy, dz, pathAngle); } }
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature) { if (creature.HasUnitState(UNIT_STATE_CASTING) && !creature.CanMoveDuringChannel()) { creature.CastStop(); return; } float X, Y, Z, nx, ny, nz, ori, dist; creature.GetHomePosition(X, Y, Z, ori); Map const* map = creature.GetBaseMap(); // For 2D/3D system selection //bool is_land_ok = creature.canWalk(); //bool is_water_ok = creature.canSwim(); bool is_air_ok = creature.canFly(); const float angle = rand_norm() * (M_PI * 2); const float range = rand_norm() * wander_distance; const float distanceX = range * cos(angle); const float distanceY = range * sin(angle); nx = X + distanceX; ny = Y + distanceY; // prevent invalid coordinates generation Oregon::NormalizeMapCoord(nx); Oregon::NormalizeMapCoord(ny); dist = (nx - X) * (nx - X) + (ny - Y) * (ny - Y); if (is_air_ok) // 3D system above ground and above water (flying mode) { // Limit height change const float distanceZ = rand_norm() * sqrtf(dist) / 2.0f; nz = Z + distanceZ; float tz = map->GetHeight(nx, ny, nz - 2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height. float wz = map->GetWaterLevel(nx, ny); // Problem here, we must fly above the ground and water, not under. Let's try on next tick if (tz >= nz || wz >= nz) return; } //else if (is_water_ok) // 3D system under water and above ground (swimming mode) else // 2D only { dist = dist >= 100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE) // The fastest way to get an accurate result 90% of the time. // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long. nz = map->GetHeight(nx, ny, Z + dist - 2.0f, false); if (fabs(nz - Z) > dist) // Map check { nz = map->GetHeight(nx, ny, Z - 2.0f, true); // Vmap Horizontal or above if (fabs(nz - Z) > dist) { // Vmap Higher nz = map->GetHeight(nx, ny, Z + dist - 2.0f, true); // let's forget this bad coords where a z cannot be find and retry at next tick if (fabs(nz - Z) > dist) return; } } } if (is_air_ok) i_nextMoveTime.Reset(0); else { if (roll_chance_i(MOVEMENT_RANDOM_MMGEN_CHANCE_NO_BREAK)) i_nextMoveTime.Reset(urand(5000, 10000)); else i_nextMoveTime.Reset(urand(50, 400)); } creature.AddUnitState(UNIT_STATE_ROAMING); Movement::MoveSplineInit init(creature); init.MoveTo(nx, ny, nz, true); if (creature.IsPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(), PET_FOLLOW_DIST + 2.5f)) init.SetWalk(false); else init.SetWalk(true); init.Launch(); if (roll_chance_i(MOVEMENT_RANDOM_MMGEN_CHANCE_NO_BREAK)) i_nextMoveTime.Reset(50); else i_nextMoveTime.Reset(urand(1500, 10000)); // Keep a short wait time }
void RandomMovementGenerator<Creature>::Finalize(Creature& creature) { creature.ClearUnitState(UNIT_STATE_ROAMING); creature.SetWalk(!creature.HasUnitState(UNIT_STATE_RUNNING_STATE)); }