public static void RestoreTerrain(VM vm, RestoreLotType type = RestoreLotType.Normal) { //take center of lotstate RestoreTerrain(vm, vm.TSOState.Terrain.BlendN[1, 1], vm.TSOState.Terrain.Roads[1, 1], type); RestoreHeight(vm, vm.TSOState.Terrain, 1, 1); }
public static void EnsureCoreObjects(VM vm, RestoreLotType type) { var del = MovePositions.Where(x => x.Type != RestoreLotType.Generic && x.Type != type).Select(x => EntityByGUID(vm, x.GUID)).Where(x => x != null).ToList(); foreach (var ent in del) { ent.Delete(true, vm.Context); } var fail = MovePositions.Where(x => { //find an object of this type var ent = EntityByGUID(vm, x.GUID); return((x.Type == type || x.Type == RestoreLotType.Generic) && (ent == null || ent.Position == LotTilePos.OUT_OF_WORLD)); }); if (fail.Count() > 0) { PositionLandmarkObjects(vm, type); } }
/// <summary> /// Positions the Landmark objects depending on the lot direction. (npc/car portals, bin, mailbox, phone) /// </summary> /// <param name="vm">The VM.</param> public static void PositionLandmarkObjects(VM vm, RestoreLotType type) { var arch = vm.Context.Architecture; var lotSInfo = vm.TSOState.Size; var lotSize = lotSInfo & 255; var lotFloors = ((lotSInfo >> 8) & 255) + 2; var lotDir = (lotSInfo >> 16); var dim = VMBuildableAreaInfo.BuildableSizes[lotSize]; //need to rotate the lot dir towards the road. bit weird cos we're rotating a rectangle var w = arch.Width; var h = arch.Height; //little bit different from the array in VMContext. Want the tile positions outside buildable area //so min x and y are 5 instead of 6. var corners = new Vector2[] { new Vector2(5, 5), // top, default orientation new Vector2(w - 7, 5), // right new Vector2(w - 7, h - 7), // bottom new Vector2(5, h - 7) // left }; var perpIncrease = new Vector2[] { new Vector2(0, -1), //bottom left road side new Vector2(1, 0), new Vector2(0, 1), new Vector2(-1, 0) }; //rotation 0: move perp from closer point to top bottom -> left (90 degree ccw of perp) //rotation 1: choose closer pt to top left->top (90 degree ccw of perp) //rotation 2: choose closer pt to top top->right (90 degree cw of perp) var pt1 = corners[(lotDir + 2) % 4]; var pt2 = corners[(lotDir + 3) % 4]; var ctr = (pt1 + pt2) / 2; //ok. var xperp = perpIncrease[(lotDir + 1) % 4]; var yperp = perpIncrease[(lotDir + 2) % 4]; //move relative position objs foreach (var pos in MovePositions) { var rpos = ctr + (pos.X * xperp) + (pos.Y * yperp); var ent = EntityByGUID(vm, pos.GUID); if (type != RestoreLotType.Blank && ent == null && (pos.Type == type || pos.Type == RestoreLotType.Generic)) { ent = vm.Context.CreateObjectInstance(pos.GUID, LotTilePos.OUT_OF_WORLD, Direction.NORTH).BaseObject; } if (ent != null) { var result = ent.MultitileGroup.BaseObject.SetPosition(LotTilePos.FromBigTile((short)rpos.X, (short)rpos.Y, 1), (Direction)(1 << ((lotDir * 2 + pos.DirOff) % 8)), vm.Context, VMPlaceRequestFlags.AllowIntersection); if (result.Status != VMPlacementError.Success) { // if we can't place the object, put it oow. ent.MultitileGroup.BaseObject.SetPosition(LotTilePos.OUT_OF_WORLD, (Direction)(1 << ((lotDir * 2 + pos.DirOff) % 8)), vm.Context); } } } // finally, must position npc portals. These are on the sidewalk, but at the far edge of the lot. // ped, npc1, npc2 (0x81E6BEF9, 0x23BC2034, 0x4E57C380) // if there is water on the space we can't intersect it :( // for now just choose pavement corners. These are safe from being in water. var npc1 = EntityByGUID(vm, 0x23BC2034); if (npc1 != null) { npc1.SetPosition(LotTilePos.FromBigTile((short)pt1.X, (short)pt1.Y, 1), (Direction)(1 << ((lotDir * 2 + 0) % 8)), vm.Context); } var npc2 = EntityByGUID(vm, 0x4E57C380); if (npc2 != null) { npc2.SetPosition(LotTilePos.FromBigTile((short)pt2.X, (short)pt2.Y, 1), (Direction)(1 << ((lotDir * 2 + 0) % 8)), vm.Context); } var ped = EntityByGUID(vm, 0x81E6BEF9); if (ped != null) { ped.SetPosition(LotTilePos.FromBigTile((short)ctr.X, (short)ctr.Y, 1), (Direction)(1 << ((lotDir * 2 + 0) % 8)), vm.Context); } var rPos = ctr + (-13 * xperp) + (2 * yperp); if (ped != null) { StampTerrainmap(arch, CarDirtRoad, (short)rPos.X, (short)rPos.Y, xperp, yperp); } }
public GUIDToPosition(uint guid, short x, short y, int dirOff, RestoreLotType type = RestoreLotType.Generic) { GUID = guid; X = x; Y = y; DirOff = dirOff; Type = type; }
public static void RestoreTerrain(VM vm, TerrainBlend blend, byte roads, RestoreLotType type) { var arch = vm.Context.Architecture; arch.DisableClip = true; var baseB = blend.Base; arch.Terrain.LightType = (baseB == TerrainType.WATER) ? TerrainType.SAND : blend.Base; arch.Terrain.DarkType = (blend.Blend == TerrainType.WATER) ? blend.Base : blend.Blend; arch.Terrain.GenerateGrassStates(); //clear all previous roads/sea VMArchitectureTools.FloorPatternRect(arch, new Rectangle(0, 0, arch.Width, 5), 0, 0, 1); VMArchitectureTools.FloorPatternRect(arch, new Rectangle(arch.Width - 7, 0, 7, arch.Height), 0, 0, 1); VMArchitectureTools.FloorPatternRect(arch, new Rectangle(0, arch.Height - 7, arch.Width, 7), 0, 0, 1); VMArchitectureTools.FloorPatternRect(arch, new Rectangle(0, 0, 5, arch.Height), 0, 0, 1); if (baseB == TerrainType.WATER) { //... VMArchitectureTools.FloorPatternRect(arch, new Rectangle(1, 1, arch.Width - 3, arch.Height - 3), 0, 65534, 1); } //blend flags start at top left, then go clockwise. (top right, bottom right..) if ((blend.WaterFlags & 1) > 0) { FillTileLine(arch, W, 0, 0, 1, WaterLineSegments, false); } if ((blend.WaterFlags & 4) > 0) { FillTileLine(arch, W, 0, 0, 1, WaterLineSegments, true); } if ((blend.WaterFlags & 16) > 0) { FillTileLine(arch, W, (short)(arch.Width - 1), 0, 1, WaterLineSegments, false); } if ((blend.WaterFlags & 64) > 0) { FillTileLine(arch, W, 0, (short)(arch.Height - 1), 1, WaterLineSegments, true); } if ((blend.WaterFlags & 2) > 0) { FillTiles(arch, W, 1, 1, 1, 1, 1); } if ((blend.WaterFlags & 8) > 0) { FillTiles(arch, W, (short)(arch.Width - 2), 1, 1, 1, 1); } if ((blend.WaterFlags & 32) > 0) { FillTiles(arch, W, (short)(arch.Width - 2), (short)(arch.Height - 2), 1, 1, 1); } if ((blend.WaterFlags & 128) > 0) { FillTiles(arch, W, 1, (short)(arch.Height - 2), 1, 1, 1); } if ((blend.WaterFlags & 5) == 5) { StampTilemap(arch, TopWaterCorner, 1, 1, 1); } if ((blend.WaterFlags & 20) == 20) { StampTilemap(arch, RightWaterCorner, (short)(arch.Width - 7), 1, 1); } if ((blend.WaterFlags & 80) == 80) { StampTilemap(arch, BottomWaterCorner, (short)(arch.Width - 7), (short)(arch.Height - 7), 1); } if ((blend.WaterFlags & 65) == 65) { StampTilemap(arch, LeftWaterCorner, 1, (short)(arch.Height - 7), 1); } /* * * if ((blend.WaterFlags & 1) > 0) VMArchitectureTools.FloorPatternRect(arch, new Rectangle(1, 1, 4, arch.Height - 2), 0, 65534, 1); * if ((blend.WaterFlags & 2) > 0) VMArchitectureTools.FloorPatternRect(arch, new Rectangle(1, 1, arch.Width-2, 4), 0, 65534, 1); * if ((blend.WaterFlags & 4) > 0) VMArchitectureTools.FloorPatternRect(arch, new Rectangle(arch.Width-5, 1, 4, arch.Height - 2), 0, 65534, 1); * if ((blend.WaterFlags & 8) > 0) VMArchitectureTools.FloorPatternRect(arch, new Rectangle(1, arch.Height-5, arch.Width-2, 4), 0, 65534, 1); * */ //hard blends into the next terrain type FillTerrainRect(arch, new Rectangle(0, 0, 1, arch.Height - 1), (byte)(((blend.AdjFlags & 1) > 0) ? 255 : 0)); FillTerrainRect(arch, new Rectangle(0, 0, arch.Width - 1, 1), (byte)(((blend.AdjFlags & 4) > 0) ? 255 : 0)); FillTerrainRect(arch, new Rectangle(arch.Width - 2, 0, 1, arch.Height - 1), (byte)(((blend.AdjFlags & 16) > 0) ? 255 : 0)); FillTerrainRect(arch, new Rectangle(0, arch.Height - 2, arch.Width - 1, 1), (byte)(((blend.AdjFlags & 64) > 0) ? 255 : 0)); /* * FillTerrainRect(arch, new Rectangle(0, 0, 1, 1), (byte)(((blend.AdjFlags & 2) > 0) ? 255 : 0)); * FillTerrainRect(arch, new Rectangle(arch.Width - 2, 0, 1, 1), (byte)(((blend.AdjFlags & 8) > 0) ? 255 : 0)); * FillTerrainRect(arch, new Rectangle(arch.Width - 2, arch.Height - 2, 1, 1), (byte)(((blend.AdjFlags & 32) > 0) ? 255 : 0)); * FillTerrainRect(arch, new Rectangle(0, arch.Height - 2, 1, 1), (byte)(((blend.AdjFlags & 128) > 0) ? 255 : 0)); */ //smooth blends into the next terrain type ApplyTerrainBlend(arch, RotateByte(blend.AdjFlags, 0), new Rectangle(0, 0, arch.Width - 1, 24), 255, 0, -11, new Point[] { new Point(0, 0), new Point(arch.Width - 1, 0) }, new float[] { (135f / 180f) * (float)Math.PI, (225f / 180f) * (float)Math.PI }, new float[] { (15f / 180f) * (float)Math.PI, (-15f / 180f) * (float)Math.PI }); ApplyTerrainBlend(arch, RotateByte(blend.AdjFlags, 6), new Rectangle(arch.Width - 25, 0, 24, arch.Height - 1), 0, 11, 0, new Point[] { new Point(arch.Width - 1, 0), new Point(arch.Width - 1, arch.Height - 1) }, new float[] { (225f / 180f) * (float)Math.PI, (315f / 180f) * (float)Math.PI }, new float[] { (15f / 180f) * (float)Math.PI, (-15f / 180f) * (float)Math.PI }); ApplyTerrainBlend(arch, RotateByte(blend.AdjFlags, 4), new Rectangle(0, arch.Height - 25, arch.Width - 1, 24), 0, 0, 11, new Point[] { new Point(arch.Width - 1, arch.Height - 1), new Point(0, arch.Height - 1) }, new float[] { (315f / 180f) * (float)Math.PI, (45f / 180f) * (float)Math.PI }, new float[] { (15f / 180f) * (float)Math.PI, (-15f / 180f) * (float)Math.PI }); ApplyTerrainBlend(arch, RotateByte(blend.AdjFlags, 2), new Rectangle(0, 0, 24, arch.Height - 1), 255, -11, 0, new Point[] { new Point(0, arch.Height - 1), new Point(0, 0) }, new float[] { (45f / 180f) * (float)Math.PI, (135f / 180f) * (float)Math.PI }, new float[] { (15f / 180f) * (float)Math.PI, (-15f / 180f) * (float)Math.PI }); RestoreRoad(vm, roads); if (vm.GetGlobalValue(11) == -1) { //set road dir. should only really do this FIRST EVER time, then road dir changes after are manual and rotate the contents of the lot. vm.TSOState.Size &= 0xFFFF; vm.TSOState.Size |= PickRoadDir(roads) << 16; } PositionLandmarkObjects(vm, type); arch.SignalTerrainRedraw(); arch.DisableClip = false; }