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; }
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; }
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(); }