Пример #1
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);
        }
Пример #2
0
        public VMPlacementResult ChangePosition(LotTilePos pos, Direction direction, VMContext context, VMPlaceRequestFlags flags)
        {
            if (pos.Level > context.Architecture.Stories)
            {
                return(new VMPlacementResult(VMPlacementError.NotAllowedOnFloor));
            }
            if (Objects.Count == 0)
            {
                return(new VMPlacementResult(VMPlacementError.Success));
            }

            var count = Objects.Count;

            VMEntity[]   OldContainers = new VMEntity[count];
            short[]      OldSlotNum    = new short[count];
            bool[]       RoomChange    = new bool[count];
            LotTilePos[] Targets       = new LotTilePos[count];
            for (int i = 0; i < count; i++)
            {
                OldContainers[i] = Objects[i].Container;
                OldSlotNum[i]    = Objects[i].ContainerSlot;
            }

            int Dir = 0;

            switch (direction)
            {
            case Direction.NORTH:
                Dir = 0; break;

            case Direction.EAST:
                Dir = 2; break;

            case Direction.SOUTH:
                Dir = 4; break;

            case Direction.WEST:
                Dir = 6; break;
            }

            Matrix rotMat = Matrix.CreateRotationZ((float)(Dir * Math.PI / 4.0));

            VMPlacementResult[] places = new VMPlacementResult[count];

            var bObj     = BaseObject;
            var bOff     = Offsets[Objects.IndexOf(BaseObject)];
            var leadOff  = new Vector3(bOff.x, bOff.y, 0);
            var offTotal = new Vector3();

            if (pos != LotTilePos.OUT_OF_WORLD)
            {
                for (int i = 0; i < count; i++)
                {
                    var sub = Objects[i];
                    var off = new Vector3(Offsets[i].x, Offsets[i].y, 0);
                    off       = Vector3.Transform(off - leadOff, rotMat);
                    offTotal += off;

                    var offPos = new LotTilePos((short)Math.Round(pos.x + off.X), (short)Math.Round(pos.y + off.Y), (sbyte)(pos.Level + Offsets[i].Level));
                    Targets[i] = offPos;
                    var roomChange = context.GetRoomAt(offPos) != context.GetObjectRoom(sub) || OldContainers[i] != null;
                    RoomChange[i] = roomChange;
                    sub.PrePositionChange(context, roomChange);
                    places[i] = sub.PositionValid(offPos, direction, context, flags);

                    if (places[i].Status != VMPlacementError.Success)
                    {
                        //go back to where we started: we're no longer out of world.
                        for (int j = 0; j <= i; j++)
                        {
                            //need to restore slot we were in
                            if (j < OldContainers.Length && OldContainers[j] != null)
                            {
                                OldContainers[j].PlaceInSlot(Objects[j], OldSlotNum[j], false, context);
                            }
                            Objects[j].PositionChange(context, false, RoomChange[j]);
                        }
                        return(places[i]);
                    }
                    else if (places[i].Object != null && !sub.StaticFootprint && !roomChange)
                    {
                        //edge case: we will be placed in a slot, but have a dynamic footprint still in the room.
                        //when placed in a slot, our collision footprint should become null.
                        //Static footprints are deleted before every move, but dynamic footprints are only removed when there is a room change.
                        //if the flag was not set, then we still need to remove the dynamic footprint for this object entering a slot.
                        sub.Footprint?.Unregister();
                    }
                }
            }
            else
            {
                for (int i = 0; i < count; i++)
                {
                    Objects[i].PrePositionChange(context, true);
                    RoomChange[i] = true;
                    var off = new Vector3(Offsets[i].x, Offsets[i].y, 0);
                    off       = Vector3.Transform(off - leadOff, rotMat);
                    offTotal += off;
                }
            }

            offTotal /= count; //this is now the average offset
            //verification success

            Matrix?groundAlign = null;

            //ground align
            if (VM.UseWorld && pos != LotTilePos.OUT_OF_WORLD && false) //wip ground alignment for carpool. currently disabled!
            {
                //find alignment
                var bp    = context.Blueprint;
                var spos  = (new Vector3(pos.x, pos.y, 0) + offTotal) / 16;
                var tBase = new Vector3(spos.X, bp.InterpAltitude(spos), spos.Y);
                var ty    = new Vector3(spos.X, bp.InterpAltitude(spos + new Vector3(0, 1 / 32f, 0)), spos.Y + 1 / 32f);
                var tx    = new Vector3(spos.X + 1 / 32f, bp.InterpAltitude(spos + new Vector3(1 / 32f, 0, 0)), spos.Y);

                var front = ty - tBase;
                front.Normalize();
                var side = tx - tBase;
                side.Normalize();
                var top = Vector3.Cross(front, side);
                groundAlign = Matrix.CreateLookAt(Vector3.Zero, new Vector3(front.X, front.Y, front.Z), top);
                //more direct coordinate creation - messes up with diagonally sloped tiles but could be useful for something else
                //groundAlign = new Matrix(new Vector4(side, 0), new Vector4(top, 0), new Vector4(front, 0), new Vector4(0, 0, 0, 1));
                if (pos != LotTilePos.OUT_OF_WORLD)
                {
                }
            }

            for (int i = 0; i < count; i++)
            {
                var sub = Objects[i];

                var offPos = (pos == LotTilePos.OUT_OF_WORLD) ?
                             LotTilePos.OUT_OF_WORLD :
                             Targets[i];

                if (VM.UseWorld)
                {
                    if (count > 0)
                    {
                        sub.WorldUI.MTOffset = Vector3.Transform(new Vector3(Offsets[i].x, Offsets[i].y, 0) - leadOff, rotMat) - offTotal;
                    }
                    if (groundAlign != null)
                    {
                        var mt = sub.WorldUI.MTOffset;
                        mt = new Vector3(mt.X / 16, mt.Z, mt.Y / 16);
                        mt = Vector3.Transform(mt, groundAlign.Value);
                        mt = new Vector3(mt.X, mt.Z, mt.Y) * 16;
                        sub.WorldUI.MTOffset = mt;
                    }
                    sub.WorldUI.GroundAlign = groundAlign;
                }
                sub.SetIndivPosition(offPos, direction, context, places[i]);
            }


            if (groundAlign != null)
            {
                //retarget floor
                var ctr = new Vector3(Offsets[0].x, Offsets[0].y, 0) - leadOff - offTotal;
                for (int i = 0; i < count; i++)
                {
                    var sub = Objects[i];
                    var mo  = Vector3.Transform(new Vector3(Offsets[i].x, Offsets[i].y, 0) - leadOff, rotMat) - offTotal;
                    var mo2 = sub.WorldUI.MTOffset;
                    if (mo != mo2)
                    {
                    }
                    mo2.Z = 0;
                    sub.VisualPosition = new Vector3(sub.VisualPosition.X, sub.VisualPosition.Y, 0) + (mo2 - mo) / 16;
                }
            }

            for (int i = 0; i < count; i++)
            {
                Objects[i].PositionChange(context, false, RoomChange[i]);
            }
            return(new VMPlacementResult(VMPlacementError.Success));
        }