/* * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version. * Copyright (C) 2008-2016 TrinityCore * Copyright (C) 2005-2009 MaNGOS */ #include "MovementPacketBuilder.h" #include "MoveSpline.h" #include "MoveSplineInit.h" #include "Opcodes.h" #include "Transport.h" #include "Unit.h" #include "Vehicle.h" #include "WorldPacket.h" namespace Movement { UnitMoveType SelectSpeedType(uint32 moveFlags) { if (moveFlags & MOVEMENTFLAG_FLYING) { if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.flight >= speed_obj.flight_back*/) return MOVE_FLIGHT_BACK; else return MOVE_FLIGHT; } else if (moveFlags & MOVEMENTFLAG_SWIMMING) { if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.swim >= speed_obj.swim_back*/) return MOVE_SWIM_BACK; else return MOVE_SWIM; } else if (moveFlags & MOVEMENTFLAG_WALKING) { //if (speed_obj.run > speed_obj.walk) return MOVE_WALK; } else if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.run >= speed_obj.run_back*/) return MOVE_RUN_BACK; // Flying creatures use MOVEMENTFLAG_CAN_FLY or MOVEMENTFLAG_DISABLE_GRAVITY // Run speed is their default flight speed. return MOVE_RUN; } int32 MoveSplineInit::Launch() { MoveSpline& move_spline = *unit->movespline; bool transport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID(); Location real_position; // there is a big chance that current position is unknown if current state is not finalized, need compute it // this also allows CalculatePath spline position and update map position in much greater intervals // Don't compute for transport movement if the unit is in a motion between two transports if (!move_spline.Finalized() && move_spline.onTransport == transport) real_position = move_spline.ComputePosition(); else { Position const* pos; if (!transport) pos = unit; else pos = &unit->m_movementInfo.transport.pos; real_position.x = pos->GetPositionX(); real_position.y = pos->GetPositionY(); real_position.z = pos->GetPositionZ(); real_position.orientation = unit->GetOrientation(); } // should i do the things that user should do? - no. if (args.path.empty()) return 0; // corrent first vertex args.path[0] = real_position; args.initialOrientation = real_position.orientation; move_spline.onTransport = transport; uint32 moveFlags = unit->m_movementInfo.GetMovementFlags(); moveFlags |= MOVEMENTFLAG_SPLINE_ENABLED; if (!args.flags.orientationInversed) { moveFlags = (moveFlags & ~(MOVEMENTFLAG_BACKWARD)) | MOVEMENTFLAG_FORWARD; } else { moveFlags = (moveFlags & ~(MOVEMENTFLAG_FORWARD)) | MOVEMENTFLAG_BACKWARD; } if (moveFlags & MOVEMENTFLAG_ROOT) moveFlags &= ~MOVEMENTFLAG_MASK_MOVING; if (!args.HasVelocity) { // If spline is initialized with SetWalk method it only means we need to select // walk move speed for it but not add walk flag to unit uint32 moveFlagsForSpeed = moveFlags; if (args.flags.walkmode) moveFlagsForSpeed |= MOVEMENTFLAG_WALKING; else moveFlagsForSpeed &= ~MOVEMENTFLAG_WALKING; args.velocity = unit->GetSpeed(SelectSpeedType(moveFlagsForSpeed)); if (Creature* creature = unit->ToCreature()) if (creature->HasSearchedAssistance()) args.velocity *= 0.66f; } // limit the speed in the same way the client does args.velocity = std::min(args.velocity, args.flags.catmullrom || args.flags.flying ? 50.0f : std::max(28.0f, unit->GetSpeed(MOVE_RUN) * 4.0f)); if (!args.Validate(unit)) return 0; unit->m_movementInfo.SetMovementFlags(moveFlags); move_spline.Initialize(args); WorldPacket data(SMSG_MONSTER_MOVE, 64); data.append(unit->GetPackGUID()); if (transport) { data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT); data.appendPackGUID(unit->GetTransGUID()); data << int8(unit->GetTransSeat()); } Movement::SplineBase::ControlArray* visualPoints = const_cast(move_spline._Spline().allocateVisualPoints()); visualPoints->resize(move_spline._Spline().getPointCount()); // Xinef: Apply hover in creature movement packet std::copy(move_spline._Spline().getPoints(false).begin(), move_spline._Spline().getPoints(false).end(), visualPoints->begin()); PacketBuilder::WriteMonsterMove(move_spline, data); unit->SendMessageToSet(&data, true); return move_spline.Duration(); } void MoveSplineInit::Stop() { MoveSpline& move_spline = *unit->movespline; // No need to stop if we are not moving if (move_spline.Finalized()) return; bool transport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID(); Location loc; if (move_spline.onTransport == transport) loc = move_spline.ComputePosition(); else { Position const* pos; if (!transport) pos = unit; else pos = &unit->m_movementInfo.transport.pos; loc.x = pos->GetPositionX(); loc.y = pos->GetPositionY(); loc.z = pos->GetPositionZ(); loc.orientation = unit->GetOrientation(); } args.flags = MoveSplineFlag::Done; unit->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD | MOVEMENTFLAG_SPLINE_ENABLED); move_spline.onTransport = transport; move_spline.Initialize(args); WorldPacket data(SMSG_MONSTER_MOVE, 64); data.append(unit->GetPackGUID()); if (transport) { data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT); data.appendPackGUID(unit->GetTransGUID()); data << int8(unit->GetTransSeat()); } PacketBuilder::WriteStopMovement(loc, args.splineId, data); unit->SendMessageToSet(&data, true); } MoveSplineInit::MoveSplineInit(Unit* m) : unit(m) { args.splineId = splineIdGen.NewId(); args.TransformForTransport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID(); // mix existing state into new args.flags.walkmode = unit->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING); args.flags.flying = unit->m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY)); } void MoveSplineInit::SetFacing(const Unit* target) { args.flags.EnableFacingTarget(); args.facing.target = target->GetGUID(); } void MoveSplineInit::SetFacing(float angle) { if (args.TransformForTransport) { if (Unit* vehicle = unit->GetVehicleBase()) angle -= vehicle->GetOrientation(); else if (Transport* transport = unit->GetTransport()) angle -= transport->GetOrientation(); } args.facing.angle = G3D::wrap(angle, 0.f, (float)G3D::twoPi()); args.flags.EnableFacingAngle(); } void MoveSplineInit::MoveTo(const Vector3& dest, bool generatePath, bool forceDestination) { if (generatePath) { PathGenerator path(unit); bool result = path.CalculatePath(dest.x, dest.y, dest.z, forceDestination); if (result && !(path.GetPathType() & PATHFIND_NOPATH)) { MovebyPath(path.GetPath()); return; } } args.path_Idx_offset = 0; args.path.resize(2); TransportPathTransform transform(unit, args.TransformForTransport); args.path[1] = transform(dest); } Vector3 TransportPathTransform::operator()(Vector3 input) { if (_transformForTransport) if (TransportBase* transport = _owner->GetDirectTransport()) transport->CalculatePassengerOffset(input.x, input.y, input.z); return input; } }