public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); var roomN = reader.ReadInt32(); Rooms = new VMRoomPortal[roomN]; for (int i=0; i< roomN; i++) Rooms[i] = new VMRoomPortal(reader); if (reader.ReadBoolean()) CurrentPortal = new VMRoomPortal(reader); var wtLen = reader.ReadInt32(); if (wtLen > -1) { WalkTo = new Point[wtLen]; for (int i = 0; i < wtLen; i++) WalkTo[i] = new Point(reader.ReadInt32(), reader.ReadInt32()); } WalkDirection = reader.ReadDouble(); TargetDirection = reader.ReadDouble(); IgnoreRooms = reader.ReadBoolean(); State = (VMRoutingFrameState)reader.ReadByte(); PortalTurns = reader.ReadInt32(); WaitTime = reader.ReadInt32(); Timeout = reader.ReadInt32(); Retries = reader.ReadInt32(); AttemptedChair = reader.ReadBoolean(); TurnTweak = reader.ReadSingle(); TurnFrames = reader.ReadInt32(); MoveTotalFrames = reader.ReadInt32(); MoveFrames = reader.ReadInt32(); Velocity = reader.ReadInt32(); CallFailureTrees = reader.ReadBoolean(); var igrN = reader.ReadInt32(); IgnoredRooms = new VMRoomPortal[igrN]; for (int i = 0; i < igrN; i++) IgnoredRooms[i] = new VMRoomPortal(reader); var avaN = reader.ReadInt32(); AvatarsToConsider = new short[avaN]; for (int i = 0; i < avaN; i++) AvatarsToConsider[i] = reader.ReadInt16(); PreviousPosition.Deserialize(reader); CurrentWaypoint.Deserialize(reader); RoomRouteInvalid = reader.ReadBoolean(); if (reader.ReadBoolean()) { Slot = SLOTItemSerializer.Deserialize(reader); } Target = reader.ReadInt16(); var chLen = reader.ReadInt32(); if (chLen > -1) { Choices = new VMFindLocationResultMarshal[chLen]; for (int i = 0; i < chLen; i++) { Choices[i] = new VMFindLocationResultMarshal(); Choices[i].Deserialize(reader); } } if (reader.ReadBoolean()) { CurRoute = new VMFindLocationResultMarshal(); CurRoute.Deserialize(reader); } }
public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); var roomN = reader.ReadInt32(); Rooms = new VMRoomPortal[roomN]; for (int i = 0; i < roomN; i++) { Rooms[i] = new VMRoomPortal(reader); } if (reader.ReadBoolean()) { CurrentPortal = new VMRoomPortal(reader); } var wtLen = reader.ReadInt32(); if (wtLen > -1) { WalkTo = new Point[wtLen]; for (int i = 0; i < wtLen; i++) { WalkTo[i] = new Point(reader.ReadInt32(), reader.ReadInt32()); } } WalkDirection = reader.ReadDouble(); TargetDirection = reader.ReadDouble(); IgnoreRooms = reader.ReadBoolean(); State = (VMRoutingFrameState)reader.ReadByte(); PortalTurns = reader.ReadInt32(); WaitTime = reader.ReadInt32(); Timeout = reader.ReadInt32(); Retries = reader.ReadInt32(); AttemptedChair = reader.ReadBoolean(); TurnTweak = reader.ReadSingle(); TurnFrames = reader.ReadInt32(); MoveTotalFrames = reader.ReadInt32(); MoveFrames = reader.ReadInt32(); Velocity = reader.ReadInt32(); CallFailureTrees = reader.ReadBoolean(); var igrN = reader.ReadInt32(); IgnoredRooms = new VMRoomPortal[igrN]; for (int i = 0; i < igrN; i++) { IgnoredRooms[i] = new VMRoomPortal(reader); } var avaN = reader.ReadInt32(); AvatarsToConsider = new short[avaN]; for (int i = 0; i < avaN; i++) { AvatarsToConsider[i] = reader.ReadInt16(); } PreviousPosition.Deserialize(reader); CurrentWaypoint.Deserialize(reader); RoomRouteInvalid = reader.ReadBoolean(); if (reader.ReadBoolean()) { Slot = SLOTItemSerializer.Deserialize(reader); } Target = reader.ReadInt16(); var chLen = reader.ReadInt32(); if (chLen > -1) { Choices = new VMFindLocationResultMarshal[chLen]; for (int i = 0; i < chLen; i++) { Choices[i] = new VMFindLocationResultMarshal(); Choices[i].Deserialize(reader); } } if (reader.ReadBoolean()) { CurRoute = new VMFindLocationResultMarshal(); CurRoute.Deserialize(reader); } if (Version > 29) { LastWalkStyle = reader.ReadInt16(); } }
private void BeginWalk() { //faces the avatar towards the initial walk direction and begins walking. WalkDirection = Caller.RadianDirection; var directionDiff = DirectionUtils.Difference(Caller.RadianDirection, TargetDirection); bool hardStart = CanPortalTurn(); Velocity = (hardStart) ? 0 : 8; if (hardStart && Turn(directionDiff)) { State = VMRoutingFrameState.BEGIN_TURN; } else { State = VMRoutingFrameState.WALKING; Caller.RadianDirection = (float)TargetDirection; StartWalkAnimation(); } }
//returns true if we should exit immediately. private bool EndWalk() { var avatar = (VMAvatar)Caller; WalkDirection = Caller.RadianDirection; TargetDirection = CurRoute.RadianDirection; avatar.SetPersonData(VMPersonDataVariable.RouteEntryFlags, (short)CurRoute.RouteEntryFlags); avatar.Velocity = new Vector3(); var directionDiff = DirectionUtils.Difference(Caller.RadianDirection, TargetDirection); if (!CurRoute.FaceAnywhere && CanPortalTurn() && Turn(directionDiff)) { State = VMRoutingFrameState.END_TURN; } else { if (!CurRoute.FaceAnywhere) avatar.RadianDirection = CurRoute.RadianDirection; return true; //we are here! } return false; }
/// <summary> /// Pathfinds to the destination position from the current. The room pathfind should get us to the same room before we do this. /// </summary> private bool AttemptWalk() { //find shortest path to destination tile. Simple A* pathfind. //portals are used to traverse floors, so we do not care about the floor each point is on. //when evaluating possible adjacent tiles we use the Caller's current floor. LotTilePos startPos = Caller.Position; CurrentWaypoint = LotTilePos.OUT_OF_WORLD; var myRoom = VM.Context.GetRoomAt(startPos); var roomInfo = VM.Context.RoomInfo[myRoom]; var obstacles = new List<VMObstacle>(); int bx = (roomInfo.Room.Bounds.X-1) << 4; int by = (roomInfo.Room.Bounds.Y-1) << 4; int width = (roomInfo.Room.Bounds.Width+2) << 4; int height = (roomInfo.Room.Bounds.Height+2) << 4; obstacles.Add(new VMObstacle(bx-16, by-16, bx+width+16, by)); obstacles.Add(new VMObstacle(bx-16, by+height, bx+width+16, by+height+16)); obstacles.Add(new VMObstacle(bx-16, by-16, bx, by+height+16)); obstacles.Add(new VMObstacle(bx+width, by-16, bx+width+16, by+height+16)); foreach (var obj in roomInfo.Entities) { var ft = obj.Footprint; var flags = (VMEntityFlags)obj.GetValue(VMStackObjectVariable.Flags); if (obj != Caller && ft != null && (obj is VMGameObject || AvatarsToConsider.Contains(obj)) && ((flags & VMEntityFlags.DisallowPersonIntersection) > 0 || (flags & VMEntityFlags.AllowPersonIntersection) == 0)) obstacles.Add(new VMObstacle(ft.x1-3, ft.y1-3, ft.x2+3, ft.y2+3)); } obstacles.AddRange(roomInfo.Room.WallObs); if (!IgnoreRooms) obstacles.AddRange(roomInfo.Room.RoomObs); var startPoint = new Point((int)startPos.x, (int)startPos.y); var endPoint = new Point((int)CurRoute.Position.x, (int)CurRoute.Position.y); foreach (var rect in obstacles) { if (rect.HardContains(startPoint)) return false; } var router = new VMRectRouter(obstacles); if (startPoint == endPoint) { State = VMRoutingFrameState.TURN_ONLY; return true; } WalkTo = router.Route(startPoint, endPoint); if (WalkTo != null) { if (WalkTo.First.Value != endPoint) WalkTo.RemoveFirst(); AdvanceWaypoint(); } return (WalkTo != null); }
public VMPrimitiveExitCode Tick() { var avatar = (VMAvatar)Caller; avatar.Velocity = new Vector3(0, 0, 0); if (State != VMRoutingFrameState.FAILED && avatar.GetFlag(VMEntityFlags.InteractionCanceled) && avatar.GetPersonData(VMPersonDataVariable.NonInterruptable) == 0) { HardFail(VMRouteFailCode.Interrupted, null); return VMPrimitiveExitCode.CONTINUE; } if (WaitTime > 0) { if (Velocity > 0) Velocity--; if (avatar.Animations.Count < 3) StartWalkAnimation(); avatar.Animations[0].Weight = (8 - Velocity) / 8f; avatar.Animations[1].Weight = (Velocity / 8f) * 0.66f; avatar.Animations[2].Weight = (Velocity / 8f) * 0.33f; WaitTime--; Timeout--; if (Timeout <= 0) { //try again. not sure if we should reset timeout for the new route SoftFail(VMRouteFailCode.NoPath, null); if (State != VMRoutingFrameState.FAILED) { Velocity = 0; State = VMRoutingFrameState.WALKING; } } else return VMPrimitiveExitCode.CONTINUE_NEXT_TICK; } if (RoomRouteInvalid && State != VMRoutingFrameState.BEGIN_TURN && State != VMRoutingFrameState.END_TURN) { RoomRouteInvalid = false; IgnoredRooms.Clear(); WalkTo = null; //reset routing state if (!DoRoomRoute(CurRoute)) { if (CurRoute != null) SoftFail(VMRouteFailCode.NoRoomRoute, null); else HardFail(VMRouteFailCode.NoRoomRoute, null); } else if (Rooms.Count > 0) { State = VMRoutingFrameState.INITIAL; } } switch (State) { case VMRoutingFrameState.STAND_FUNC: if (Thread.LastStackExitCode == VMPrimitiveExitCode.RETURN_TRUE) { State = VMRoutingFrameState.INITIAL; if (avatar.GetPersonData(VMPersonDataVariable.Posture) == 1) avatar.SetPersonData(VMPersonDataVariable.Posture, 0); } else SoftFail(VMRouteFailCode.CantStand, null); return VMPrimitiveExitCode.CONTINUE; case VMRoutingFrameState.INITIAL: case VMRoutingFrameState.ROOM_PORTAL: //check if the room portal that just finished succeeded. if (State == VMRoutingFrameState.ROOM_PORTAL) { if (Thread.LastStackExitCode != VMPrimitiveExitCode.RETURN_TRUE) { IgnoredRooms.Add(CurrentPortal); State = VMRoutingFrameState.INITIAL; if (!DoRoomRoute(CurRoute)) { SoftFail(VMRouteFailCode.NoRoomRoute, null); //todo: reattempt room route with portal we tried removed. return VMPrimitiveExitCode.CONTINUE; } } } if (Rooms.Count > 0) { //push portal function of next portal CurrentPortal = Rooms.Pop(); var ent = VM.GetObjectById(CurrentPortal.ObjectID); State = VMRoutingFrameState.ROOM_PORTAL; if (!PushEntryPoint(15, ent)) //15 is portal function SoftFail(VMRouteFailCode.NoRoomRoute, null); //could not execute portal function return VMPrimitiveExitCode.CONTINUE; } //if we're here, room route is OK. start routing to a destination. if (Choices == null) { //perform slot parse. if (Slot == null) { HardFail(VMRouteFailCode.Unknown, null); return VMPrimitiveExitCode.CONTINUE; //this should never happen. If it does, someone has used the routing system incorrectly. } var parser = new VMSlotParser(Slot); Choices = parser.FindAvaliableLocations(Target, VM.Context, avatar); if (Choices.Count == 0) { HardFail(parser.FailCode, parser.Blocker); return VMPrimitiveExitCode.CONTINUE; } else { CurRoute = Choices[0]; Choices.RemoveAt(0); } } //do we need to sit in a seat? it should take over. if (CurRoute.Chair != null) { if (!AttemptedChair) { AttemptedChair = true; if (PushEntryPoint(26, CurRoute.Chair)) return VMPrimitiveExitCode.CONTINUE; else { SoftFail(VMRouteFailCode.CantSit, null); return VMPrimitiveExitCode.CONTINUE; } } else { if (Thread.LastStackExitCode == VMPrimitiveExitCode.RETURN_TRUE) return VMPrimitiveExitCode.RETURN_TRUE; else { SoftFail(VMRouteFailCode.CantSit, null); return VMPrimitiveExitCode.CONTINUE; } } } //If we are sitting, and the target is not this seat we need to call the stand function on the object we are contained within. if (avatar.GetPersonData(VMPersonDataVariable.Posture) == 1) { State = VMRoutingFrameState.STAND_FUNC; //push it onto our stack, except now the portal owns our soul! when we are returned to we can evaluate the result and determine if the route failed. var chair = Caller.Container; if (chair == null) avatar.SetPersonData(VMPersonDataVariable.Posture, 0); //we're sitting, but are not bound to a chair. Just instantly get up.. else { if (!PushEntryPoint(27, chair)) //27 is stand. TODO: set up an enum for these HardFail(VMRouteFailCode.CantStand, null); return VMPrimitiveExitCode.CONTINUE; } } //no chair, we just need to walk to the spot. Start the within-room routing. if (WalkTo == null) { if (!AttemptWalk()) { SoftFail(VMRouteFailCode.NoPath, null); return VMPrimitiveExitCode.CONTINUE; } } if (State != VMRoutingFrameState.TURN_ONLY) BeginWalk(); return VMPrimitiveExitCode.CONTINUE; case VMRoutingFrameState.FAILED: return VMPrimitiveExitCode.RETURN_FALSE; case VMRoutingFrameState.TURN_ONLY: return (EndWalk()) ? VMPrimitiveExitCode.RETURN_TRUE : VMPrimitiveExitCode.CONTINUE; case VMRoutingFrameState.SHOOED: StartWalkAnimation(); State = VMRoutingFrameState.WALKING; return VMPrimitiveExitCode.CONTINUE; case VMRoutingFrameState.BEGIN_TURN: case VMRoutingFrameState.END_TURN: if (avatar.CurrentAnimationState.EndReached) { if (State == VMRoutingFrameState.BEGIN_TURN) { State = VMRoutingFrameState.WALKING; WalkDirection = TargetDirection; avatar.RadianDirection = (float)TargetDirection; StartWalkAnimation(); return VMPrimitiveExitCode.CONTINUE; } else { if (!CurRoute.FaceAnywhere) avatar.RadianDirection = CurRoute.RadianDirection; //reset animation, so that we're facing the correct direction afterwards. avatar.Animations.Clear(); var animation = FSO.Content.Content.Get().AvatarAnimations.Get(avatar.WalkAnimations[3] + ".anim"); var state = new VMAnimationState(animation, false); state.Loop = true; avatar.Animations.Add(state); return VMPrimitiveExitCode.RETURN_TRUE; //we are here! } } else { avatar.RadianDirection += TurnTweak; //while we're turning, adjust our direction return VMPrimitiveExitCode.CONTINUE_NEXT_TICK; } case VMRoutingFrameState.WALKING: if (WalkTo == null) { if (!AttemptWalk()) { SoftFail(VMRouteFailCode.NoPath, null); } return VMPrimitiveExitCode.CONTINUE; } if (WalkTo.Count == 0 && MoveTotalFrames - MoveFrames <= 28 && CanPortalTurn()) //7+6+5+4... { //tail off if (Velocity <= 0) Velocity = 1; if (Velocity > 1) Velocity--; } else { //get started if (Velocity < 8) Velocity++; } avatar.Animations[0].Weight = (8 - Velocity) / 8f; avatar.Animations[1].Weight = (Velocity / 8f) * 0.66f; avatar.Animations[2].Weight = (Velocity / 8f) * 0.33f; MoveFrames += Velocity; if (MoveFrames >= MoveTotalFrames) { MoveFrames = MoveTotalFrames; //move us to the final spot, then attempt an advance. } //normal sims can move 0.05 units in a frame. if (TurnFrames > 0) { avatar.RadianDirection = (float)(TargetDirection + DirectionUtils.Difference(TargetDirection, WalkDirection) * (TurnFrames / 10.0)); TurnFrames--; } else avatar.RadianDirection = (float)TargetDirection; var diff = CurrentWaypoint - PreviousPosition; diff.x = (short)((diff.x * MoveFrames) / MoveTotalFrames); diff.y = (short)((diff.y * MoveFrames) / MoveTotalFrames); var storedDir = avatar.RadianDirection; var result = Caller.SetPosition(PreviousPosition + diff, Direction.NORTH, VM.Context); avatar.RadianDirection = storedDir; if (result.Status != VMPlacementError.Success && result.Status != VMPlacementError.CantBeThroughWall) { //route failure, either something changed or we hit an avatar //on both cases try again, but if we hit an avatar then detect if they have a routing frame and stop us for a bit. //we stop the first collider because in most cases they're walking across our walk direction and the problem will go away after a second once they're past. // //if we need to route around a stopped avatar we add them to our "avatars to consider" set. bool routeAround = true; VMRoutingFrame colRoute = null; if (result.Object != null && result.Object is VMAvatar) { var colAvatar = (VMAvatar)result.Object; var colTopFrame = colAvatar.Thread.Stack.LastOrDefault(); //we already attempted to move around this avatar... if this happens too much give up. if (AvatarsToConsider.Contains(colAvatar) && --Retries <= 0) { SoftFail(VMRouteFailCode.NoPath, avatar); return VMPrimitiveExitCode.CONTINUE; } if (colTopFrame != null && colTopFrame is VMRoutingFrame) { colRoute = (VMRoutingFrame)colTopFrame; routeAround = (colRoute.WaitTime > 0); } if (routeAround) AvatarsToConsider.Add(colAvatar); } if (result.Object == null || result.Object is VMGameObject) { //this should not happen often. An object or other feature has blocked our path due to some change in its position. //repeated occurances indicate that we are stuck in something. //todo: is this safe for the robot lot? if (--Retries <= 0) { SoftFail(VMRouteFailCode.NoPath, avatar); return VMPrimitiveExitCode.CONTINUE; } } if (routeAround) { var oldWalk = new LinkedList<Point>(WalkTo); if (AttemptWalk()) return VMPrimitiveExitCode.CONTINUE; else { //failed to walk around the object if (result.Object is VMAvatar) { WalkTo = oldWalk; //if they're a person, shoo them away. //if they're in a routing frame we can push the tree directly onto their stack //otherwise we push an interaction and just hope they move (todo: does tso do this?) //DO NOT push tree if: // - sim is already being shooed. (the parent of the top routing frame is in state "SHOOED" or shoo interaction is present) // - we are being shooed. // - sim is waiting on someone they just shooed. (presumably can move out of our way once they finish waiting) //instead just wait a small duration and try again later. //cases where we cannot continue moving increase the retry count. if this is greater than RETRY_COUNT then we fail. //not sure how the original game works. if (CanShooAvatar((VMAvatar)result.Object)) { AvatarsToConsider.Remove((VMAvatar)result.Object); VMEntity callee = VM.Context.CreateObjectInstance(GOTO_GUID, new LotTilePos(result.Object.Position), Direction.NORTH).Objects[0]; if (colRoute != null) { colRoute.State = VMRoutingFrameState.SHOOED; colRoute.WalkTo = null; colRoute.AvatarsToConsider.Add(avatar); //just to make sure they don't try route through us. var tree = callee.GetBHAVWithOwner(SHOO_TREE, VM.Context); result.Object.Thread.ExecuteSubRoutine(colRoute, tree.bhav, tree.owner, new VMSubRoutineOperand()); WalkInterrupt(60); } else { callee.PushUserInteraction(SHOO_INTERACTION, result.Object, VM.Context); WalkInterrupt(60); } } else { WalkInterrupt(60); //wait for a little while, they're moving out of the way. } return VMPrimitiveExitCode.CONTINUE; } SoftFail(VMRouteFailCode.DestTileOccupied, result.Object); return VMPrimitiveExitCode.CONTINUE; } } else { WalkInterrupt(30); return VMPrimitiveExitCode.CONTINUE; } } Caller.VisualPosition = Vector3.Lerp(PreviousPosition.ToVector3(), CurrentWaypoint.ToVector3(), MoveFrames / (float)MoveTotalFrames); var velocity = Vector3.Lerp(PreviousPosition.ToVector3(), CurrentWaypoint.ToVector3(), Velocity / (float)MoveTotalFrames) - PreviousPosition.ToVector3(); velocity.Z = 0; avatar.Velocity = velocity; if (MoveTotalFrames == MoveFrames) { MoveTotalFrames = 0; while (MoveTotalFrames == 0) { var remains = AdvanceWaypoint(); if (!remains) { MoveTotalFrames = -1; if (EndWalk()) return VMPrimitiveExitCode.RETURN_TRUE; } } } return VMPrimitiveExitCode.CONTINUE_NEXT_TICK; } return VMPrimitiveExitCode.GOTO_FALSE; //??? }
public override void Load(VMStackFrameMarshal input, VMContext context) { base.Load(input, context); var inR = (VMRoutingFrameMarshal)input; Rooms = new Stack<VMRoomPortal>(); for (int i=inR.Rooms.Length-1; i>=0; i--) Rooms.Push(inR.Rooms[i]); CurrentPortal = inR.CurrentPortal; ParentRoute = GetParentFrame(); //should be able to, since all arrays are generated left to right, including the stacks. WalkTo = (inR.WalkTo == null)?null:new LinkedList<Point>(inR.WalkTo); WalkDirection = inR.WalkDirection; TargetDirection = inR.TargetDirection; IgnoreRooms = inR.IgnoreRooms; State = inR.State; PortalTurns = inR.PortalTurns; WaitTime = inR.WaitTime; Timeout = inR.Timeout; Retries = inR.Retries; AttemptedChair = inR.AttemptedChair; TurnTweak = inR.TurnTweak; TurnFrames = inR.TurnFrames; MoveTotalFrames = inR.MoveTotalFrames; MoveFrames = inR.MoveFrames; Velocity = inR.Velocity; CallFailureTrees = inR.CallFailureTrees; IgnoredRooms = new HashSet<VMRoomPortal>(inR.IgnoredRooms); AvatarsToConsider = new HashSet<VMAvatar>(); foreach (var avatar in inR.AvatarsToConsider) AvatarsToConsider.Add((VMAvatar)context.VM.GetObjectById(avatar)); PreviousPosition = inR.PreviousPosition; CurrentWaypoint = inR.CurrentWaypoint; RoomRouteInvalid = inR.RoomRouteInvalid; Slot = inR.Slot; //NULLable Target = context.VM.GetObjectById(inR.Target); //object id if (inR.Choices != null) { Choices = new List<VMFindLocationResult>(); foreach (var c in inR.Choices) Choices.Add(new VMFindLocationResult(c, context)); } else Choices = null; CurRoute = (inR.CurRoute == null)?null:new VMFindLocationResult(inR.CurRoute, context); //NULLable }
private void HardFail(VMRouteFailCode code, VMEntity blocker) { State = VMRoutingFrameState.FAILED; var avatar = (VMAvatar)Caller; if (CallFailureTrees) { avatar.SetPersonData(VMPersonDataVariable.Priority, 100); //TODO: what is this meant to be? what dictates it? //probably has to do with interaction priority. //we just set it to 100 here so that failure trees work. var bhav = Global.Resource.Get<BHAV>(ROUTE_FAIL_TREE); Thread.ExecuteSubRoutine(this, bhav, CodeOwner, new VMSubRoutineOperand(new short[] { (short)code, (blocker==null)?(short)0:blocker.ObjectID, 0, 0 })); } avatar.SetPersonData(VMPersonDataVariable.RouteResult, (short)code); }
public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); var bezierRouting = (Version > 31); var roomN = reader.ReadInt32(); Rooms = new VMRoomPortal[roomN]; for (int i = 0; i < roomN; i++) { Rooms[i] = new VMRoomPortal(reader); } if (reader.ReadBoolean()) { CurrentPortal = new VMRoomPortal(reader); } var wtLen = reader.ReadInt32(); Point[] points = null; if (wtLen > -1) { WalkTo = new VMIPathSegment[wtLen]; if (bezierRouting) { for (int i = 0; i < wtLen; i++) { WalkTo[i] = ReadGenericSegment(reader); } } else { //old point list. convert to line segments. points = new Point[wtLen]; for (int i = 0; i < wtLen; i++) { points[i] = new Point(reader.ReadInt32(), reader.ReadInt32()); } } } WalkDirection = reader.ReadDouble(); TargetDirection = reader.ReadDouble(); IgnoreRooms = reader.ReadBoolean(); State = (VMRoutingFrameState)reader.ReadByte(); PortalTurns = reader.ReadInt32(); WaitTime = reader.ReadInt32(); Timeout = reader.ReadInt32(); Retries = reader.ReadInt32(); AttemptedChair = reader.ReadBoolean(); TurnTweak = reader.ReadSingle(); TurnFrames = reader.ReadInt32(); MoveTotalFrames = reader.ReadInt32(); MoveFrames = reader.ReadInt32(); Velocity = reader.ReadInt32(); CallFailureTrees = reader.ReadBoolean(); var igrN = reader.ReadInt32(); IgnoredRooms = new VMRoomPortal[igrN]; for (int i = 0; i < igrN; i++) { IgnoredRooms[i] = new VMRoomPortal(reader); } var avaN = reader.ReadInt32(); AvatarsToConsider = new short[avaN]; for (int i = 0; i < avaN; i++) { AvatarsToConsider[i] = reader.ReadInt16(); } LotTilePos CurrentWaypoint = new LotTilePos(); PreviousPosition.Deserialize(reader); if (bezierRouting) { CurrentPath = ReadGenericSegment(reader); } else { //convert old format into new CurrentWaypoint.Deserialize(reader); CurrentPath = new VMPathLineSegment( new Point(PreviousPosition.x * 0x8000, PreviousPosition.y * 0x8000), new Point(CurrentWaypoint.x * 0x8000, CurrentWaypoint.y * 0x8000)); if (points != null) { if (points.Length > 0) { WalkTo = new VMIPathSegment[points.Length]; WalkTo[0] = new VMPathLineSegment( new Point(CurrentWaypoint.x * 0x8000, CurrentWaypoint.y * 0x8000), new Point(points[0].X * 0x8000, points[0].Y * 0x8000)); for (int i = 1; i < WalkTo.Length; i++) { WalkTo[i] = new VMPathLineSegment( new Point(points[i - 1].X * 0x8000, points[i - 1].Y * 0x8000), new Point(points[i].X * 0x8000, points[i].Y * 0x8000)); } } else { WalkTo = new VMIPathSegment[0]; } } else { WalkTo = null; } } CurrentPath.CalculateTotalFrames(); CurrentPath.UpdateTotalFrames(MoveTotalFrames); CurrentPath.ResetToFrame(MoveFrames); RoomRouteInvalid = reader.ReadBoolean(); if (reader.ReadBoolean()) { Slot = SLOTItemSerializer.Deserialize(reader); } Target = reader.ReadInt16(); var chLen = reader.ReadInt32(); if (chLen > -1) { Choices = new VMFindLocationResultMarshal[chLen]; for (int i = 0; i < chLen; i++) { Choices[i] = new VMFindLocationResultMarshal(); Choices[i].Deserialize(reader); } } if (reader.ReadBoolean()) { CurRoute = new VMFindLocationResultMarshal(); CurRoute.Deserialize(reader); } if (Version > 29) { LastWalkStyle = reader.ReadInt16(); } }