Exemple #1
0
 private void SetFail(VMRouteFailCode code, VMEntity blocker)
 {
     if (Array.IndexOf(FailPrio, code) > Array.IndexOf(FailPrio, FailCode))
     {
         FailCode = code;
         Blocker  = blocker;
     }
 }
Exemple #2
0
        // TODO: float values may desync if devices are not both x86 or using a different C# library.
        // Might need to replace with fixed point library for position and rotation

        /// <summary>
        /// This method will find all the avaliable locations within the criteria ordered by proximity to the optimal proximity
        /// External functions can then decide which is most desirable. E.g. the nearest slot to the object may be the longest route if
        /// its in another room.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="slot"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public List <VMFindLocationResult> FindAvaliableLocations(VMEntity obj, VMContext context, VMEntity caller)
        {
            /**
             * Start at min proximity and circle around the object to find the avaliable locations.
             * Then pick the one nearest to the optimal value
             */

            /**
             * ------ MAJOR TODO: ------
             * Avoid vector math at all costs! Small differences in hardware could cause desyncs.
             * This really goes for all areas of the SimAntics engine, but here it's particularly bad.
             */
            Vector2 center;

            if (OnlySit)
            {
                FailCode = VMRouteFailCode.NoChair;
            }

            // if we need to use the average location of an object group, it needs to be calculated.
            if (((Flags & SLOTFlags.UseAverageObjectLocation) > 0) && (obj.MultitileGroup.MultiTile))
            {
                center = new Vector2(0, 0);
                var objs = obj.MultitileGroup.Objects;
                for (int i = 0; i < objs.Count; i++)
                {
                    center += new Vector2(objs[i].Position.x / 16f, objs[i].Position.y / 16f);
                }
                center /= objs.Count;
            }
            else
            {
                center = new Vector2(obj.Position.x / 16f, obj.Position.y / 16f);
            }

            //add offset of slot if it exists. must be rotated to be relative to object
            var rotOff    = Vector3.Transform(Slot.Offset, Matrix.CreateRotationZ(obj.RadianDirection));
            var circleCtr = new Vector2(center.X + rotOff.X / 16, center.Y + rotOff.Y / 16);

            ushort room = context.VM.Context.GetRoomAt(obj.Position);

            Results = new List <VMFindLocationResult>();

            if ((Flags & SLOTFlags.SnapToDirection) > 0)
            { //snap to the specified direction, on the specified point.
                double baseRot;
                if (Slot.Facing > SLOTFacing.FaceAwayFromObject)
                {
                    // bit of a legacy thing here. Facing field did not use to exist,
                    // which is why SnapToDirection was hacked to use the directional flags.
                    // now that it exists, it is used instead, to encode the same information...
                    // just transform back into old format.
                    Flags |= (SLOTFlags)(1 << (int)Slot.Facing);
                }
                else
                {
                    if (((int)Flags & 255) == 0)
                    {
                        Flags |= SLOTFlags.NORTH;
                    }
                }

                var flagRot = DirectionUtils.PosMod(obj.RadianDirection + FlagsAsRad(Flags), Math.PI * 2);
                if (flagRot > Math.PI)
                {
                    flagRot -= Math.PI * 2;
                }

                VerifyAndAddLocation(obj, circleCtr, center, Flags, Double.MaxValue, context, caller, (float)flagRot);
                return(Results);
            }
            else
            {
                if (((int)Flags & 255) == 0 || Slot.Offset != new Vector3())
                {
                    //exact position
                    //Flags |= (SLOTFlags)255;

                    // special case, walk directly to point.
                    VerifyAndAddLocation(obj, circleCtr, center, Flags, Double.MaxValue, context, caller, float.NaN);
                    return(Results);
                }
                var maxScore    = Math.Max(DesiredProximity - MinProximity, MaxProximity - DesiredProximity) + (LotTilePos.Distance(obj.Position, caller.Position) + MaxProximity) / 3 + 2;
                var ignoreRooms = (Flags & SLOTFlags.IgnoreRooms) > 0;

                SLOTEnumerationFunction((x, y, distance) =>
                {
                    var pos = new Vector2(circleCtr.X + x / 16.0f, circleCtr.Y + y / 16.0f);
                    if (distance >= MinProximity - 0.5 && distance <= MaxProximity + 0.5 && (ignoreRooms || context.VM.Context.GetRoomAt(new LotTilePos((short)Math.Round(pos.X * 16), (short)Math.Round(pos.Y * 16), obj.Position.Level)) == room)) //slot is within proximity
                    {
                        var routeEntryFlags = (GetSearchDirection(circleCtr, pos, obj.RadianDirection) & Flags);                                                                                                                                     //the route needs to know what conditions it fulfilled
                        if (routeEntryFlags > 0)                                                                                                                                                                                                     //within search location
                        {
                            double baseScore = ((maxScore - Math.Abs(DesiredProximity - distance)) + context.VM.Context.NextRandom(1024) / 1024.0f);
                            VerifyAndAddLocation(obj, pos, center, routeEntryFlags, baseScore, context, caller, float.NaN);
                        }
                    }
                });
            }
            /** Sort by how close they are to desired proximity **/

            if (Results.Count > 1)
            {
                Results = Results.OrderBy(x => - x.Score).ToList();                   //avoid sort because it acts incredibly unusually
            }
            if (Results.Count > 0)
            {
                FailCode = VMRouteFailCode.Success;
            }
            return(Results);
        }
Exemple #3
0
 private void SetFail(VMRouteFailCode code, VMEntity blocker)
 {
     if (Array.IndexOf(FailPrio, code) > Array.IndexOf(FailPrio, FailCode))
     {
         FailCode = code;
         Blocker = blocker;
     }
 }
Exemple #4
0
        // TODO: float values may desync if devices are not both x86 or using a different C# library.
        // Might need to replace with fixed point library for position and rotation
        /// <summary>
        /// This method will find all the avaliable locations within the criteria ordered by proximity to the optimal proximity
        /// External functions can then decide which is most desirable. E.g. the nearest slot to the object may be the longest route if
        /// its in another room.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="slot"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public List<VMFindLocationResult> FindAvaliableLocations(VMEntity obj, VMContext context, VMEntity caller)
        {
            /**
             * Start at min proximity and circle around the object to find the avaliable locations.
             * Then pick the one nearest to the optimal value
             */

            /**
             * ------ MAJOR TODO: ------
             * Avoid vector math at all costs! Small differences in hardware could cause desyncs.
             * This really goes for all areas of the SimAntics engine, but here it's particularly bad.
             */
            Vector2 center;
            if (OnlySit) FailCode = VMRouteFailCode.NoChair;

            // if we need to use the average location of an object group, it needs to be calculated.
            if (((Flags & SLOTFlags.UseAverageObjectLocation) > 0) && (obj.MultitileGroup.MultiTile)) {
                center = new Vector2(0, 0);
                var objs = obj.MultitileGroup.Objects;
                for (int i = 0; i < objs.Count; i++)
                {
                    center += new Vector2(objs[i].Position.x/16f, objs[i].Position.y/16f);
                }
                center /= objs.Count;
            } else center = new Vector2(obj.Position.x/16f, obj.Position.y/16f);

            //add offset of slot if it exists. must be rotated to be relative to object
            var rotOff = Vector3.Transform(Slot.Offset, Matrix.CreateRotationZ(obj.RadianDirection));
            var circleCtr = new Vector2(center.X + rotOff.X / 16, center.Y + rotOff.Y / 16);

            ushort room = context.VM.Context.GetRoomAt(obj.Position);
            Results = new List<VMFindLocationResult>();

            if ((Flags & SLOTFlags.SnapToDirection) > 0)
            { //snap to the specified direction, on the specified point.
                double baseRot;
                if (Slot.Facing > SLOTFacing.FaceAwayFromObject)
                {
                    // bit of a legacy thing here. Facing field did not use to exist,
                    // which is why SnapToDirection was hacked to use the directional flags.
                    // now that it exists, it is used instead, to encode the same information...
                    // just transform back into old format.
                    Flags |= (SLOTFlags)(1 << (int)Slot.Facing);
                }
                else
                {
                    if (((int)Flags & 255) == 0) Flags |= SLOTFlags.NORTH;
                }

                var flagRot = DirectionUtils.PosMod(obj.RadianDirection+FlagsAsRad(Flags), Math.PI*2);
                if (flagRot > Math.PI) flagRot -= Math.PI * 2;

                VerifyAndAddLocation(obj, circleCtr, center, Flags, Double.MaxValue, context, caller, (float)flagRot);
                return Results;
            }
            else
            {
                if (((int)Flags & 255) == 0 || Slot.Offset != new Vector3())
                {
                    //exact position
                    //Flags |= (SLOTFlags)255;

                    // special case, walk directly to point.
                    VerifyAndAddLocation(obj, circleCtr, center, Flags, Double.MaxValue, context, caller, float.NaN);
                    return Results;
                }
                var maxScore = Math.Max(DesiredProximity - MinProximity, MaxProximity - DesiredProximity) + (LotTilePos.Distance(obj.Position, caller.Position)+MaxProximity)/3 + 2;
                var ignoreRooms = (Flags & SLOTFlags.IgnoreRooms) > 0;

                var resolutionBound = (MaxProximity / Slot.Resolution) * Slot.Resolution;

                for (int x = -resolutionBound; x <= resolutionBound; x += Slot.Resolution)
                {
                    for (int y = -resolutionBound; y <= resolutionBound; y += Slot.Resolution)
                    {
                        var pos = new Vector2(circleCtr.X + x / 16.0f, circleCtr.Y + y / 16.0f);
                        double distance = Math.Sqrt(x * x + y * y);
                        if (distance >= MinProximity - 0.01 && distance <= MaxProximity + 0.01 && (ignoreRooms || context.VM.Context.GetRoomAt(new LotTilePos((short)Math.Round(pos.X * 16), (short)Math.Round(pos.Y * 16), obj.Position.Level)) == room)) //slot is within proximity
                        {
                            var routeEntryFlags = (GetSearchDirection(circleCtr, pos, obj.RadianDirection) & Flags); //the route needs to know what conditions it fulfilled
                            if (routeEntryFlags > 0) //within search location
                            {
                                double baseScore = ((maxScore - Math.Abs(DesiredProximity - distance)) + context.VM.Context.NextRandom(1024) / 1024.0f);
                                VerifyAndAddLocation(obj, pos, center, routeEntryFlags, baseScore, context, caller, float.NaN);
                            }
                        }
                    }
                }
            }
            /** Sort by how close they are to desired proximity **/

            if (Results.Count > 1) Results = Results.OrderBy(x => -x.Score).ToList(); //avoid sort because it acts incredibly unusually
            if (Results.Count > 0) FailCode = VMRouteFailCode.Success;
            return Results;
        }
Exemple #5
0
        public void SoftFail(VMRouteFailCode code, VMEntity blocker)
        {
            var found = VMRouteFailCode.NoValidGoals;
            while (found != VMRouteFailCode.Success && Choices != null && Choices.Count > 0)
            {
                found = AttemptRoute(Choices[0]);
                Choices.RemoveAt(0);
            }

            if (found != VMRouteFailCode.Success) HardFail(code, blocker);
        }
Exemple #6
0
 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);
 }