/// <summary> /// </summary> /// <param name="character"> /// </param> /// <param name="destination"> /// </param> /// <param name="heading"> /// </param> /// <param name="playfield"> /// </param> /// <returns> /// </returns> public static N3TeleportMessage Create( ICharacter character, Coordinate destination, IQuaternion heading, Identity playfield) { return new N3TeleportMessage() { Identity = character.Identity, Destination = new Vector3() { X = destination.x, Y = destination.y, Z = destination.z }, Heading = new Quaternion() { X = heading.xf, Y = heading.yf, Z = heading.zf, W = heading.wf }, Unknown1 = 0x61, Playfield = new Identity() { Type = IdentityType.Playfield1, Instance = playfield.Instance }, ChangePlayfield = ((playfield.Instance != character.Playfield.Identity.Instance) || (playfield.Type != character.Playfield.Identity.Type)) ? new Identity { Type = IdentityType.Playfield2, Instance = playfield.Instance } : Identity.None, Playfield2 = new Identity { Type = IdentityType.Playfield3, Instance = playfield.Instance }, }; }
/// <summary> /// </summary> /// <param name="character"> /// </param> /// <param name="destination"> /// </param> /// <param name="heading"> /// </param> /// <param name="playfield"> /// </param> public static void Send(ICharacter character, Coordinate destination, IQuaternion heading, Identity playfield) { // This needs to be sent immediately! character.Client.SendCompressed(Create(character, destination, heading, playfield)); }
/// <summary> /// </summary> /// <param name="Self"> /// </param> /// <param name="Caller"> /// </param> /// <param name="Target"> /// </param> /// <param name="Arguments"> /// </param> /// <returns> /// </returns> public bool FunctionExecute( INamedEntity Self, IEntity Caller, IInstancedEntity Target, MessagePackObject[] Arguments) { // TODO: Use the arguments!!!!! Coordinate destination = new Coordinate(Arguments[0].AsInt32(), Arguments[1].AsInt32(), Arguments[2].AsInt32()); IQuaternion heading = new Quaternion(0.0, 0.0, 0.0, 0.0); Identity playfield = new Identity() { Type = IdentityType.Playfield, Instance = Arguments[3].AsInt32() }; if (playfield.Instance==0) { playfield = Self.Playfield.Identity; } ((Character)Self).Teleport(destination, heading, playfield); return true; }
/// <summary> /// </summary> /// <param name="Self"> /// </param> /// <param name="Caller"> /// </param> /// <param name="Target"> /// </param> /// <param name="Arguments"> /// </param> /// <returns> /// </returns> public bool FunctionExecute( INamedEntity Self, INamedEntity Caller, IInstancedEntity Target, MessagePackObject[] Arguments) { // TODO: Use the arguments!!!!! Coordinate destination = new Coordinate(); IQuaternion heading = new Quaternion(0.0, 0.0, 0.0, 0.0); Identity playfield = new Identity(); ((Character)Self).Teleport(destination, heading, playfield); return true; }
/// <summary> /// </summary> /// <param name="self"> /// </param> /// <param name="caller"> /// </param> /// <param name="target"> /// </param> /// <param name="arguments"> /// </param> /// <returns> /// </returns> public override bool Execute( INamedEntity self, IEntity caller, IInstancedEntity target, MessagePackObject[] arguments) { if (arguments.Count() != 3) { return false; } uint arg1 = arguments[1].AsUInt32(); int toPlayfield = arguments[2].AsInt32(); byte destinationIndex = (byte)(arg1 >> 16); PlayfieldData pfd = PlayfieldLoader.PFData[toPlayfield]; PlayfieldDestination pfDestination = pfd.Destinations[destinationIndex]; float newX = (pfDestination.EndX - pfDestination.StartX) * 0.5f + pfDestination.StartX; float newZ = (pfDestination.EndZ - pfDestination.StartZ) * 0.5f + pfDestination.StartZ; float dist = WallCollision.Distance( pfDestination.StartX, pfDestination.StartZ, pfDestination.EndX, pfDestination.EndZ); float headDistX = (pfDestination.EndX - pfDestination.StartX) / dist; float headDistZ = (pfDestination.EndZ - pfDestination.StartZ) / dist; newX -= headDistZ * 4; newZ += headDistX * 4; Coordinate destCoordinate = new Coordinate(newX, pfDestination.EndY, newZ); ((ICharacter)self).Teleport( destCoordinate, ((ICharacter)self).Heading, new Identity() { Type = IdentityType.Playfield, Instance = toPlayfield }); return true; }
/// <summary> /// </summary> /// <param name="message"> /// </param> /// <param name="client"> /// </param> public static void Read(CharDCMoveMessage message, ZoneClient client) { byte moveType = message.MoveType; var heading = new Quaternion(message.Heading.X, message.Heading.Y, message.Heading.Z, message.Heading.W); Coordinate coordinates = new Coordinate(message.Coordinates); // TODO: Find out what these (tmpInt) are and name them int tmpInt1 = message.Unknown1; int tmpInt2 = message.Unknown2; int tmpInt3 = message.Unknown3; /* if (!client.Character.DoNotDoTimers) { var teleportPlayfield = WallCollision.WallCollisionCheck( coordinates.x, coordinates.z, client.Character.PlayField); if (teleportPlayfield.ZoneToPlayfield >= 1) { var coordHeading = WallCollision.GetCoord( teleportPlayfield, coordinates.x, coordinates.z, coordinates); if (teleportPlayfield.Flags != 1337 && client.Character.PlayField != 152 || Math.Abs(client.Character.Coordinates.y - teleportPlayfield.Y) <= 2 || teleportPlayfield.Flags == 1337 && Math.Abs(client.Character.Coordinates.y - teleportPlayfield.Y) <= 6) { client.Teleport( coordHeading.Coordinates, coordHeading.Heading, teleportPlayfield.ZoneToPlayfield); Program.zoneServer.Clients.Remove(client); } return; } if (client.Character.Stats.LastConcretePlayfieldInstance.Value != 0) { var correspondingDoor = DoorHandler.DoorinRange( client.Character.PlayField, client.Character.Coordinates, 1.0f); if (correspondingDoor != null) { correspondingDoor = DoorHandler.FindCorrespondingDoor(correspondingDoor, client.Character); client.Character.Stats.LastConcretePlayfieldInstance.Value = 0; var aoc = correspondingDoor.Coordinates; aoc.x += correspondingDoor.hX * 3; aoc.y += correspondingDoor.hY * 3; aoc.z += correspondingDoor.hZ * 3; client.Teleport(aoc, client.Character.Heading, correspondingDoor.playfield); Program.zoneServer.Clients.Remove(client); return; } } } */ // Is this correct? Shouldnt the client input be compared to the prediction and then be overridden to prevent teleportation exploits? // - Algorithman client.Character.RawCoordinates = coordinates.coordinate; client.Character.RawHeading = heading; client.Character.UpdateMoveType(moveType); /* Start NV Heading Testing Code * Yaw: 0 to 360 Degrees (North turning clockwise to a complete revolution) * Roll: Not sure, but is always 0 cause we can't roll in AO * Pitch: 90 to -90 Degrees (90 is nose in the air, 0 is level, -90 is nose to the ground) */ /* Comment this line with a '//' to enable heading testing client.SendChatText("Raw Headings: X: " + client.Character.heading.x + " Y: " + client.Character.heading.y + " Z:" + client.Character.heading.z); client.SendChatText("Yaw: " + Math.Round(180 * client.Character.heading.yaw / Math.PI) + " Degrees"); client.SendChatText("Roll: " + Math.Round(180 * client.Character.heading.roll / Math.PI) + " Degrees"); client.SendChatText("Pitch: " + Math.Round(180 * client.Character.heading.pitch / Math.PI) + " Degrees"); /* End NV Heading testing code */ /* start of packet */ var reply = new CharDCMoveMessage { Identity = client.Character.Identity, Unknown = 0x00, MoveType = moveType, Heading = new SmokeLounge.AOtomation.Messaging.GameData.Quaternion { X = heading .xf, Y = heading .yf, Z = heading .zf, W = heading .wf }, Coordinates = new Vector3 { X = coordinates.x, Y = coordinates.y, Z = coordinates.z }, Unknown1 = tmpInt1, Unknown2 = tmpInt2, Unknown3 = tmpInt3 }; client.Playfield.Publish(new IMSendAOtomationMessageToPlayfield { Body = reply }); // TODO: rewrite statelscheck /* if (Statels.StatelppfonEnter.ContainsKey(client.Character.PlayField)) { foreach (var s in Statels.StatelppfonEnter[client.Character.PlayField]) { if (s.onEnter(client)) { return; } if (s.onTargetinVicinity(client)) { return; } } } */ }