void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPacket& recvData) { uint64 guid; uint32 questId; uint8 unk1; recvData >> guid >> questId >> unk1; TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), questId, unk1); // Verify that the guid is valid and is a questgiver or involved in the requested quest Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM); if (!object || (!object->hasQuest(questId) && !object->hasInvolvedQuest(questId))) { _player->PlayerTalkClass->SendCloseGossip(); return; } if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) { // not sure here what should happen to quests with QUEST_FLAGS_AUTOCOMPLETE // if this breaks them, add && object->GetTypeId() == TYPEID_ITEM to this check // item-started quests never have that flag if (!_player->CanTakeQuest(quest, true)) return; if (quest->IsAutoAccept() && _player->CanAddQuest(quest, true)) _player->AddQuestAndCheckCompletion(quest, object); if (quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, object->GetGUID(), _player->CanCompleteQuest(quest->GetQuestId()), true); else _player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, object->GetGUID(), true); } }
void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPackets::Quest::QuestGiverQueryQuest& packet) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST QuestGiverGUID = %s, QuestID = %u, RespondToGiver = %u", packet.QuestGiverGUID.ToString().c_str(), packet.QuestID, packet.RespondToGiver); // Verify that the guid is valid and is a questgiver or involved in the requested quest Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, packet.QuestGiverGUID, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM); if (!object || (!object->hasQuest(packet.QuestID) && !object->hasInvolvedQuest(packet.QuestID))) { _player->PlayerTalkClass->SendCloseGossip(); return; } if (Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID)) { if (!_player->CanTakeQuest(quest, true)) return; if (quest->IsAutoAccept() && _player->CanAddQuest(quest, true)) _player->AddQuestAndCheckCompletion(quest, object); if (quest->IsAutoComplete()) _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, object->GetGUID(), _player->CanCompleteQuest(quest->GetQuestId()), true); else _player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, object->GetGUID(), true); } }
void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPacket & recv_data) { uint64 guid; uint32 quest; uint8 unk1; recv_data >> guid >> quest >> unk1; sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1); // Verify that the guid is valid and is a questgiver or involved in the requested quest Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM); if (!pObject || (!pObject->hasQuest(quest) && !pObject->hasInvolvedQuest(quest))) { _player->PlayerTalkClass->SendCloseGossip(); return; } Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest); if (pQuest) { if (pQuest->IsAutoAccept() && _player->CanAddQuest(pQuest, true)) { _player->AddQuest(pQuest, pObject); if (_player->CanCompleteQuest(quest)) _player->CompleteQuest(quest); } if (pQuest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, pObject->GetGUID(), _player->CanCompleteQuest(pQuest->GetQuestId()), true); else _player->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, pObject->GetGUID(), true); } }
void MapMgr::ChangeFarsightLocation(Player* plr, DynamicObject* farsight) { if(farsight == 0) { // We're clearing. for(ObjectSet::iterator itr = plr->m_visibleFarsightObjects.begin(); itr != plr->m_visibleFarsightObjects.end(); ++itr) { if(plr->IsVisible((*itr)->GetGUID()) && !plr->CanSee((*itr))) { // Send destroy plr->PushOutOfRange((*itr)->GetNewGUID()); } } plr->m_visibleFarsightObjects.clear(); } else { uint32 cellX = GetPosX(farsight->GetPositionX()); uint32 cellY = GetPosY(farsight->GetPositionY()); uint32 endX = (cellX <= _sizeX) ? cellX + 1 : (_sizeX - 1); uint32 endY = (cellY <= _sizeY) ? cellY + 1 : (_sizeY - 1); uint32 startX = cellX > 0 ? cellX - 1 : 0; uint32 startY = cellY > 0 ? cellY - 1 : 0; uint32 posX, posY; MapCell* cell; Object* obj; MapCell::ObjectSet::iterator iter, iend; uint32 count; for(posX = startX; posX <= endX; ++posX) { for(posY = startY; posY <= endY; ++posY) { cell = GetCell(posX, posY); if(cell) { iter = cell->Begin(); iend = cell->End(); for(; iter != iend; ++iter) { obj = (*iter); if(!plr->IsVisible(obj->GetGUID()) && plr->CanSee(obj) && farsight->GetDistance2dSq(obj) <= m_UpdateDistance) { ByteBuffer buf; count = obj->BuildCreateUpdateBlockForPlayer(&buf, plr); plr->PushCreationData(&buf, count); plr->m_visibleFarsightObjects.insert(obj); } } } } } } }
void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& recvPacket) { MovementInfo mi; // TODO: use a reference to a MovementInfo in Unit/Player class once implemented uint16 flags; // uint64 fullguid; // see below float speedWalk, speedRun, speedSwimBack, speedSwim, speedWalkBack, speedTurn, speedFly, speedFlyBack, speedPitchRate; uint32 unk32; Object *obj = (Object*)objmgr.GetObj(uguid, true); // also depleted objects Unit *u = NULL; if(obj) { if(obj->IsUnit()) u = (Unit*)obj; // only use for Unit:: functions!! else logdev("MovementUpdate: object "I64FMT" is not Unit (typeId=%u)",obj->GetGUID(),obj->GetTypeId()); } else { logerror("MovementUpdate for unknown object "I64FMT" typeid=%u",uguid,objtypeid); } recvPacket >> flags; mi.flags = 0; // not sure if its correct to set it to 0 (needs some starting flag?) if(flags & UPDATEFLAG_LIVING) { recvPacket >> mi.flags >> mi.unkFlags >> mi.time; logdev("MovementUpdate: TypeID=%u GUID="I64FMT" pObj=%X flags=%u mi.flags=%u",objtypeid,uguid,obj,flags,mi.flags); recvPacket >> mi.x >> mi.y >> mi.z >> mi.o; logdev("FLOATS: x=%f y=%f z=%f o=%f",mi.x, mi.y, mi.z ,mi.o); if(obj && obj->IsWorldObject()) ((WorldObject*)obj)->SetPosition(mi.x, mi.y, mi.z, mi.o); if(mi.flags & MOVEMENTFLAG_ONTRANSPORT) { mi.t_guid = recvPacket.GetPackedGuid(); recvPacket >> mi.t_x >> mi.t_y >> mi.t_z >> mi.t_o; recvPacket >> mi.t_time; // added in 2.0.3 recvPacket >> mi.t_seat; logdev("TRANSPORT @ mi.flags: guid="I64FMT" x=%f y=%f z=%f o=%f", mi.t_guid, mi.t_x, mi.t_y, mi.t_z, mi.t_o); }
void WorldSession::HandleQuestgiverQuestQueryOpcode(WorldPacket& recv_data) { uint64 guid; uint32 quest; recv_data >> guid >> quest; DEBUG_LOG("WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u", uint32(GUID_LOPART(guid)), quest); // Verify that the guid is valid and is a questgiver or involved in the requested quest Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM); if (!pObject || (!pObject->hasQuest(quest) && !pObject->hasInvolvedQuest(quest))) { _player->PlayerTalkClass->CloseGossip(); return; } Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest); if (pQuest) _player->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, pObject->GetGUID(), true); }
void WorldSession::HandleQuestgiverQueryQuestOpcode( WorldPacket & recv_data ) { uint64 guid; uint32 quest; uint8 unk1; recv_data >> guid >> quest >> unk1; sLog.outDebug( "WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1 ); // Verify that the guid is valid and is a questgiver or involved in the requested quest Object* pObject = _player->GetObjectByTypeMask(guid, TYPEMASK_CREATURE_GAMEOBJECT_OR_ITEM); if(!pObject||!pObject->hasQuest(quest) && !pObject->hasInvolvedQuest(quest)) { _player->PlayerTalkClass->CloseGossip(); return; } Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest); if ( pQuest ) { _player->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, pObject->GetGUID(), true); } }
void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPackets::Quest::QuestGiverStatusQuery& packet) { uint32 questStatus = DIALOG_STATUS_NONE; Object* questGiver = ObjectAccessor::GetObjectByTypeMask(*_player, packet.QuestGiverGUID, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT); if (!questGiver) { TC_LOG_INFO("network", "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for non-existing questgiver (%s)", packet.QuestGiverGUID.ToString().c_str()); return; } switch (questGiver->GetTypeId()) { case TYPEID_UNIT: { TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc, %s", questGiver->GetGUID().ToString().c_str()); if (!questGiver->ToCreature()->IsHostileTo(_player)) // do not show quest status to enemies questStatus = _player->GetQuestDialogStatus(questGiver); break; } case TYPEID_GAMEOBJECT: { TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject %s", questGiver->GetGUID().ToString().c_str()); questStatus = _player->GetQuestDialogStatus(questGiver); break; } default: TC_LOG_ERROR("network", "QuestGiver called for unexpected type %u", questGiver->GetTypeId()); break; } //inform client about status of quest _player->PlayerTalkClass->SendQuestGiverStatus(questStatus, packet.QuestGiverGUID); }
/// Process queued scripts void Map::ScriptsProcess() { if (m_scriptSchedule.empty()) return; ///- Process overdue queued scripts ScriptScheduleMap::iterator iter = m_scriptSchedule.begin(); // ok as multimap is a *sorted* associative container while (!m_scriptSchedule.empty() && (iter->first <= sWorld->GetGameTime())) { ScriptAction const& step = iter->second; Object* source = NULL; if (!step.sourceGUID.IsEmpty()) { switch (step.sourceGUID.GetHigh()) { case HighGuid::Item: // as well as HIGHGUID_CONTAINER if (Player* player = HashMapHolder<Player>::Find(step.ownerGUID)) source = player->GetItemByGuid(step.sourceGUID); break; case HighGuid::Creature: case HighGuid::Vehicle: source = GetCreature(step.sourceGUID); break; case HighGuid::Pet: source = GetPet(step.sourceGUID); break; case HighGuid::Player: source = HashMapHolder<Player>::Find(step.sourceGUID); break; case HighGuid::GameObject: case HighGuid::Transport: source = GetGameObject(step.sourceGUID); break; case HighGuid::Corpse: source = GetCorpse(step.sourceGUID); break; default: TC_LOG_ERROR("scripts", "%s source with unsupported high guid %s.", step.script->GetDebugInfo().c_str(), step.sourceGUID.ToString().c_str()); break; } } WorldObject* target = NULL; if (!step.targetGUID.IsEmpty()) { switch (step.targetGUID.GetHigh()) { case HighGuid::Creature: case HighGuid::Vehicle: target = GetCreature(step.targetGUID); break; case HighGuid::Pet: target = GetPet(step.targetGUID); break; case HighGuid::Player: target = HashMapHolder<Player>::Find(step.targetGUID); break; case HighGuid::GameObject: case HighGuid::Transport: target = GetGameObject(step.targetGUID); break; case HighGuid::Corpse: target = GetCorpse(step.targetGUID); break; default: TC_LOG_ERROR("scripts", "%s target with unsupported high guid %s.", step.script->GetDebugInfo().c_str(), step.targetGUID.ToString().c_str()); break; } } switch (step.script->command) { case SCRIPT_COMMAND_TALK: { if (step.script->Talk.ChatType > CHAT_TYPE_BOSS_WHISPER) { TC_LOG_ERROR("scripts", "%s invalid chat type (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->Talk.ChatType); break; } if (step.script->Talk.Flags & SF_TALK_USE_PLAYER) source = _GetScriptPlayerSourceOrTarget(source, target, step.script); else source = _GetScriptCreatureSourceOrTarget(source, target, step.script); if (source) { Unit* sourceUnit = source->ToUnit(); if (!sourceUnit) { TC_LOG_ERROR("scripts", "%s source object (%s) is not an unit, skipping.", step.script->GetDebugInfo().c_str(), source->GetGUID().ToString().c_str()); break; } switch (step.script->Talk.ChatType) { case CHAT_TYPE_SAY: sourceUnit->Say(step.script->Talk.TextID, target); break; case CHAT_TYPE_YELL: sourceUnit->Yell(step.script->Talk.TextID, target); break; case CHAT_TYPE_TEXT_EMOTE: case CHAT_TYPE_BOSS_EMOTE: sourceUnit->TextEmote(step.script->Talk.TextID, target, step.script->Talk.ChatType == CHAT_TYPE_BOSS_EMOTE); break; case CHAT_TYPE_WHISPER: case CHAT_TYPE_BOSS_WHISPER: { Player* receiver = target ? target->ToPlayer() : nullptr; if (!receiver) TC_LOG_ERROR("scripts", "%s attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str()); else sourceUnit->Whisper(step.script->Talk.TextID, receiver, step.script->Talk.ChatType == CHAT_TYPE_BOSS_WHISPER); break; } default: break; // must be already checked at load } } break; } case SCRIPT_COMMAND_EMOTE: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { if (step.script->Emote.Flags & SF_EMOTE_USE_STATE) cSource->SetUInt32Value(UNIT_NPC_EMOTESTATE, step.script->Emote.EmoteID); else cSource->HandleEmoteCommand(step.script->Emote.EmoteID); } break; case SCRIPT_COMMAND_FIELD_SET: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FieldSet.FieldID <= OBJECT_FIELD_ENTRY || step.script->FieldSet.FieldID >= cSource->GetValuesCount()) TC_LOG_ERROR("scripts", "%s wrong field %u (max count: %u) in object (TypeId: %u, %s) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FieldSet.FieldID, cSource->GetValuesCount(), cSource->GetTypeId(), cSource->GetGUID().ToString().c_str()); else cSource->SetUInt32Value(step.script->FieldSet.FieldID, step.script->FieldSet.FieldValue); } break; case SCRIPT_COMMAND_MOVE_TO: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { Unit* unit = (Unit*)cSource; if (step.script->MoveTo.TravelTime != 0) { float speed = unit->GetDistance(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ) / ((float)step.script->MoveTo.TravelTime * 0.001f); unit->MonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, speed); } else unit->NearTeleportTo(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, unit->GetOrientation()); } break; case SCRIPT_COMMAND_FLAG_SET: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FlagToggle.FieldID <= OBJECT_FIELD_ENTRY || step.script->FlagToggle.FieldID >= cSource->GetValuesCount()) { TC_LOG_ERROR("scripts", "%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, %s) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FlagToggle.FieldID, cSource->GetValuesCount(), cSource->GetTypeId(), cSource->GetEntry(), cSource->GetGUID().ToString().c_str()); } else cSource->SetFlag(step.script->FlagToggle.FieldID, step.script->FlagToggle.FieldValue); } break; case SCRIPT_COMMAND_FLAG_REMOVE: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FlagToggle.FieldID <= OBJECT_FIELD_ENTRY || step.script->FlagToggle.FieldID >= cSource->GetValuesCount()) { TC_LOG_ERROR("scripts", "%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, %s) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FlagToggle.FieldID, cSource->GetValuesCount(), cSource->GetTypeId(), cSource->GetEntry(), cSource->GetGUID().ToString().c_str()); } else cSource->RemoveFlag(step.script->FlagToggle.FieldID, step.script->FlagToggle.FieldValue); } break; case SCRIPT_COMMAND_TELEPORT_TO: if (step.script->TeleportTo.Flags & SF_TELEPORT_USE_CREATURE) { // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true)) cSource->NearTeleportTo(step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation); } else { // Source or target must be Player. if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script)) player->TeleportTo(step.script->TeleportTo.MapID, step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation); } break; case SCRIPT_COMMAND_QUEST_EXPLORED: { if (!source) { TC_LOG_ERROR("scripts", "%s source object is NULL.", step.script->GetDebugInfo().c_str()); break; } if (!target) { TC_LOG_ERROR("scripts", "%s target object is NULL.", step.script->GetDebugInfo().c_str()); break; } // when script called for item spell casting then target == (unit or GO) and source is player WorldObject* worldObject; Player* player = target->ToPlayer(); if (player) { if (source->GetTypeId() != TYPEID_UNIT && source->GetTypeId() != TYPEID_GAMEOBJECT && source->GetTypeId() != TYPEID_PLAYER) { TC_LOG_ERROR("scripts", "%s source is not unit, gameobject or player (TypeId: %u, Entry: %u, %s), skipping.", step.script->GetDebugInfo().c_str(), source->GetTypeId(), source->GetEntry(), source->GetGUID().ToString().c_str()); break; } worldObject = dynamic_cast<WorldObject*>(source); } else { player = source->ToPlayer(); if (player) { if (target->GetTypeId() != TYPEID_UNIT && target->GetTypeId() != TYPEID_GAMEOBJECT && target->GetTypeId() != TYPEID_PLAYER) { TC_LOG_ERROR("scripts", "%s target is not unit, gameobject or player (TypeId: %u, Entry: %u, %s), skipping.", step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUID().ToString().c_str()); break; } worldObject = dynamic_cast<WorldObject*>(target); } else { TC_LOG_ERROR("scripts", "%s neither source nor target is player (Entry: %u, GUID: %s; target: Entry: %u, GUID: %s), skipping.", step.script->GetDebugInfo().c_str(), source->GetEntry(), source->GetGUID().ToString().c_str(), target->GetEntry(), target->GetGUID().ToString().c_str()); break; } } // quest id and flags checked at script loading if ((worldObject->GetTypeId() != TYPEID_UNIT || ((Unit*)worldObject)->IsAlive()) && (step.script->QuestExplored.Distance == 0 || worldObject->IsWithinDistInMap(player, float(step.script->QuestExplored.Distance)))) player->AreaExploredOrEventHappens(step.script->QuestExplored.QuestID); else player->FailQuest(step.script->QuestExplored.QuestID); break; } case SCRIPT_COMMAND_KILL_CREDIT: // Source or target must be Player. if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script)) { if (step.script->KillCredit.Flags & SF_KILLCREDIT_REWARD_GROUP) player->RewardPlayerAndGroupAtEvent(step.script->KillCredit.CreatureEntry, player); else player->KilledMonsterCredit(step.script->KillCredit.CreatureEntry); } break; case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: if (!step.script->RespawnGameobject.GOGuid) { TC_LOG_ERROR("scripts", "%s gameobject guid (datalong) is not specified.", step.script->GetDebugInfo().c_str()); break; } // Source or target must be WorldObject. if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script)) { GameObject* pGO = _FindGameObject(pSummoner, step.script->RespawnGameobject.GOGuid); if (!pGO) { TC_LOG_ERROR("scripts", "%s gameobject was not found (guid: %u).", step.script->GetDebugInfo().c_str(), step.script->RespawnGameobject.GOGuid); break; } if (pGO->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE || pGO->GetGoType() == GAMEOBJECT_TYPE_DOOR || pGO->GetGoType() == GAMEOBJECT_TYPE_BUTTON || pGO->GetGoType() == GAMEOBJECT_TYPE_TRAP) { TC_LOG_ERROR("scripts", "%s can not be used with gameobject of type %u (guid: %u).", step.script->GetDebugInfo().c_str(), uint32(pGO->GetGoType()), step.script->RespawnGameobject.GOGuid); break; } // Check that GO is not spawned if (!pGO->isSpawned()) { int32 nTimeToDespawn = std::max(5, int32(step.script->RespawnGameobject.DespawnDelay)); pGO->SetLootState(GO_READY); pGO->SetRespawnTime(nTimeToDespawn); pGO->GetMap()->AddToMap(pGO); } } break; case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: { // Source must be WorldObject. if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script)) { if (!step.script->TempSummonCreature.CreatureEntry) TC_LOG_ERROR("scripts", "%s creature entry (datalong) is not specified.", step.script->GetDebugInfo().c_str()); else { float x = step.script->TempSummonCreature.PosX; float y = step.script->TempSummonCreature.PosY; float z = step.script->TempSummonCreature.PosZ; float o = step.script->TempSummonCreature.Orientation; if (!pSummoner->SummonCreature(step.script->TempSummonCreature.CreatureEntry, x, y, z, o, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, step.script->TempSummonCreature.DespawnDelay)) TC_LOG_ERROR("scripts", "%s creature was not spawned (entry: %u).", step.script->GetDebugInfo().c_str(), step.script->TempSummonCreature.CreatureEntry); } } break; } case SCRIPT_COMMAND_OPEN_DOOR: case SCRIPT_COMMAND_CLOSE_DOOR: _ScriptProcessDoor(source, target, step.script); break; case SCRIPT_COMMAND_ACTIVATE_OBJECT: // Source must be Unit. if (Unit* unit = _GetScriptUnit(source, true, step.script)) { // Target must be GameObject. if (!target) { TC_LOG_ERROR("scripts", "%s target object is NULL.", step.script->GetDebugInfo().c_str()); break; } if (target->GetTypeId() != TYPEID_GAMEOBJECT) { TC_LOG_ERROR("scripts", "%s target object is not gameobject (TypeId: %u, Entry: %u, %s), skipping.", step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUID().ToString().c_str()); break; } if (GameObject* pGO = target->ToGameObject()) pGO->Use(unit); } break; case SCRIPT_COMMAND_REMOVE_AURA: { // Source (datalong2 != 0) or target (datalong2 == 0) must be Unit. bool bReverse = step.script->RemoveAura.Flags & SF_REMOVEAURA_REVERSE; if (Unit* unit = _GetScriptUnit(bReverse ? source : target, bReverse, step.script)) unit->RemoveAurasDueToSpell(step.script->RemoveAura.SpellID); break; } case SCRIPT_COMMAND_CAST_SPELL: { /// @todo Allow gameobjects to be targets and casters if (!source && !target) { TC_LOG_ERROR("scripts", "%s source and target objects are NULL.", step.script->GetDebugInfo().c_str()); break; } Unit* uSource = NULL; Unit* uTarget = NULL; // source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s switch (step.script->CastSpell.Flags) { case SF_CASTSPELL_SOURCE_TO_TARGET: // source -> target uSource = source ? source->ToUnit() : NULL; uTarget = target ? target->ToUnit() : NULL; break; case SF_CASTSPELL_SOURCE_TO_SOURCE: // source -> source uSource = source ? source->ToUnit() : NULL; uTarget = uSource; break; case SF_CASTSPELL_TARGET_TO_TARGET: // target -> target uSource = target ? target->ToUnit() : NULL; uTarget = uSource; break; case SF_CASTSPELL_TARGET_TO_SOURCE: // target -> source uSource = target ? target->ToUnit() : NULL; uTarget = source ? source->ToUnit() : NULL; break; case SF_CASTSPELL_SEARCH_CREATURE: // source -> creature with entry uSource = source ? source->ToUnit() : NULL; uTarget = uSource ? uSource->FindNearestCreature(abs(step.script->CastSpell.CreatureEntry), step.script->CastSpell.SearchRadius) : NULL; break; } if (!uSource || !uSource->isType(TYPEMASK_UNIT)) { TC_LOG_ERROR("scripts", "%s no source unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->CastSpell.SpellID); break; } if (!uTarget || !uTarget->isType(TYPEMASK_UNIT)) { TC_LOG_ERROR("scripts", "%s no target unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->CastSpell.SpellID); break; } bool triggered = (step.script->CastSpell.Flags != 4) ? step.script->CastSpell.CreatureEntry & SF_CASTSPELL_TRIGGERED : step.script->CastSpell.CreatureEntry < 0; uSource->CastSpell(uTarget, step.script->CastSpell.SpellID, triggered); break; } case SCRIPT_COMMAND_PLAY_SOUND: // Source must be WorldObject. if (WorldObject* object = _GetScriptWorldObject(source, true, step.script)) { // PlaySound.Flags bitmask: 0/1=anyone/target Player* player = NULL; if (step.script->PlaySound.Flags & SF_PLAYSOUND_TARGET_PLAYER) { // Target must be Player. player = _GetScriptPlayer(target, false, step.script); if (!target) break; } // PlaySound.Flags bitmask: 0/2=without/with distance dependent if (step.script->PlaySound.Flags & SF_PLAYSOUND_DISTANCE_SOUND) object->PlayDistanceSound(step.script->PlaySound.SoundID, player); else object->PlayDirectSound(step.script->PlaySound.SoundID, player); } break; case SCRIPT_COMMAND_CREATE_ITEM: // Target or source must be Player. if (Player* pReceiver = _GetScriptPlayerSourceOrTarget(source, target, step.script)) { ItemPosCountVec dest; InventoryResult msg = pReceiver->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, step.script->CreateItem.ItemEntry, step.script->CreateItem.Amount); if (msg == EQUIP_ERR_OK) { if (Item* item = pReceiver->StoreNewItem(dest, step.script->CreateItem.ItemEntry, true)) pReceiver->SendNewItem(item, step.script->CreateItem.Amount, false, true); } else pReceiver->SendEquipError(msg, NULL, NULL, step.script->CreateItem.ItemEntry); } break; case SCRIPT_COMMAND_DESPAWN_SELF: // Target or source must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true)) cSource->DespawnOrUnsummon(step.script->DespawnSelf.DespawnDelay); break; case SCRIPT_COMMAND_LOAD_PATH: // Source must be Unit. if (Unit* unit = _GetScriptUnit(source, true, step.script)) { if (!sWaypointMgr->GetPath(step.script->LoadPath.PathID)) TC_LOG_ERROR("scripts", "%s source object has an invalid path (%u), skipping.", step.script->GetDebugInfo().c_str(), step.script->LoadPath.PathID); else unit->GetMotionMaster()->MovePath(step.script->LoadPath.PathID, step.script->LoadPath.IsRepeatable != 0); } break; case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT: { if (!step.script->CallScript.CreatureEntry) { TC_LOG_ERROR("scripts", "%s creature entry is not specified, skipping.", step.script->GetDebugInfo().c_str()); break; } if (!step.script->CallScript.ScriptID) { TC_LOG_ERROR("scripts", "%s script id is not specified, skipping.", step.script->GetDebugInfo().c_str()); break; } Creature* cTarget = NULL; auto creatureBounds = _creatureBySpawnIdStore.equal_range(step.script->CallScript.CreatureEntry); if (creatureBounds.first != creatureBounds.second) { // Prefer alive (last respawned) creature auto creatureItr = std::find_if(creatureBounds.first, creatureBounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair) { return pair.second->IsAlive(); }); cTarget = creatureItr != creatureBounds.second ? creatureItr->second : creatureBounds.first->second; } if (!cTarget) { TC_LOG_ERROR("scripts", "%s target was not found (entry: %u)", step.script->GetDebugInfo().c_str(), step.script->CallScript.CreatureEntry); break; } //Lets choose our ScriptMap map ScriptMapMap* datamap = GetScriptsMapByType(ScriptsType(step.script->CallScript.ScriptType)); //if no scriptmap present... if (!datamap) { TC_LOG_ERROR("scripts", "%s unknown scriptmap (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->CallScript.ScriptType); break; } // Insert script into schedule but do not start it ScriptsStart(*datamap, step.script->CallScript.ScriptID, cTarget, NULL); break; } case SCRIPT_COMMAND_KILL: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { if (cSource->isDead()) { TC_LOG_ERROR("scripts", "%s creature is already dead (Entry: %u, %s)", step.script->GetDebugInfo().c_str(), cSource->GetEntry(), cSource->GetGUID().ToString().c_str()); } else { cSource->setDeathState(JUST_DIED); if (step.script->Kill.RemoveCorpse == 1) cSource->RemoveCorpse(); } } break; case SCRIPT_COMMAND_ORIENTATION: // Source must be Unit. if (Unit* sourceUnit = _GetScriptUnit(source, true, step.script)) { if (step.script->Orientation.Flags & SF_ORIENTATION_FACE_TARGET) { // Target must be Unit. Unit* targetUnit = _GetScriptUnit(target, false, step.script); if (!targetUnit) break; sourceUnit->SetFacingToObject(targetUnit); } else sourceUnit->SetFacingTo(step.script->Orientation.Orientation); } break; case SCRIPT_COMMAND_EQUIP: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) cSource->LoadEquipment(step.script->Equip.EquipmentID); break; case SCRIPT_COMMAND_MODEL: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) cSource->SetDisplayId(step.script->Model.ModelID); break; case SCRIPT_COMMAND_CLOSE_GOSSIP: // Source must be Player. if (Player* player = _GetScriptPlayer(source, true, step.script)) player->PlayerTalkClass->SendCloseGossip(); break; case SCRIPT_COMMAND_PLAYMOVIE: // Source must be Player. if (Player* player = _GetScriptPlayer(source, true, step.script)) player->SendMovieStart(step.script->PlayMovie.MovieID); break; case SCRIPT_COMMAND_MOVEMENT: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) { if (!cSource->IsAlive()) return; cSource->GetMotionMaster()->MovementExpired(); cSource->GetMotionMaster()->MoveIdle(); switch (step.script->Movement.MovementType) { case RANDOM_MOTION_TYPE: cSource->GetMotionMaster()->MoveRandom((float)step.script->Movement.MovementDistance); break; case WAYPOINT_MOTION_TYPE: cSource->GetMotionMaster()->MovePath(step.script->Movement.Path, false); break; } } break; case SCRIPT_COMMAND_PLAY_ANIMKIT: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) cSource->PlayOneShotAnimKitId(step.script->PlayAnimKit.AnimKitID); break; default: TC_LOG_ERROR("scripts", "Unknown script command %s.", step.script->GetDebugInfo().c_str()); break; } m_scriptSchedule.erase(iter); iter = m_scriptSchedule.begin(); sMapMgr->DecreaseScheduledScriptCount(); } }
/// Process queued scripts void Map::ScriptsProcess() { if (m_scriptSchedule.empty()) return; ///- Process overdue queued scripts ScriptScheduleMap::iterator iter = m_scriptSchedule.begin(); // ok as multimap is a *sorted* associative container while (!m_scriptSchedule.empty() && (iter->first <= sWorld->GetGameTime())) { ScriptAction const& step = iter->second; Object* source = NULL; if (step.sourceGUID) { switch (GUID_HIPART(step.sourceGUID)) { case HIGHGUID_ITEM: // as well as HIGHGUID_CONTAINER if (Player* player = HashMapHolder<Player>::Find(step.ownerGUID)) source = player->GetItemByGuid(step.sourceGUID); break; case HIGHGUID_UNIT: case HIGHGUID_VEHICLE: source = HashMapHolder<Creature>::Find(step.sourceGUID); break; case HIGHGUID_PET: source = HashMapHolder<Pet>::Find(step.sourceGUID); break; case HIGHGUID_PLAYER: source = HashMapHolder<Player>::Find(step.sourceGUID); break; case HIGHGUID_GAMEOBJECT: source = HashMapHolder<GameObject>::Find(step.sourceGUID); break; case HIGHGUID_CORPSE: source = HashMapHolder<Corpse>::Find(step.sourceGUID); break; case HIGHGUID_MO_TRANSPORT: for (MapManager::TransportSet::iterator itr2 = sMapMgr->m_Transports.begin(); itr2 != sMapMgr->m_Transports.end(); ++itr2) { if ((*itr2)->GetGUID() == step.sourceGUID) { source = *itr2; break; } } break; default: sLog->outError(LOG_FILTER_TSCR, "%s source with unsupported high guid (GUID: " UI64FMTD ", high guid: %u).", step.script->GetDebugInfo().c_str(), step.sourceGUID, GUID_HIPART(step.sourceGUID)); break; } } Object* target = NULL; if (step.targetGUID) { switch (GUID_HIPART(step.targetGUID)) { case HIGHGUID_UNIT: case HIGHGUID_VEHICLE: target = HashMapHolder<Creature>::Find(step.targetGUID); break; case HIGHGUID_PET: target = HashMapHolder<Pet>::Find(step.targetGUID); break; case HIGHGUID_PLAYER: // empty GUID case also target = HashMapHolder<Player>::Find(step.targetGUID); break; case HIGHGUID_GAMEOBJECT: target = HashMapHolder<GameObject>::Find(step.targetGUID); break; case HIGHGUID_CORPSE: target = HashMapHolder<Corpse>::Find(step.targetGUID); break; default: sLog->outError(LOG_FILTER_TSCR, "%s target with unsupported high guid (GUID: " UI64FMTD ", high guid: %u).", step.script->GetDebugInfo().c_str(), step.targetGUID, GUID_HIPART(step.targetGUID)); break; } } switch (step.script->command) { case SCRIPT_COMMAND_TALK: if (step.script->Talk.ChatType > CHAT_TYPE_WHISPER && step.script->Talk.ChatType != CHAT_MSG_RAID_BOSS_WHISPER) { sLog->outError(LOG_FILTER_TSCR, "%s invalid chat type (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->Talk.ChatType); break; } if (step.script->Talk.Flags & SF_TALK_USE_PLAYER) { if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script)) { LocaleConstant loc_idx = player->GetSession()->GetSessionDbLocaleIndex(); std::string text(sObjectMgr->GetTrinityString(step.script->Talk.TextID, loc_idx)); switch (step.script->Talk.ChatType) { case CHAT_TYPE_SAY: player->Say(text, LANG_UNIVERSAL); break; case CHAT_TYPE_YELL: player->Yell(text, LANG_UNIVERSAL); break; case CHAT_TYPE_TEXT_EMOTE: case CHAT_TYPE_BOSS_EMOTE: player->TextEmote(text); break; case CHAT_TYPE_WHISPER: case CHAT_MSG_RAID_BOSS_WHISPER: { uint64 targetGUID = target ? target->GetGUID() : 0; if (!targetGUID || !IS_PLAYER_GUID(targetGUID)) sLog->outError(LOG_FILTER_TSCR, "%s attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str()); else player->Whisper(text, LANG_UNIVERSAL, targetGUID); break; } default: break; // must be already checked at load } } } else { // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { uint64 targetGUID = target ? target->GetGUID() : 0; switch (step.script->Talk.ChatType) { case CHAT_TYPE_SAY: cSource->Say(step.script->Talk.TextID, LANG_UNIVERSAL, targetGUID); break; case CHAT_TYPE_YELL: cSource->Yell(step.script->Talk.TextID, LANG_UNIVERSAL, targetGUID); break; case CHAT_TYPE_TEXT_EMOTE: cSource->TextEmote(step.script->Talk.TextID, targetGUID); break; case CHAT_TYPE_BOSS_EMOTE: cSource->MonsterTextEmote(step.script->Talk.TextID, targetGUID, true); break; case CHAT_TYPE_WHISPER: if (!targetGUID || !IS_PLAYER_GUID(targetGUID)) sLog->outError(LOG_FILTER_TSCR, "%s attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str()); else cSource->Whisper(step.script->Talk.TextID, targetGUID); break; case CHAT_MSG_RAID_BOSS_WHISPER: if (!targetGUID || !IS_PLAYER_GUID(targetGUID)) sLog->outError(LOG_FILTER_TSCR, "%s attempt to raidbosswhisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str()); else cSource->MonsterWhisper(step.script->Talk.TextID, targetGUID, true); break; default: break; // must be already checked at load } } } break; case SCRIPT_COMMAND_EMOTE: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { if (step.script->Emote.Flags & SF_EMOTE_USE_STATE) cSource->SetUInt32Value(UNIT_NPC_EMOTESTATE, step.script->Emote.EmoteID); else cSource->HandleEmoteCommand(step.script->Emote.EmoteID); } break; case SCRIPT_COMMAND_FIELD_SET: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FieldSet.FieldID <= OBJECT_FIELD_ENTRY || step.script->FieldSet.FieldID >= cSource->GetValuesCount()) sLog->outError(LOG_FILTER_TSCR, "%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FieldSet.FieldID, cSource->GetValuesCount(), cSource->GetTypeId(), cSource->GetEntry(), cSource->GetGUIDLow()); else cSource->SetUInt32Value(step.script->FieldSet.FieldID, step.script->FieldSet.FieldValue); } break; case SCRIPT_COMMAND_MOVE_TO: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { Unit * unit = (Unit*)cSource; if (step.script->MoveTo.TravelTime != 0) { float speed = unit->GetDistance(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ) / ((float)step.script->MoveTo.TravelTime * 0.001f); unit->MonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, speed); } else unit->NearTeleportTo(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, unit->GetOrientation()); } break; case SCRIPT_COMMAND_FLAG_SET: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FlagToggle.FieldID <= OBJECT_FIELD_ENTRY || step.script->FlagToggle.FieldID >= cSource->GetValuesCount()) sLog->outError(LOG_FILTER_TSCR, "%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FlagToggle.FieldID, source->GetValuesCount(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow()); else cSource->SetFlag(step.script->FlagToggle.FieldID, step.script->FlagToggle.FieldValue); } break; case SCRIPT_COMMAND_FLAG_REMOVE: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FlagToggle.FieldID <= OBJECT_FIELD_ENTRY || step.script->FlagToggle.FieldID >= cSource->GetValuesCount()) sLog->outError(LOG_FILTER_TSCR, "%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FlagToggle.FieldID, source->GetValuesCount(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow()); else cSource->RemoveFlag(step.script->FlagToggle.FieldID, step.script->FlagToggle.FieldValue); } break; case SCRIPT_COMMAND_TELEPORT_TO: if (step.script->TeleportTo.Flags & SF_TELEPORT_USE_CREATURE) { // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true)) cSource->NearTeleportTo(step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation); } else { // Source or target must be Player. if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script)) player->TeleportTo(step.script->TeleportTo.MapID, step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation); } break; case SCRIPT_COMMAND_QUEST_EXPLORED: { if (!source) { sLog->outError(LOG_FILTER_TSCR, "%s source object is NULL.", step.script->GetDebugInfo().c_str()); break; } if (!target) { sLog->outError(LOG_FILTER_TSCR, "%s target object is NULL.", step.script->GetDebugInfo().c_str()); break; } // when script called for item spell casting then target == (unit or GO) and source is player WorldObject* worldObject; Player* player = target->ToPlayer(); if (player) { if (source->GetTypeId() != TYPEID_UNIT && source->GetTypeId() != TYPEID_GAMEOBJECT && source->GetTypeId() != TYPEID_PLAYER) { sLog->outError(LOG_FILTER_TSCR, "%s source is not unit, gameobject or player (TypeId: %u, Entry: %u, GUID: %u), skipping.", step.script->GetDebugInfo().c_str(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow()); break; } worldObject = dynamic_cast<WorldObject*>(source); } else { player = source->ToPlayer(); if (player) { if (target->GetTypeId() != TYPEID_UNIT && target->GetTypeId() != TYPEID_GAMEOBJECT && target->GetTypeId() != TYPEID_PLAYER) { sLog->outError(LOG_FILTER_TSCR, "%s target is not unit, gameobject or player (TypeId: %u, Entry: %u, GUID: %u), skipping.", step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUIDLow()); break; } worldObject = dynamic_cast<WorldObject*>(target); } else { sLog->outError(LOG_FILTER_TSCR, "%s neither source nor target is player (source: TypeId: %u, Entry: %u, GUID: %u; target: TypeId: %u, Entry: %u, GUID: %u), skipping.", step.script->GetDebugInfo().c_str(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow(), target->GetTypeId(), target->GetEntry(), target->GetGUIDLow()); break; } } // quest id and flags checked at script loading if ((worldObject->GetTypeId() != TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) && (step.script->QuestExplored.Distance == 0 || worldObject->IsWithinDistInMap(player, float(step.script->QuestExplored.Distance)))) player->AreaExploredOrEventHappens(step.script->QuestExplored.QuestID); else player->FailQuest(step.script->QuestExplored.QuestID); break; } case SCRIPT_COMMAND_KILL_CREDIT: // Source or target must be Player. if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script)) { if (step.script->KillCredit.Flags & SF_KILLCREDIT_REWARD_GROUP) player->RewardPlayerAndGroupAtEvent(step.script->KillCredit.CreatureEntry, player); else player->KilledMonsterCredit(step.script->KillCredit.CreatureEntry, 0); } break; case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: if (!step.script->RespawnGameobject.GOGuid) { sLog->outError(LOG_FILTER_TSCR, "%s gameobject guid (datalong) is not specified.", step.script->GetDebugInfo().c_str()); break; } // Source or target must be WorldObject. if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script)) { GameObject* pGO = _FindGameObject(pSummoner, step.script->RespawnGameobject.GOGuid); if (!pGO) { sLog->outError(LOG_FILTER_TSCR, "%s gameobject was not found (guid: %u).", step.script->GetDebugInfo().c_str(), step.script->RespawnGameobject.GOGuid); break; } if (pGO->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE || pGO->GetGoType() == GAMEOBJECT_TYPE_DOOR || pGO->GetGoType() == GAMEOBJECT_TYPE_BUTTON || pGO->GetGoType() == GAMEOBJECT_TYPE_TRAP) { sLog->outError(LOG_FILTER_TSCR, "%s can not be used with gameobject of type %u (guid: %u).", step.script->GetDebugInfo().c_str(), uint32(pGO->GetGoType()), step.script->RespawnGameobject.GOGuid); break; } // Check that GO is not spawned if (!pGO->isSpawned()) { int32 nTimeToDespawn = std::max(5, int32(step.script->RespawnGameobject.DespawnDelay)); pGO->SetLootState(GO_READY); pGO->SetRespawnTime(nTimeToDespawn); pGO->GetMap()->AddToMap(pGO); } } break; case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: { // Source must be WorldObject. if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script)) { if (!step.script->TempSummonCreature.CreatureEntry) sLog->outError(LOG_FILTER_TSCR, "%s creature entry (datalong) is not specified.", step.script->GetDebugInfo().c_str()); else { float x = step.script->TempSummonCreature.PosX; float y = step.script->TempSummonCreature.PosY; float z = step.script->TempSummonCreature.PosZ; float o = step.script->TempSummonCreature.Orientation; if (!pSummoner->SummonCreature(step.script->TempSummonCreature.CreatureEntry, x, y, z, o, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, step.script->TempSummonCreature.DespawnDelay)) sLog->outError(LOG_FILTER_TSCR, "%s creature was not spawned (entry: %u).", step.script->GetDebugInfo().c_str(), step.script->TempSummonCreature.CreatureEntry); } } break; } case SCRIPT_COMMAND_OPEN_DOOR: case SCRIPT_COMMAND_CLOSE_DOOR: _ScriptProcessDoor(source, target, step.script); break; case SCRIPT_COMMAND_ACTIVATE_OBJECT: // Source must be Unit. if (Unit* unit = _GetScriptUnit(source, true, step.script)) { // Target must be GameObject. if (!target) { sLog->outError(LOG_FILTER_TSCR, "%s target object is NULL.", step.script->GetDebugInfo().c_str()); break; } if (target->GetTypeId() != TYPEID_GAMEOBJECT) { sLog->outError(LOG_FILTER_TSCR, "%s target object is not gameobject (TypeId: %u, Entry: %u, GUID: %u), skipping.", step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUIDLow()); break; } if (GameObject* pGO = target->ToGameObject()) pGO->Use(unit); } break; case SCRIPT_COMMAND_REMOVE_AURA: { // Source (datalong2 != 0) or target (datalong2 == 0) must be Unit. bool bReverse = step.script->RemoveAura.Flags & SF_REMOVEAURA_REVERSE; if (Unit* unit = _GetScriptUnit(bReverse ? source : target, bReverse, step.script)) unit->RemoveAurasDueToSpell(step.script->RemoveAura.SpellID); break; } case SCRIPT_COMMAND_CAST_SPELL: { // TODO: Allow gameobjects to be targets and casters if (!source && !target) { sLog->outError(LOG_FILTER_TSCR, "%s source and target objects are NULL.", step.script->GetDebugInfo().c_str()); break; } Unit* uSource = NULL; Unit* uTarget = NULL; // source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s switch (step.script->CastSpell.Flags) { case SF_CASTSPELL_SOURCE_TO_TARGET: // source -> target uSource = source ? source->ToUnit() : NULL; uTarget = target ? target->ToUnit() : NULL; break; case SF_CASTSPELL_SOURCE_TO_SOURCE: // source -> source uSource = source ? source->ToUnit() : NULL; uTarget = uSource; break; case SF_CASTSPELL_TARGET_TO_TARGET: // target -> target uSource = target ? target->ToUnit() : NULL; uTarget = uSource; break; case SF_CASTSPELL_TARGET_TO_SOURCE: // target -> source uSource = target ? target->ToUnit() : NULL; uTarget = source ? source->ToUnit() : NULL; break; case SF_CASTSPELL_SEARCH_CREATURE: // source -> creature with entry uSource = source ? source->ToUnit() : NULL; uTarget = uSource ? GetClosestCreatureWithEntry(uSource, abs(step.script->CastSpell.CreatureEntry), step.script->CastSpell.SearchRadius) : NULL; break; } if (!uSource || !uSource->isType(TYPEMASK_UNIT)) { sLog->outError(LOG_FILTER_TSCR, "%s no source unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->CastSpell.SpellID); break; } if (!uTarget || !uTarget->isType(TYPEMASK_UNIT)) { sLog->outError(LOG_FILTER_TSCR, "%s no target unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->CastSpell.SpellID); break; } bool triggered = (step.script->CastSpell.Flags != 4) ? step.script->CastSpell.CreatureEntry & SF_CASTSPELL_TRIGGERED : step.script->CastSpell.CreatureEntry < 0; uSource->CastSpell(uTarget, step.script->CastSpell.SpellID, triggered); break; } case SCRIPT_COMMAND_PLAY_SOUND: // Source must be WorldObject. if (WorldObject* object = _GetScriptWorldObject(source, true, step.script)) { // PlaySound.Flags bitmask: 0/1=anyone/target Player* player = NULL; if (step.script->PlaySound.Flags & SF_PLAYSOUND_TARGET_PLAYER) { // Target must be Player. player = _GetScriptPlayer(target, false, step.script); if (!target) break; } // PlaySound.Flags bitmask: 0/2=without/with distance dependent if (step.script->PlaySound.Flags & SF_PLAYSOUND_DISTANCE_SOUND) object->PlayDistanceSound(step.script->PlaySound.SoundID, player); else object->PlayDirectSound(step.script->PlaySound.SoundID, player); } break; case SCRIPT_COMMAND_CREATE_ITEM: // Target or source must be Player. if (Player* pReceiver = _GetScriptPlayerSourceOrTarget(source, target, step.script)) { ItemPosCountVec dest; InventoryResult msg = pReceiver->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, step.script->CreateItem.ItemEntry, step.script->CreateItem.Amount); if (msg == EQUIP_ERR_OK) { if (Item* item = pReceiver->StoreNewItem(dest, step.script->CreateItem.ItemEntry, true)) pReceiver->SendNewItem(item, step.script->CreateItem.Amount, false, true); } else pReceiver->SendEquipError(msg, NULL, NULL, step.script->CreateItem.ItemEntry); } break; case SCRIPT_COMMAND_DESPAWN_SELF: // Target or source must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true)) cSource->DespawnOrUnsummon(step.script->DespawnSelf.DespawnDelay); break; case SCRIPT_COMMAND_LOAD_PATH: // Source must be Unit. if (Unit* unit = _GetScriptUnit(source, true, step.script)) { if (!sWaypointMgr->GetPath(step.script->LoadPath.PathID)) sLog->outError(LOG_FILTER_TSCR, "%s source object has an invalid path (%u), skipping.", step.script->GetDebugInfo().c_str(), step.script->LoadPath.PathID); else unit->GetMotionMaster()->MovePath(step.script->LoadPath.PathID, step.script->LoadPath.IsRepeatable); } break; case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT: { if (!step.script->CallScript.CreatureEntry) { sLog->outError(LOG_FILTER_TSCR, "%s creature entry is not specified, skipping.", step.script->GetDebugInfo().c_str()); break; } if (!step.script->CallScript.ScriptID) { sLog->outError(LOG_FILTER_TSCR, "%s script id is not specified, skipping.", step.script->GetDebugInfo().c_str()); break; } Creature* cTarget = NULL; if (source) //using grid searcher { WorldObject* wSource = dynamic_cast <WorldObject*> (source); CellCoord p(MistCore::ComputeCellCoord(wSource->GetPositionX(), wSource->GetPositionY())); Cell cell(p); MistCore::CreatureWithDbGUIDCheck target_check(wSource, step.script->CallScript.CreatureEntry); MistCore::CreatureSearcher<MistCore::CreatureWithDbGUIDCheck> checker(wSource, cTarget, target_check); TypeContainerVisitor<MistCore::CreatureSearcher <MistCore::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker); cell.Visit(p, unit_checker, *wSource->GetMap(), *wSource, wSource->GetGridActivationRange()); } else //check hashmap holders { if (CreatureData const* data = sObjectMgr->GetCreatureData(step.script->CallScript.CreatureEntry)) cTarget = ObjectAccessor::GetObjectInWorld<Creature>(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->CallScript.CreatureEntry, data->id, HIGHGUID_UNIT), cTarget); } if (!cTarget) { sLog->outError(LOG_FILTER_TSCR, "%s target was not found (entry: %u)", step.script->GetDebugInfo().c_str(), step.script->CallScript.CreatureEntry); break; } //Lets choose our ScriptMap map ScriptMapMap* datamap = GetScriptsMapByType(ScriptsType(step.script->CallScript.ScriptType)); //if no scriptmap present... if (!datamap) { sLog->outError(LOG_FILTER_TSCR, "%s unknown scriptmap (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->CallScript.ScriptType); break; } // Insert script into schedule but do not start it ScriptsStart(*datamap, step.script->CallScript.ScriptID, cTarget, NULL); break; } case SCRIPT_COMMAND_KILL: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { if (cSource->isDead()) sLog->outError(LOG_FILTER_TSCR, "%s creature is already dead (Entry: %u, GUID: %u)", step.script->GetDebugInfo().c_str(), cSource->GetEntry(), cSource->GetGUIDLow()); else { cSource->setDeathState(JUST_DIED); if (step.script->Kill.RemoveCorpse == 1) cSource->RemoveCorpse(); } } break; case SCRIPT_COMMAND_ORIENTATION: // Source must be Unit. if (Unit* sourceUnit = _GetScriptUnit(source, true, step.script)) { if (step.script->Orientation.Flags & SF_ORIENTATION_FACE_TARGET) { // Target must be Unit. Unit* targetUnit = _GetScriptUnit(target, false, step.script); if (!targetUnit) break; sourceUnit->SetInFront(targetUnit); } else sourceUnit->SetOrientation(step.script->Orientation.Orientation); sourceUnit->SendMovementFlagUpdate(); } break; case SCRIPT_COMMAND_EQUIP: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) cSource->LoadEquipment(step.script->Equip.EquipmentID); break; case SCRIPT_COMMAND_MODEL: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) cSource->SetDisplayId(step.script->Model.ModelID); break; case SCRIPT_COMMAND_CLOSE_GOSSIP: // Source must be Player. if (Player* player = _GetScriptPlayer(source, true, step.script)) player->PlayerTalkClass->SendCloseGossip(); break; case SCRIPT_COMMAND_PLAYMOVIE: // Source must be Player. if (Player* player = _GetScriptPlayer(source, true, step.script)) player->SendMovieStart(step.script->PlayMovie.MovieID); break; default: sLog->outError(LOG_FILTER_TSCR, "Unknown script command %s.", step.script->GetDebugInfo().c_str()); break; } m_scriptSchedule.erase(iter); iter = m_scriptSchedule.begin(); sScriptMgr->DecreaseScheduledScriptCount(); } }
bool Spell::GenerateTargets(SpellCastTargets* t) { if(u_caster == NULL || u_caster->GetAIInterface() == NULL || !u_caster->IsInWorld()) return false; bool result = false; for(uint32 i = 0; i < 3; ++i) { if(m_spellInfo->Effect[i] == 0) continue; uint32 TargetType = 0; TargetType |= GetTargetType(m_spellInfo->EffectImplicitTargetA[i], i); //never get info from B if it is 0 :P if(m_spellInfo->EffectImplicitTargetB[i] != 0) TargetType |= GetTargetType(m_spellInfo->EffectImplicitTargetB[i], i); if(TargetType & (SPELL_TARGET_OBJECT_SELF | SPELL_TARGET_AREA_PARTY | SPELL_TARGET_AREA_RAID)) { t->m_targetMask |= TARGET_FLAG_UNIT; t->m_unitTarget = u_caster->GetGUID(); result = true; } if(TargetType & SPELL_TARGET_NO_OBJECT) { t->m_targetMask = TARGET_FLAG_SELF; result = true; } if(!(TargetType & (SPELL_TARGET_AREA | SPELL_TARGET_AREA_SELF | SPELL_TARGET_AREA_CURTARGET | SPELL_TARGET_AREA_CONE))) { if(TargetType & SPELL_TARGET_ANY_OBJECT) { if(u_caster->GetUInt64Value(UNIT_FIELD_TARGET)) { //generate targets for things like arcane missiles trigger, tame pet, etc Object* target = u_caster->GetMapMgr()->_GetObject(u_caster->GetUInt64Value(UNIT_FIELD_TARGET)); if(target != NULL) { if(target->IsUnit()) { t->m_targetMask |= TARGET_FLAG_UNIT; t->m_unitTarget = target->GetGUID(); result = true; } else if(target->IsGameObject()) { t->m_targetMask |= TARGET_FLAG_OBJECT; t->m_unitTarget = target->GetGUID(); result = true; } } result = true; } } if(TargetType & SPELL_TARGET_REQUIRE_ATTACKABLE) { if(u_caster->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT)) { //generate targets for things like arcane missiles trigger, tame pet, etc Object* target = u_caster->GetMapMgr()->_GetObject(u_caster->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT)); if(target != NULL) { if(target->IsUnit()) { t->m_targetMask |= TARGET_FLAG_UNIT; t->m_unitTarget = target->GetGUID(); result = true; } else if(target->IsGameObject()) { t->m_targetMask |= TARGET_FLAG_OBJECT; t->m_unitTarget = target->GetGUID(); result = true; } } } else if(u_caster->GetUInt64Value(UNIT_FIELD_TARGET)) { //generate targets for things like arcane missiles trigger, tame pet, etc Object* target = u_caster->GetMapMgr()->_GetObject(u_caster->GetUInt64Value(UNIT_FIELD_TARGET)); if(target != NULL) { if(target->IsUnit()) { t->m_targetMask |= TARGET_FLAG_UNIT; t->m_unitTarget = target->GetGUID(); result = true; } else if(target->IsGameObject()) { t->m_targetMask |= TARGET_FLAG_OBJECT; t->m_unitTarget = target->GetGUID(); result = true; } } result = true; } else if(u_caster->IsCreature() && u_caster->IsTotem()) { Unit* target = u_caster->GetMapMgr()->GetUnit(GetSinglePossibleEnemy(i)); if(target != NULL) { t->m_targetMask |= TARGET_FLAG_UNIT; t->m_unitTarget = target->GetGUID(); } } } if(TargetType & SPELL_TARGET_REQUIRE_FRIENDLY) { Unit* target = u_caster->GetMapMgr()->GetUnit(GetSinglePossibleFriend(i)); if(target != NULL) { t->m_targetMask |= TARGET_FLAG_UNIT; t->m_unitTarget = target->GetGUID(); result = true; } else { t->m_targetMask |= TARGET_FLAG_UNIT; t->m_unitTarget = u_caster->GetGUID(); result = true; } } } if(TargetType & SPELL_TARGET_AREA_RANDOM) { //we always use radius(0) for some reason uint8 attempts = 0; do { //prevent deadlock ++attempts; if(attempts > 10) return false; float r = RandomFloat(GetRadius(0)); float ang = RandomFloat(M_PI_FLOAT * 2); t->m_destX = m_caster->GetPositionX() + (cosf(ang) * r); t->m_destY = m_caster->GetPositionY() + (sinf(ang) * r); t->m_destZ = m_caster->GetMapMgr()->GetLandHeight(t->m_destX, t->m_destY, m_caster->GetPositionZ() + 2.0f); t->m_targetMask = TARGET_FLAG_DEST_LOCATION; } while(sWorld.Collision && !CollideInterface.CheckLOS(m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), t->m_destX, t->m_destY, t->m_destZ)); result = true; } else if(TargetType & SPELL_TARGET_AREA) //targetted aoe { //spells like blizzard, rain of fire if(u_caster->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT)) { Object* target = u_caster->GetMapMgr()->_GetObject(u_caster->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT)); if(target != NULL) { t->m_targetMask |= TARGET_FLAG_DEST_LOCATION | TARGET_FLAG_UNIT; t->m_destX = target->GetPositionX(); t->m_destY = target->GetPositionY(); t->m_destZ = target->GetPositionZ(); } result = true; } else { if(u_caster->GetAIInterface()->getNextTarget() != NULL && TargetType & SPELL_TARGET_REQUIRE_ATTACKABLE) { t->m_targetMask |= TARGET_FLAG_DEST_LOCATION | TARGET_FLAG_UNIT; t->m_destX = u_caster->GetAIInterface()->getNextTarget()->GetPositionX(); t->m_destY = u_caster->GetAIInterface()->getNextTarget()->GetPositionY(); t->m_destZ = u_caster->GetAIInterface()->getNextTarget()->GetPositionZ(); result = true; } else if(TargetType & SPELL_TARGET_REQUIRE_FRIENDLY) { t->m_targetMask |= TARGET_FLAG_DEST_LOCATION | TARGET_FLAG_UNIT; t->m_destX = u_caster->GetPositionX(); t->m_destY = u_caster->GetPositionY(); t->m_destZ = u_caster->GetPositionZ(); result = true; } } } else if(TargetType & SPELL_TARGET_AREA_SELF) { t->m_targetMask |= TARGET_FLAG_SOURCE_LOCATION | TARGET_FLAG_UNIT; t->m_unitTarget = u_caster->GetGUID(); t->m_srcX = u_caster->GetPositionX(); t->m_srcY = u_caster->GetPositionY(); t->m_srcZ = u_caster->GetPositionZ(); t->m_destX = u_caster->GetPositionX(); t->m_destY = u_caster->GetPositionY(); t->m_destZ = u_caster->GetPositionZ(); result = true; } if(TargetType & SPELL_TARGET_AREA_CHAIN) { if(TargetType & SPELL_TARGET_REQUIRE_ATTACKABLE) { if(u_caster->GetAIInterface()->getNextTarget() != NULL) { t->m_targetMask |= TARGET_FLAG_UNIT; t->m_unitTarget = u_caster->GetAIInterface()->getNextTarget()->GetGUID(); result = true; } } else { t->m_targetMask |= TARGET_FLAG_UNIT; t->m_unitTarget = u_caster->GetGUID(); result = true; } } //target cone if(TargetType & SPELL_TARGET_AREA_CONE) { if(u_caster->GetAIInterface()->getNextTarget() != NULL) { t->m_targetMask |= TARGET_FLAG_DEST_LOCATION; t->m_destX = u_caster->GetAIInterface()->getNextTarget()->GetPositionX(); t->m_destY = u_caster->GetAIInterface()->getNextTarget()->GetPositionY(); t->m_destZ = u_caster->GetAIInterface()->getNextTarget()->GetPositionZ(); result = true; } } } return result; }
bool ChatHandler::HandleGPSCommand(const char* args) { Object *obj = getSelectedUnit(); if(!obj) { SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); return true; } CellPair cell_val = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); Cell cell = RedZone::GetZone(cell_val); PSendSysMultilineMessage(LANG_MAP_POSITION, obj->GetMapId(), obj->GetZoneId(), obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(),cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY()); sLog.outDebug("Player %s GPS call unit " I64FMT " " LANG_MAP_POSITION, m_session->GetPlayer()->GetName(), obj->GetGUID(), obj->GetMapId(), obj->GetZoneId(), obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY()); return true; }
void Group::RemovePlayer(PlayerInfo* info) { WorldPacket data(50); Player* pPlayer = info->m_loggedInPlayer; m_groupLock.Acquire(); if(m_isqueued) { m_isqueued = false; BattlegroundManager.RemoveGroupFromQueues(this); } SubGroup* sg = NULL; if(info->subGroup >= 0 && info->subGroup <= 8) sg = m_SubGroups[info->subGroup]; if(sg == NULL || sg->m_GroupMembers.find(info) == sg->m_GroupMembers.end()) { for(uint8 i = 0; i < m_SubGroupCount; ++i) { if(m_SubGroups[i] != NULL) { if(m_SubGroups[i]->m_GroupMembers.find(info) != m_SubGroups[i]->m_GroupMembers.end()) { sg = m_SubGroups[i]; break; } } } } info->m_Group = NULL; info->subGroup = -1; if(sg == NULL) { m_groupLock.Release(); return; } m_dirty = true; sg->RemovePlayer(info); --m_MemberCount; // remove team member from the instance if(info->m_loggedInPlayer != NULL) { sInstanceMgr.PlayerLeftGroup(this, info->m_loggedInPlayer); } if(pPlayer != NULL) { if(pPlayer->GetSession() != NULL) { SendNullUpdate(pPlayer); data.SetOpcode(SMSG_GROUP_DESTROYED); pPlayer->GetSession()->SendPacket(&data); data.Initialize(SMSG_PARTY_COMMAND_RESULT); data << uint32(2) << uint8(0) << uint32(0); // you leave the group pPlayer->GetSession()->SendPacket(&data); } //Remove some party auras. for(uint32 i = MAX_POSITIVE_AURAS_EXTEDED_START; i < MAX_POSITIVE_AURAS_EXTEDED_END; i++) { if(pPlayer->m_auras[i] && pPlayer->m_auras[i]->m_areaAura) { Object* caster = pPlayer->m_auras[ i ]->GetCaster(); if((caster != NULL) && (pPlayer->GetGUID() != caster->GetGUID())) pPlayer->m_auras[i]->Remove(); } } } if(m_MemberCount < 2) { if(m_disbandOnNoMembers) { m_groupLock.Release(); Disband(); return; } } /* eek! ;P */ Player* newPlayer = NULL; if(m_Looter == info) { newPlayer = FindFirstPlayer(); if(newPlayer != NULL) m_Looter = newPlayer->getPlayerInfo(); else m_Looter = NULL; } if(m_Leader == info) { if(newPlayer == NULL) newPlayer = FindFirstPlayer(); if(newPlayer != NULL) SetLeader(newPlayer, false); else m_Leader = NULL; } Update(); m_groupLock.Release(); }
void MapMgr::_UpdateObjects() { if(!_updates.size() && !_processQueue.size()) return; Object* pObj; Player* pOwner; std::set< Object* >::iterator it_start, it_end, itr; Player* lplr; ByteBuffer update(2500); uint32 count = 0; m_updateMutex.Acquire(); UpdateQueue::iterator iter = _updates.begin(); PUpdateQueue::iterator it, eit; for(; iter != _updates.end();) { pObj = *iter; ++iter; if(!pObj) continue; if(pObj->IsItem() || pObj->IsContainer()) { // our update is only sent to the owner here. pOwner = TO< Item* >(pObj)->GetOwner(); if(pOwner != NULL) { count = TO< Item* >(pObj)->BuildValuesUpdateBlockForPlayer(&update, pOwner); // send update to owner if(count) { pOwner->PushUpdateData(&update, count); update.clear(); } } } else { if(pObj->IsInWorld()) { // players have to receive their own updates ;) if(pObj->IsPlayer()) { // need to be different! ;) count = pObj->BuildValuesUpdateBlockForPlayer(&update, TO< Player* >(pObj)); if(count) { TO< Player* >(pObj)->PushUpdateData(&update, count); update.clear(); } } if(pObj->IsUnit() && pObj->HasUpdateField(UNIT_FIELD_HEALTH)) TO< Unit* >(pObj)->EventHealthChangeSinceLastUpdate(); // build the update count = pObj->BuildValuesUpdateBlockForPlayer(&update, static_cast< Player* >(NULL)); if(count) { it_start = pObj->GetInRangePlayerSetBegin(); it_end = pObj->GetInRangePlayerSetEnd(); for(itr = it_start; itr != it_end;) { lplr = TO< Player* >(*itr); ++itr; // Make sure that the target player can see us. if(lplr->IsVisible(pObj->GetGUID())) lplr->PushUpdateData(&update, count); } update.clear(); } } } pObj->ClearUpdateMask(); } _updates.clear(); m_updateMutex.Release(); // generate pending a9packets and send to clients. Player* plyr; for(it = _processQueue.begin(); it != _processQueue.end();) { plyr = *it; eit = it; ++it; _processQueue.erase(eit); if(plyr->GetMapMgr() == this) plyr->ProcessPendingUpdates(); } }
void MapMgr::UpdateInRangeSet(Object* obj, Player* plObj, MapCell* cell, ByteBuffer** buf) { #define CHECK_BUF if(!*buf) *buf = new ByteBuffer(2500) if(cell == NULL) return; Object* curObj; Player* plObj2; int count; float fRange; bool cansee, isvisible; ObjectSet::iterator iter = cell->Begin(); while(iter != cell->End()) { curObj = *iter; ++iter; if(curObj == NULL) continue; if(curObj->IsPlayer() && obj->IsPlayer() && plObj != NULL && plObj->transporter_info.guid && plObj->transporter_info.guid == TO< Player* >(curObj)->transporter_info.guid) fRange = 0.0f; // unlimited distance for people on same boat else if(curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER) fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.) //If the object announcing its position is a transport, or other special object, then deleting it from visible objects should be avoided. - By: VLack else if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId()) fRange = 0.0f; //If the object we're checking for possible removal is a transport or other special object, and we are players on the same map, don't remove it, and add it whenever possible... else if(plObj && curObj->IsGameObject() && (TO< GameObject* >(curObj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId()) fRange = 0.0f; else fRange = m_UpdateDistance; // normal distance if(curObj != obj && (curObj->GetDistance2dSq(obj) <= fRange || fRange == 0.0f)) { if(!obj->IsInRangeSet(curObj)) { // Object in range, add to set obj->AddInRangeObject(curObj); curObj->AddInRangeObject(obj); if(curObj->IsPlayer()) { plObj2 = TO< Player* >(curObj); if(plObj2->CanSee(obj) && !plObj2->IsVisible(obj->GetGUID())) { CHECK_BUF; count = obj->BuildCreateUpdateBlockForPlayer(*buf, plObj2); plObj2->PushCreationData(*buf, count); plObj2->AddVisibleObject(obj->GetGUID()); (*buf)->clear(); } } if(plObj != NULL) { if(plObj->CanSee(curObj) && !plObj->IsVisible(curObj->GetGUID())) { CHECK_BUF; count = curObj->BuildCreateUpdateBlockForPlayer(*buf, plObj); plObj->PushCreationData(*buf, count); plObj->AddVisibleObject(curObj->GetGUID()); (*buf)->clear(); } } } else { // Check visibility if(curObj->IsPlayer()) { plObj2 = TO< Player* >(curObj); cansee = plObj2->CanSee(obj); isvisible = plObj2->IsVisible(obj->GetGUID()); if(!cansee && isvisible) { plObj2->PushOutOfRange(obj->GetNewGUID()); plObj2->RemoveVisibleObject(obj->GetGUID()); } else if(cansee && !isvisible) { CHECK_BUF; count = obj->BuildCreateUpdateBlockForPlayer(*buf, plObj2); plObj2->PushCreationData(*buf, count); plObj2->AddVisibleObject(obj->GetGUID()); (*buf)->clear(); } } if(plObj != NULL) { cansee = plObj->CanSee(curObj); isvisible = plObj->IsVisible(curObj->GetGUID()); if(!cansee && isvisible) { plObj->PushOutOfRange(curObj->GetNewGUID()); plObj->RemoveVisibleObject(curObj->GetGUID()); } else if(cansee && !isvisible) { CHECK_BUF; count = curObj->BuildCreateUpdateBlockForPlayer(*buf, plObj); plObj->PushCreationData(*buf, count); plObj->AddVisibleObject(curObj->GetGUID()); (*buf)->clear(); } } } } } }
void MapMgr::ChangeObjectLocation(Object* obj) { /* if ( !obj ) return; // crashfix */ ARCEMU_ASSERT(obj != NULL); // Items and containers are of no interest for us if(obj->IsItem() || obj->IsContainer() || obj->GetMapMgr() != this) { return; } Player* plObj = NULL; ByteBuffer* buf = 0; if(obj->IsPlayer()) { plObj = TO< Player* >(obj); } Object* curObj; float fRange = 0.0f; /////////////////////////////////////// // Update in-range data for old objects /////////////////////////////////////// if(obj->HasInRangeObjects()) { for(Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(); iter != obj->GetInRangeSetEnd();) { curObj = *iter; ++iter; if(curObj->IsPlayer() && plObj != NULL && plObj->transporter_info.guid && plObj->transporter_info.guid == TO< Player* >(curObj)->transporter_info.guid) fRange = 0.0f; // unlimited distance for people on same boat else if(curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER) fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.) //If the object announcing its position is a transport, or other special object, then deleting it from visible objects should be avoided. - By: VLack else if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId()) fRange = 0.0f; //If the object we're checking for possible removal is a transport or other special object, and we are players on the same map, don't remove it... else if(plObj && curObj->IsGameObject() && (TO< GameObject* >(curObj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId()) fRange = 0.0f; else if(curObj->IsPlayer() && TO< Player* >(curObj)->GetFarsightTarget() == obj->GetGUID()) fRange = 0.0f;//Mind Vision, Eye of Kilrogg else fRange = m_UpdateDistance; // normal distance if(fRange > 0.0f && (curObj->GetDistance2dSq(obj) > fRange)) { if(plObj != NULL) plObj->RemoveIfVisible(curObj->GetGUID()); if(curObj->IsPlayer()) TO< Player* >(curObj)->RemoveIfVisible(obj->GetGUID()); curObj->RemoveInRangeObject(obj); if(obj->GetMapMgr() != this) { /* Something removed us. */ return; } obj->RemoveInRangeObject(curObj); } } } /////////////////////////// // Get new cell coordinates /////////////////////////// if(obj->GetMapMgr() != this) { /* Something removed us. */ return; } if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minX || obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY) { if(plObj != NULL) { if(plObj->GetBindMapId() != GetMapId()) { plObj->SafeTeleport(plObj->GetBindMapId(), 0, plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0); plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); return; } else { obj->GetPositionV()->ChangeCoords(plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0); plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); plObj->SendTeleportAckMsg(plObj->GetPosition()); } } else { obj->GetPositionV()->ChangeCoords(0, 0, 0, 0); } } uint32 cellX = GetPosX(obj->GetPositionX()); uint32 cellY = GetPosY(obj->GetPositionY()); if(cellX >= _sizeX || cellY >= _sizeY) { return; } MapCell* objCell = GetCell(cellX, cellY); MapCell* pOldCell = obj->GetMapCell(); if(objCell == NULL) { objCell = Create(cellX, cellY); objCell->Init(cellX, cellY, this); } ARCEMU_ASSERT(objCell != NULL); // If object moved cell if(objCell != pOldCell) { // THIS IS A HACK! // Current code, if a creature on a long waypoint path moves from an active // cell into an inactive one, it will disable itself and will never return. // This is to prevent cpu leaks. I will think of a better solution very soon :P if(!objCell->IsActive() && !plObj && obj->IsActive()) obj->Deactivate(this); if(pOldCell != NULL) pOldCell->RemoveObject(obj); objCell->AddObject(obj); obj->SetMapCell(objCell); // if player we need to update cell activity // radius = 2 is used in order to update both // old and new cells if(obj->IsPlayer()) { // have to unlock/lock here to avoid a deadlock situation. UpdateCellActivity(cellX, cellY, 2); if(pOldCell != NULL) { // only do the second check if there's -/+ 2 difference if(abs((int)cellX - (int)pOldCell->_x) > 2 || abs((int)cellY - (int)pOldCell->_y) > 2) { UpdateCellActivity(pOldCell->_x, pOldCell->_y, 2); } } } } ////////////////////////////////////// // Update in-range set for new objects ////////////////////////////////////// uint32 endX = cellX <= _sizeX ? cellX + 1 : (_sizeX - 1); uint32 endY = cellY <= _sizeY ? cellY + 1 : (_sizeY - 1); uint32 startX = cellX > 0 ? cellX - 1 : 0; uint32 startY = cellY > 0 ? cellY - 1 : 0; uint32 posX, posY; MapCell* cell; //If the object announcing it's position is a special one, then it should do so in a much wider area - like the distance between the two transport towers in Orgrimmar, or more. - By: VLack if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_ONMOVEWIDE)) { endX = cellX + 5 <= _sizeX ? cellX + 6 : (_sizeX - 1); endY = cellY + 5 <= _sizeY ? cellY + 6 : (_sizeY - 1); startX = cellX > 5 ? cellX - 6 : 0; startY = cellY > 5 ? cellY - 6 : 0; } for(posX = startX; posX <= endX; ++posX) { for(posY = startY; posY <= endY; ++posY) { cell = GetCell(posX, posY); if(cell) UpdateInRangeSet(obj, plObj, cell, &buf); } } if(buf) delete buf; }