コード例 #1
0
        private Point RectIntersect(VMObstacle r1, VMObstacle r2, Point destPoint)
        {
            bool vert = true;
            int  d1, d2, p = 0;

            if (r1.x1 == r2.x2)
            {
                vert = false; p = r1.x1;
            }
            if (r1.x2 == r2.x1)
            {
                vert = false; p = r1.x2;
            }

            if (r1.y1 == r2.y2)
            {
                vert = true; p = r1.y1;
            }
            if (r1.y2 == r2.y1)
            {
                vert = true; p = r1.y2;
            }

            if (vert)
            {
                d1 = Math.Max(r1.x1, r2.x1); d2 = Math.Min(r1.x2, r2.x2);
                return(new Point(Math.Max(d1, Math.Min(d2, destPoint.X)), p));
            }
            else
            {
                d1 = Math.Max(r1.y1, r2.y1); d2 = Math.Min(r1.y2, r2.y2);
                return(new Point(p, Math.Max(d1, Math.Min(d2, destPoint.Y))));
            }
        }
コード例 #2
0
 public virtual void PositionChange(VMContext context,bool noEntryPoint)
 {
     Footprint = GetObstacle(Position,Direction);
     if (!(GhostImage || noEntryPoint))
     {
         ExecuteEntryPoint(9,context,true);                                  //Placement
     }
 }
コード例 #3
0
        public void SetFlag(VMEntityFlags flag,bool set)
        {
            if (set)
            {
                ObjectData[(int)VMStackObjectVariable.Flags] |= (short)(flag);
            }
            else
            {
                ObjectData[(int)VMStackObjectVariable.Flags] &= ((short)~(flag));
            }

            if (flag == VMEntityFlags.HasZeroExtent)
            {
                Footprint = GetObstacle(Position,Direction);
            }
            return;
        }
コード例 #4
0
ファイル: VMContext.cs プロジェクト: Ne-Ice/FreeSims
        public VMPlacementResult GetAvatarPlace(VMEntity target, LotTilePos pos, Direction dir)
        {
            //avatars cannot be placed in slots under any circumstances, so we skip a few steps.

            VMObstacle footprint = target.GetObstacle(pos, dir);
            ushort     room      = GetRoomAt(pos);

            VMPlacementError status    = VMPlacementError.Success;
            VMEntity         statusObj = null;

            if (footprint == null || pos.Level < 1)
            {
                return(new VMPlacementResult(status));
            }

            var objs = RoomInfo[room].Entities;

            foreach (var obj in objs)
            {
                if (obj.MultitileGroup == target.MultitileGroup)
                {
                    continue;
                }
                var oFoot = obj.Footprint;

                if (oFoot != null && oFoot.Intersects(footprint) &&
                    (!(target.ExecuteEntryPoint(5, this, true, obj, new short[] { obj.ObjectID, 0, 0, 0 }) ||
                       obj.ExecuteEntryPoint(5, this, true, target, new short[] { target.ObjectID, 0, 0, 0 })))
                    )
                {
                    var  flags        = (VMEntityFlags)obj.GetValue(VMStackObjectVariable.Flags);
                    bool allowAvatars = ((flags & VMEntityFlags.DisallowPersonIntersection) == 0) && ((flags & VMEntityFlags.AllowPersonIntersection) > 0);
                    if (!allowAvatars)
                    {
                        status    = VMPlacementError.CantIntersectOtherObjects;
                        statusObj = obj;
                        if (obj.EntryPoints[26].ActionFunction != 0)
                        {
                            break;                                          //select chairs immediately.
                        }
                    }
                }
            }
            return(new VMPlacementResult(status, statusObj));
        }
コード例 #5
0
        public List <VMObstacle> GenerateRoomObs(ushort room, Rectangle bounds)
        {
            var result = new List <VMObstacle>();
            var x1     = Math.Max(0, bounds.X - 1);
            var x2     = Math.Min(Width, bounds.Right + 1);
            var y1     = Math.Max(0, bounds.Y - 1);
            var y2     = Math.Min(Height, bounds.Bottom + 1);

            for (int y = y1; y < y2; y++)
            {
                VMObstacle next = null;
                for (int x = x1; x < x2; x++)
                {
                    int tRoom = (ushort)Map[x + y * Width];
                    if (tRoom != room)
                    {
                        if (next != null)
                        {
                            next.x2 += 16;
                        }
                        else
                        {
                            next = new VMObstacle((x << 4) - 3, (y << 4) - 3, (x << 4) + 19, (y << 4) + 19);
                            result.Add(next);
                        }
                    }
                    else
                    {
                        if (next != null)
                        {
                            next = null;
                        }
                    }
                }
            }
            return(result);
        }
コード例 #6
0
ファイル: VMContext.cs プロジェクト: Ne-Ice/FreeSims
        public VMPlacementResult GetObjPlace(VMEntity target, LotTilePos pos, Direction dir)
        {
            //ok, this might be confusing...
            short allowedHeights = target.GetValue(VMStackObjectVariable.AllowedHeightFlags);
            short weight         = target.GetValue(VMStackObjectVariable.Weight);
            bool  noFloor        = (allowedHeights & 1) == 0;

            var  flags        = (VMEntityFlags)target.GetValue(VMStackObjectVariable.Flags);
            bool allowAvatars = ((flags & VMEntityFlags.DisallowPersonIntersection) == 0) && ((flags & VMEntityFlags.AllowPersonIntersection) > 0);

            VMObstacle footprint = target.GetObstacle(pos, dir);
            ushort     room      = GetRoomAt(pos);

            VMPlacementError status    = (noFloor)?VMPlacementError.HeightNotAllowed:VMPlacementError.Success;
            VMEntity         statusObj = null;

            if (footprint == null || pos.Level < 1)
            {
                return(new VMPlacementResult {
                    Status = status
                });
            }

            var objs = RoomInfo[room].Entities;

            foreach (var obj in objs)
            {
                if (obj.MultitileGroup == target.MultitileGroup || (obj is VMAvatar && allowAvatars) ||
                    (target.GhostImage && target.GhostOriginal != null && target.GhostOriginal.Objects.Contains(obj)))
                {
                    continue;
                }
                var oFoot = obj.Footprint;

                if (oFoot != null && oFoot.Intersects(footprint) &&
                    (!(target.ExecuteEntryPoint(5, this, true, obj, new short[] { obj.ObjectID, 0, 0, 0 }) ||
                       obj.ExecuteEntryPoint(5, this, true, target, new short[] { target.ObjectID, 0, 0, 0 })))
                    )
                {
                    statusObj = obj;
                    status    = VMPlacementError.CantIntersectOtherObjects;

                    //this object is technically solid. Check if we can place on top of it
                    if (allowedHeights > 1 && obj.TotalSlots() > 0 && (obj.GetSlot(0) == null || obj.GetSlot(0) == target))
                    {
                        //first check if we have a slot 0, which is what we place onto. then check if it's empty,
                        //then check if the object can support this one's weight.
                        //we also need to make sure that the height of this specific slot is allowed.

                        if (((1 << (obj.GetSlotHeight(0) - 1)) & allowedHeights) > 0)
                        {
                            if (weight < obj.GetValue(VMStackObjectVariable.SupportStrength))
                            {
                                return(new VMPlacementResult(VMPlacementError.Success, obj));
                            }
                            else
                            {
                                status = VMPlacementError.CantSupportWeight;
                            }
                        }
                        else
                        {
                            if (noFloor)
                            {
                                if ((allowedHeights & (1 << 3)) > 0)
                                {
                                    status = VMPlacementError.CounterHeight;
                                }
                                else
                                {
                                    status = (obj.GetSlotHeight(0) == 8) ? VMPlacementError.CannotPlaceComputerOnEndTable : VMPlacementError.HeightNotAllowed;
                                }
                            }
                        }
                    }
                }
            }
            return(new VMPlacementResult(status, statusObj));
        }
コード例 #7
0
        public List <VMObstacle> GenerateRoomObs(ushort room, sbyte level, Rectangle bounds, VMContext context)
        {
            var result = new List <VMObstacle>();

            if (room == 0)
            {
                bounds = new Rectangle(1, 1, Width - 2, Height - 2);
            }
            var x1 = Math.Max(0, bounds.X - 1);
            var x2 = Math.Min(Width, bounds.Right + 1);
            var y1 = Math.Max(0, bounds.Y - 1);
            var y2 = Math.Min(Height, bounds.Bottom + 1);

            for (int y = y1; y < y2; y++)
            {
                VMObstacle next = null;
                for (int x = x1; x < x2; x++)
                {
                    uint tRoom = Map[x + y * Width];
                    if ((ushort)tRoom != room && ((tRoom >> 16) & 0x7FFF) != room)
                    {
                        //is there a door on this tile?
                        var door = (context.ObjectQueries.GetObjectsAt(LotTilePos.FromBigTile((short)x, (short)y, level))?.FirstOrDefault(
                                        o => ((VMEntityFlags2)(o.GetValue(VMStackObjectVariable.FlagField2)) & VMEntityFlags2.ArchitectualDoor) > 0)
                                    );
                        if (door != null)
                        {
                            //ok... is is a portal to this room? block all sides that are not a portal to this room
                            var otherSide = door.MultitileGroup.Objects.FirstOrDefault(o => context.GetObjectRoom(o) == room && o.EntryPoints[15].ActionFunction != 0);
                            if (otherSide != null)
                            {
                                //make a hole for this door
                                if (next != null)
                                {
                                    next = null;
                                }
                                // note: the sims 1 stops here. this creates issues where sims can walk through doors in some circumstance
                                // eg. two doors back to back into the same room. The sim will not perform a room route to the middle room, they will just walk through the door.
                                // like, through it. This also works for pools but some additional rules prevent you from doing anything too silly.
                                // we want to create 1 unit thick walls blocking each non-portal side.

                                // todo: fix for this
                                continue;
                            }
                        }

                        if (next != null)
                        {
                            next.x2 += 16;
                        }
                        else
                        {
                            next = new VMObstacle((x << 4) - 3, (y << 4) - 3, (x << 4) + 19, (y << 4) + 19);
                            result.Add(next);
                        }
                    }
                    else
                    {
                        if (next != null)
                        {
                            next = null;
                        }
                    }
                }
            }
            OptimizeObstacles(result);
            return(result);
        }
コード例 #8
0
 public VMExtendRegion(int a, int b, VMObstacle rect)
 {
     this.a    = a;
     this.b    = b;
     this.rect = rect;
 }
コード例 #9
0
        // STATIC

        private static void GenerateBezierControl(VMIPathSegment fromSegI, VMIPathSegment toSegI,
                                                  VMWalkableRect from, VMWalkableRect to)
        {
            //find average direction line

            var fromSlice = new VMObstacle(from.x1 * 0x8000, from.y1 * 0x8000, from.x2 * 0x8000, from.y2 * 0x8000); //new VMObstacle(fromSegI.Source, fromSegI.Destination);
            var toSlice   = new VMObstacle(to.x1 * 0x8000, to.y1 * 0x8000, to.x2 * 0x8000, to.y2 * 0x8000);         //new VMObstacle(toSegI.Source, toSegI.Destination);

            if (fromSegI is VMPathBezierSegment)
            {
                var fromSeg = (VMPathBezierSegment)fromSegI;
                if (toSegI is VMPathBezierSegment)
                {
                    var toSeg    = (VMPathBezierSegment)toSegI;
                    var fromDiff = (fromSeg.D - fromSeg.A).ToVector2();
                    var toDiff   = (toSeg.D - toSeg.A).ToVector2();

                    //essentially normalizing, but keeping the lengths stored
                    var fromLength = fromDiff.Length();
                    var toLength   = toDiff.Length();
                    fromDiff /= fromLength;
                    toDiff   /= toLength;

                    //our control points should create a line with average direction between its bordering lines.
                    var avg = fromDiff + toDiff;
                    avg.Normalize();

                    var controlStrength = Math.Min(fromLength, toLength) / 2;
                    toSeg.B   = toSeg.A + (avg * toLength / 3).ToPoint();
                    fromSeg.C = fromSeg.D - (avg * fromLength / 3).ToPoint();

                    int  changed = 2;
                    bool testTo  = true;

                    int emergency = 0;
                    while (emergency++ < 1000 && changed-- > 0)
                    {
                        if (testTo)
                        {
                            //make sure to is within rect bounds
                            var n = toSlice.Closest(toSeg.B.X, toSeg.B.Y);
                            if (n != toSeg.B)
                            {
                                //if we changed, we'll need to check the other side again.
                                changed = 1;

                                //multiply the other side by the change factors here
                                var diff  = (toSeg.B - toSeg.A);
                                var diff2 = (n - toSeg.A);

                                var otherDiff = (fromSeg.C - fromSeg.D);
                                if (diff.X != 0)
                                {
                                    otherDiff.X = (int)(((long)otherDiff.X * diff2.X) / diff.X);
                                }
                                if (diff.Y != 0)
                                {
                                    otherDiff.Y = (int)(((long)otherDiff.Y * diff2.Y) / diff.Y);
                                }

                                toSeg.B = n;

                                fromSeg.C = fromSeg.D + otherDiff;
                            }
                        }
                        else
                        {
                            //make sure from is within rect bounds
                            var n = fromSlice.Closest(fromSeg.C.X, fromSeg.C.Y);
                            if (n != fromSeg.C)
                            {
                                //if we changed, we'll need to check the other side again.
                                changed = 1;

                                //multiply the other side by the change factors here
                                var diff  = (fromSeg.C - fromSeg.D);
                                var diff2 = (n - fromSeg.D);

                                var otherDiff = (toSeg.B - toSeg.A);
                                if (diff.X != 0)
                                {
                                    otherDiff.X = (int)(((long)otherDiff.X * diff2.X) / diff.X);
                                }
                                if (diff.Y != 0)
                                {
                                    otherDiff.Y = (int)(((long)otherDiff.Y * diff2.Y) / diff.Y);
                                }

                                fromSeg.C = n;
                                toSeg.B   = toSeg.A + otherDiff;
                            }
                        }
                        testTo = !testTo;
                    }
                }
                else
                {
                    var fromDiff = (fromSeg.D - fromSeg.A).ToVector2();
                    var toDiff   = (toSegI.Destination - toSegI.Source).ToVector2();

                    //essentially normalizing, but keeping the lengths stored
                    var fromLength = fromDiff.Length();
                    var toLength   = toDiff.Length();
                    fromDiff /= fromLength;
                    toDiff   /= toLength;

                    //our control points should create a line with average direction between its bordering lines.
                    fromSeg.C = fromSeg.D - (toDiff * fromLength / 3).ToPoint();
                    fromSeg.C = fromSlice.Closest(fromSeg.C.X, fromSeg.C.Y);
                }
            }
            else if (toSegI is VMPathBezierSegment)
            {
                var toSeg    = (VMPathBezierSegment)toSegI;
                var fromDiff = (fromSegI.Destination - fromSegI.Source).ToVector2();
                var toDiff   = (toSeg.D - toSeg.A).ToVector2();

                //essentially normalizing, but keeping the lengths stored
                var fromLength = fromDiff.Length();
                var toLength   = toDiff.Length();
                fromDiff /= fromLength;
                toDiff   /= toLength;

                //our control points should create a line with average direction between its bordering lines.
                toSeg.B = toSeg.A + (fromDiff * toLength / 3).ToPoint();
                toSeg.B = toSlice.Closest(toSeg.B.X, toSeg.B.Y);
            }
        }
コード例 #10
0
 private List <VMObstacle> EdgeSet(VMObstacle search)
 {
     return(TreeMap.OnEdge(search));
 }
コード例 #11
0
 private List <VMObstacle> IntersectSet(VMObstacle search)
 {
     return(TreeMap.AllIntersect(search));
 }
コード例 #12
0
        private VMExtendRectResult ExtendRect(int dir, int d1, int d2, int p)
        {
            int        bestN = ((dir + 1) % 4 < 2) ? int.MinValue : int.MaxValue;
            var        best  = new List <VMExtendRegion>();
            VMObstacle extendRange;

            switch (dir)
            {
            case 0:     //top
                extendRange = new VMObstacle(d1, int.MinValue, d2, p);
                foreach (VMObstacle r in IntersectSet(extendRange))
                {
                    if (r.y2 > p)
                    {
                        continue;               //bottom of rect lower than start point = no hit
                    }
                    if (r.x1 >= d2 || r.x2 <= d1)
                    {
                        continue;                               //does not intersect
                    }
                    if (r.y2 > bestN)
                    {
                        bestN = r.y2;
                        best.Clear();
                        best.Add(new VMExtendRegion(r.x1, r.x2, r));
                    }
                    else if (r.y2 == bestN)
                    {
                        best.Add(new VMExtendRegion(r.x1, r.x2, r));
                    }
                }
                break;

            case 1:     //right
                extendRange = new VMObstacle(p, d1, int.MaxValue, d2);
                foreach (VMObstacle r in IntersectSet(extendRange))
                {
                    if (r.x1 < p)
                    {
                        continue;               //left of rect lefter than start point = no hit
                    }
                    if (r.y1 >= d2 || r.y2 <= d1)
                    {
                        continue;                               //does not intersect
                    }
                    if (r.x1 < bestN)
                    {
                        bestN = r.x1;
                        best.Clear();
                        best.Add(new VMExtendRegion(r.y1, r.y2, r));
                    }
                    else if (r.x1 == bestN)
                    {
                        best.Add(new VMExtendRegion(r.y1, r.y2, r));
                    }
                }
                break;

            case 2:     //bottom
                extendRange = new VMObstacle(d1, p, d2, int.MaxValue);
                foreach (VMObstacle r in IntersectSet(extendRange))
                {
                    if (r.y1 < p)
                    {
                        continue;               //top of rect higher than start point = no hit
                    }
                    if (r.x1 >= d2 || r.x2 <= d1)
                    {
                        continue;                               //does not intersect
                    }
                    if (r.y1 < bestN)
                    {
                        bestN = r.y1;
                        best.Clear();
                        best.Add(new VMExtendRegion(r.x1, r.x2, r));
                    }
                    else if (r.y1 == bestN)
                    {
                        best.Add(new VMExtendRegion(r.x1, r.x2, r));
                    }
                }
                break;

            case 3:     //left
                extendRange = new VMObstacle(int.MinValue, d1, p, d2);
                foreach (VMObstacle r in IntersectSet(extendRange))
                {
                    if (r.x2 > p)
                    {
                        continue;               //right of rect righter than start point = no hit
                    }
                    if (r.y1 >= d2 || r.y2 <= d1)
                    {
                        continue;                               //does not intersect
                    }
                    if (r.x2 > bestN)
                    {
                        bestN = r.x2;
                        best.Clear();
                        best.Add(new VMExtendRegion(r.y1, r.y2, r));
                    }
                    else if (r.x2 == bestN)
                    {
                        best.Add(new VMExtendRegion(r.y1, r.y2, r));
                    }
                }
                break;
            }
            return(new VMExtendRectResult {
                Best = best, BestN = bestN
            });
        }