bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type) { SetMap(caster->GetMap()); Relocate(pos); if (!IsPositionValid()) { TC_LOG_ERROR("misc", "DynamicObject (spell %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", spellId, GetPositionX(), GetPositionY()); return false; } WorldObject::_Create(guidlow, HighGuid::DynamicObject, caster->GetPhaseMask()); SetEntry(spellId); SetObjectScale(1); SetGuidValue(DYNAMICOBJECT_CASTER, caster->GetGUID()); // The lower word of DYNAMICOBJECT_BYTES must be 0x0001. This value means that the visual radius will be overriden // by client for most of the "ground patch" visual effect spells and a few "skyfall" ones like Hurricane. // If any other value is used, the client will _always_ use the radius provided in DYNAMICOBJECT_RADIUS, but // precompensation is necessary (eg radius *= 2) for many spells. Anyway, blizz sends 0x0001 for all the spells // I saw sniffed... SetByteValue(DYNAMICOBJECT_BYTES, 0, type); SetUInt32Value(DYNAMICOBJECT_SPELLID, spellId); SetFloatValue(DYNAMICOBJECT_RADIUS, radius); SetUInt32Value(DYNAMICOBJECT_CASTTIME, GameTime::GetGameTimeMS()); if (IsWorldObject()) setActive(true); //must before add to map to be put in world container Transport* transport = caster->GetTransport(); if (transport) { float x, y, z, o; pos.GetPosition(x, y, z, o); transport->CalculatePassengerOffset(x, y, z, &o); m_movementInfo.transport.pos.Relocate(x, y, z, o); // This object must be added to transport before adding to map for the client to properly display it transport->AddPassenger(this); } if (!GetMap()->AddToMap(this)) { // Returning false will cause the object to be deleted - remove from transport if (transport) transport->RemovePassenger(this); return false; } return true; }
bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caster, SpellInfo const* spell, Position const& pos, float radius, DynamicObjectType type, uint32 spellXSpellVisualId) { _spellXSpellVisualId = spellXSpellVisualId; SetMap(caster->GetMap()); Relocate(pos); if (!IsPositionValid()) { TC_LOG_ERROR("misc", "DynamicObject (spell %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", spell->Id, GetPositionX(), GetPositionY()); return false; } WorldObject::_Create(ObjectGuid::Create<HighGuid::DynamicObject>(GetMapId(), spell->Id, guidlow)); SetPhaseMask(caster->GetPhaseMask(), false); SetEntry(spell->Id); SetObjectScale(1.0f); SetGuidValue(DYNAMICOBJECT_CASTER, caster->GetGUID()); SetUInt32Value(DYNAMICOBJECT_TYPE, type); SetUInt32Value(DYNAMICOBJECT_SPELL_X_SPELL_VISUAL_ID, spellXSpellVisualId); SetUInt32Value(DYNAMICOBJECT_SPELLID, spell->Id); SetFloatValue(DYNAMICOBJECT_RADIUS, radius); SetUInt32Value(DYNAMICOBJECT_CASTTIME, getMSTime()); if (IsWorldObject()) setActive(true); //must before add to map to be put in world container Transport* transport = caster->GetTransport(); if (transport) { float x, y, z, o; pos.GetPosition(x, y, z, o); transport->CalculatePassengerOffset(x, y, z, &o); m_movementInfo.transport.pos.Relocate(x, y, z, o); // This object must be added to transport before adding to map for the client to properly display it transport->AddPassenger(this); } if (!GetMap()->AddToMap(this)) { // Returning false will cause the object to be deleted - remove from transport if (transport) transport->RemovePassenger(this); return false; } return true; }
void WorldSession::HandleMoverRelocation(MovementInfo& movementInfo) { movementInfo.UpdateTime(getMSTime()); Unit *mover = _player->GetMover(); if (Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL) { if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT)) { if (!plMover->GetTransport()) { float trans_rad = movementInfo.GetTransportPos()->x*movementInfo.GetTransportPos()->x + movementInfo.GetTransportPos()->y*movementInfo.GetTransportPos()->y + movementInfo.GetTransportPos()->z*movementInfo.GetTransportPos()->z; if (trans_rad > 3600.0f) // transport radius = 60 yards //cheater with on_transport_flag { return; } // elevators also cause the client to send MOVEFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr.m_Transports.begin(); iter != sMapMgr.m_Transports.end(); ++iter) { Transport* transport = *iter; if (transport->GetObjectGuid() == movementInfo.GetTransportGuid()) { plMover->SetTransport(transport); transport->AddPassenger(plMover); if (plMover->GetVehicleKit()) plMover->GetVehicleKit()->RemoveAllPassengers(); break; } } } } else if (plMover->GetTransport()) // if we were on a transport, leave { plMover->GetTransport()->RemovePassenger(plMover); plMover->SetTransport(NULL); movementInfo.ClearTransportData(); } if (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING) != plMover->IsInWater()) { // now client not include swimming flag in case jumping under water plMover->SetInWater( !plMover->IsInWater() || plMover->GetTerrain()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z) ); } if(plMover->GetTerrain()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z-7.0f)) { plMover->m_anti_BeginFallZ=INVALID_HEIGHT; } plMover->SetPosition(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); plMover->m_movementInfo = movementInfo; if(movementInfo.GetPos()->z < -500.0f) { if(plMover->InBattleGround() && plMover->GetBattleGround() && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) { // do nothing, the handle already did if returned true } else { // NOTE: this is actually called many times while falling // even after the player has been teleported away // TODO: discard movement packets after the player is rooted if(plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, plMover->GetMaxHealth()); // pl can be alive if GM/etc if(!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } } }
bool AreaTrigger::Create(uint32 spellMiscId, Unit* caster, Unit* target, SpellInfo const* spell, Position const& pos, int32 duration, uint32 spellXSpellVisualId, ObjectGuid const& castId, AuraEffect const* aurEff) { _targetGuid = target ? target->GetGUID() : ObjectGuid::Empty; _aurEff = aurEff; SetMap(caster->GetMap()); Relocate(pos); if (!IsPositionValid()) { TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (spellMiscId %u) not created. Invalid coordinates (X: %f Y: %f)", spellMiscId, GetPositionX(), GetPositionY()); return false; } _areaTriggerMiscTemplate = sAreaTriggerDataStore->GetAreaTriggerMiscTemplate(spellMiscId); if (!_areaTriggerMiscTemplate) { TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (spellMiscId %u) not created. Invalid areatrigger miscid (%u)", spellMiscId, spellMiscId); return false; } Object::_Create(ObjectGuid::Create<HighGuid::AreaTrigger>(GetMapId(), GetTemplate()->Id, caster->GetMap()->GenerateLowGuid<HighGuid::AreaTrigger>())); SetEntry(GetTemplate()->Id); SetDuration(duration); SetObjectScale(1.0f); SetGuidValue(AREATRIGGER_CASTER, caster->GetGUID()); SetGuidValue(AREATRIGGER_CREATING_EFFECT_GUID, castId); SetUInt32Value(AREATRIGGER_SPELLID, spell->Id); SetUInt32Value(AREATRIGGER_SPELL_FOR_VISUALS, spell->Id); SetUInt32Value(AREATRIGGER_SPELL_X_SPELL_VISUAL_ID, spellXSpellVisualId); SetUInt32Value(AREATRIGGER_TIME_TO_TARGET_SCALE, GetMiscTemplate()->TimeToTargetScale != 0 ? GetMiscTemplate()->TimeToTargetScale : GetUInt32Value(AREATRIGGER_DURATION)); SetFloatValue(AREATRIGGER_BOUNDS_RADIUS_2D, GetTemplate()->MaxSearchRadius); SetUInt32Value(AREATRIGGER_DECAL_PROPERTIES_ID, GetMiscTemplate()->DecalPropertiesId); for (uint8 scaleCurveIndex = 0; scaleCurveIndex < MAX_AREATRIGGER_SCALE; ++scaleCurveIndex) if (GetMiscTemplate()->ExtraScale.Data.Raw[scaleCurveIndex]) SetUInt32Value(AREATRIGGER_EXTRA_SCALE_CURVE + scaleCurveIndex, GetMiscTemplate()->ExtraScale.Data.Raw[scaleCurveIndex]); PhasingHandler::InheritPhaseShift(this, caster); if (target && GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_ATTACHED)) { m_movementInfo.transport.guid = target->GetGUID(); } UpdateShape(); uint32 timeToTarget = GetMiscTemplate()->TimeToTarget != 0 ? GetMiscTemplate()->TimeToTarget : GetUInt32Value(AREATRIGGER_DURATION); if (GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_CIRCULAR_MOVEMENT)) { AreaTriggerCircularMovementInfo cmi = GetMiscTemplate()->CircularMovementInfo; if (target && GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_ATTACHED)) cmi.PathTarget = target->GetGUID(); else cmi.Center = pos; InitCircularMovement(cmi, timeToTarget); } else if (GetMiscTemplate()->HasSplines()) { InitSplineOffsets(GetMiscTemplate()->SplinePoints, timeToTarget); } // movement on transport of areatriggers on unit is handled by themself Transport* transport = m_movementInfo.transport.guid.IsEmpty() ? caster->GetTransport() : nullptr; if (transport) { float x, y, z, o; pos.GetPosition(x, y, z, o); transport->CalculatePassengerOffset(x, y, z, &o); m_movementInfo.transport.pos.Relocate(x, y, z, o); // This object must be added to transport before adding to map for the client to properly display it transport->AddPassenger(this); } AI_Initialize(); // Relocate areatriggers with circular movement again if (HasCircularMovement()) Relocate(CalculateCircularMovementPosition()); if (!GetMap()->AddToMap(this)) { // Returning false will cause the object to be deleted - remove from transport if (transport) transport->RemovePassenger(this); return false; } caster->_RegisterAreaTrigger(this); _ai->OnCreate(); return true; }
//teleport to creature static bool HandleGoCreatureCommand(ChatHandler* handler, char const* args) { if (!*args) return false; Player* player = handler->GetSession()->GetPlayer(); // "id" or number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r char* param1 = handler->extractKeyFromLink((char*)args, "Hcreature"); if (!param1) return false; std::ostringstream whereClause; // User wants to teleport to the NPC's template entry if (strcmp(param1, "id") == 0) { // Get the "creature_template.entry" // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r char* tail = strtok(NULL, ""); if (!tail) return false; char* id = handler->extractKeyFromLink(tail, "Hcreature_entry"); if (!id) return false; int32 entry = atoi(id); if (!entry) return false; whereClause << "WHERE id = '" << entry << '\''; } else { int32 guid = atoi(param1); // Number is invalid - maybe the user specified the mob's name if (!guid) { std::string name = param1; WorldDatabase.EscapeString(name); whereClause << ", creature_template WHERE creature.id = creature_template.entry AND creature_template.name " _LIKE_" '" << name << '\''; } else whereClause << "WHERE guid = '" << guid << '\''; } QueryResult result = WorldDatabase.PQuery("SELECT position_x, position_y, position_z, orientation, map, guid, id FROM creature %s", whereClause.str().c_str()); if (!result) { handler->SendSysMessage(LANG_COMMAND_GOCREATNOTFOUND); handler->SetSentErrorMessage(true); return false; } if (result->GetRowCount() > 1) handler->SendSysMessage(LANG_COMMAND_GOCREATMULTIPLE); Field* fields = result->Fetch(); float x = fields[0].GetFloat(); float y = fields[1].GetFloat(); float z = fields[2].GetFloat(); float o = fields[3].GetFloat(); uint32 mapId = fields[4].GetUInt16(); uint32 guid = fields[5].GetUInt32(); uint32 id = fields[6].GetUInt32(); Transport* transport = NULL; if (Creature* creature = ObjectAccessor::GetObjectInWorld(ObjectGuid(HIGHGUID_UNIT, id, guid), (Creature*)NULL)) { x = creature->GetPositionX(); y = creature->GetPositionY(); z = creature->GetPositionZ(); o = creature->GetOrientation(); mapId = creature->GetMapId(); transport = creature->GetTransport(); } if (!MapManager::IsValidMapCoord(mapId, x, y, z, o) || sObjectMgr->IsTransportMap(mapId)) { handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapId); handler->SetSentErrorMessage(true); return false; } // stop flight if need if (player->IsInFlight()) { player->GetMotionMaster()->MovementExpired(); player->CleanupAfterTaxiFlight(); } // save only in non-flight case else player->SaveRecallPosition(); if (player->TeleportTo(mapId, x, y, z, o)) { if (transport) transport->AddPassenger(player); } return true; }
int32 MoveSplineInit::Launch() { float realSpeedRun = 0.0f; MoveSpline& move_spline = *unit.movespline; Transport* newTransport = NULL; if (args.transportGuid) newTransport = HashMapHolder<Transport>::Find(ObjectGuid(HIGHGUID_MO_TRANSPORT, args.transportGuid)); Vector3 real_position(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZ()); // there is a big chance that current position is unknown if current state is not finalized, need compute it // this also allows calculate spline position and update map position in much greater intervals if (!move_spline.Finalized()) { real_position = move_spline.ComputePosition(); Transport* oldTransport = NULL; if (move_spline.GetTransportGuid()) oldTransport = HashMapHolder<Transport>::Find(ObjectGuid(HIGHGUID_MO_TRANSPORT, move_spline.GetTransportGuid())); if (oldTransport) oldTransport->CalculatePassengerPosition(real_position.x, real_position.y, real_position.z); } if (newTransport) newTransport->CalculatePassengerOffset(real_position.x, real_position.y, real_position.z); if (args.path.empty()) { // should i do the things that user should do? MoveTo(real_position); } // corrent first vertex args.path[0] = real_position; uint32 moveFlags = unit.m_movementInfo.GetMovementFlags(); uint32 oldMoveFlags = moveFlags; if (args.flags.done) { args.flags = MoveSplineFlag::Done; moveFlags &= ~(MOVEFLAG_SPLINE_ENABLED | MOVEFLAG_MASK_MOVING); } else { moveFlags |= (MOVEFLAG_SPLINE_ENABLED | MOVEFLAG_FORWARD); if (args.flags.runmode) moveFlags &= ~MOVEFLAG_WALK_MODE; else moveFlags |= MOVEFLAG_WALK_MODE; } if (newTransport) moveFlags |= MOVEFLAG_ONTRANSPORT; else moveFlags &= ~MOVEFLAG_ONTRANSPORT; if (args.velocity == 0.f) realSpeedRun = args.velocity = unit.GetSpeed(SelectSpeedType(moveFlags)); else realSpeedRun = unit.GetSpeed(MOVE_RUN); if (!args.Validate(&unit)) return 0; unit.m_movementInfo.SetMovementFlags((MovementFlags)moveFlags); unit.clearUnitState(UNIT_STAT_CLIENT_ROOT); move_spline.SetMovementOrigin(movementType); move_spline.Initialize(args); WorldPacket data(SMSG_MONSTER_MOVE, 64); data << unit.GetPackGUID(); if (newTransport) { data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT); data << newTransport->GetPackGUID(); } if (unit.GetTransport() && unit.GetTransport() != newTransport) unit.GetTransport()->RemovePassenger(&unit); if (newTransport && unit.GetTransport() != newTransport) newTransport->AddPassenger(&unit); // Stop packet if (args.flags.done) { data << real_position.x << real_position.y << real_position.z; data << move_spline.GetId(); data << uint8(1); // MonsterMoveStop=1 } else move_spline.setLastPointSent(PacketBuilder::WriteMonsterMove(move_spline, data)); // Compress data or not ? bool compress = false; if (!args.flags.done && args.velocity > 4 * realSpeedRun) compress = true; else if ((data.wpos() + 2) > 0x10) compress = true; else if (unit.hasUnitState(UNIT_STAT_CLIENT_ROOT)) compress = true; // Since packet size is stored with an uint8, packet size is limited for compressed packets if ((data.wpos() + 2) > 0xFF) compress = false; MovementData mvtData(compress ? NULL : &unit); // Nostalrius: client has a hardcoded limit to spline movement speed : 4*runSpeed. // We need to fix this, in case of charges for example (if character has movement slowing effects) if (args.velocity > 4 * realSpeedRun && !args.flags.done) // From client mvtData.SetUnitSpeed(SMSG_SPLINE_SET_RUN_SPEED, unit.GetObjectGuid(), args.velocity); if (unit.hasUnitState(UNIT_STAT_CLIENT_ROOT)) mvtData.SetSplineOpcode(SMSG_SPLINE_MOVE_UNROOT, unit.GetObjectGuid()); if (oldMoveFlags & MOVEFLAG_WALK_MODE && !(moveFlags & MOVEFLAG_WALK_MODE)) // Switch to run mode mvtData.SetSplineOpcode(SMSG_SPLINE_MOVE_SET_RUN_MODE, unit.GetObjectGuid()); if (moveFlags & MOVEFLAG_WALK_MODE && !(oldMoveFlags & MOVEFLAG_WALK_MODE)) // Switch to walk mode mvtData.SetSplineOpcode(SMSG_SPLINE_MOVE_SET_WALK_MODE, unit.GetObjectGuid()); mvtData.AddPacket(data); // Do not forget to restore velocity after movement ! if (args.velocity > 4 * realSpeedRun && !args.flags.done) mvtData.SetUnitSpeed(SMSG_SPLINE_SET_RUN_SPEED, unit.GetObjectGuid(), realSpeedRun); // Restore correct walk mode for players if (unit.GetTypeId() == TYPEID_PLAYER && (moveFlags & MOVEFLAG_WALK_MODE) != (oldMoveFlags & MOVEFLAG_WALK_MODE)) mvtData.SetSplineOpcode(oldMoveFlags & MOVEFLAG_WALK_MODE ? SMSG_SPLINE_MOVE_SET_WALK_MODE : SMSG_SPLINE_MOVE_SET_RUN_MODE, unit.GetObjectGuid()); if (compress) { WorldPacket data2; mvtData.BuildPacket(data2); unit.SendMovementMessageToSet(std::move(data2), true); } return move_spline.Duration(); }