public bool QuadOutOfArea(Quad2 quad) { if (mode != LoadMode.NewGame && mode != LoadMode.LoadGame && mode != LoadMode.NewGameFromScenario) { return(false); } var result = CrossTheLine.IsCrossingLineProhibited(); if (result) { do { }while (!Monitor.TryEnter(_lock, SimulationManager.SYNCHRONIZE_TIMEOUT)); try { RedirectionHelper.RevertJumpTo(_originalPtr, _state); result = Singleton <GameAreaManager> .instance.QuadOutOfArea(quad); RedirectionHelper.PatchJumpTo(_originalPtr, _detourPtr); } finally { Monitor.Exit(_lock); } } return(result); }
public static bool ApplyZoning(ZoneTool z, ushort blockIndex, ref ZoneBlock zoneBlock, Quad2 quad2) { var parameters = new object[] { blockIndex, zoneBlock, quad2 }; bool b = (bool)z.GetType().GetMethod("ApplyZoning", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(ZoneBlock).MakeByRefType(), typeof(Quad2) }, null).Invoke(z, parameters); zoneBlock = (ZoneBlock)parameters[1]; return b; }
private static float GetSideOffset(ushort vehicleID, ref Vehicle vehicleData, ref Vehicle.Frame frameData) { VehicleInfo vehicleInfo = vehicleData.Info; Vector3 position = frameData.m_position; Vector2 xz = VectorUtils.XZ(frameData.m_position); float y = position.y; Quaternion rotation = frameData.m_rotation; Vector3 size = vehicleInfo.m_generatedInfo.m_size; float vehicleTopY = y + vehicleInfo.m_generatedInfo.m_size.y - vehicleInfo.m_generatedInfo.m_negativeHeight; Vector2 forwardDir = VectorUtils.XZ(rotation * Vector3.forward).normalized; Vector2 rightDir = VectorUtils.XZ(rotation * Vector3.right).normalized; Quad2 passingQuad = new Quad2 { a = xz - 0.5f * size.z * forwardDir - 0.5f * size.x * rightDir, b = xz - 0.5f * size.z * forwardDir + 0.5f * size.x * rightDir, c = xz + 0.75f * size.z * forwardDir + 0.5f * size.x * rightDir, d = xz + 0.75f * size.z * forwardDir - 0.5f * size.x * rightDir }; float halfWidth = size.x / 2; Quad2 quad01 = QuadUtils.GetSegmentQuad(vehicleData.m_targetPos0, vehicleData.m_targetPos1, halfWidth); Quad2 quad12 = QuadUtils.GetSegmentQuad(vehicleData.m_targetPos1, vehicleData.m_targetPos2, halfWidth); Vector2 quadMin = Vector2.Min(Vector2.Min(passingQuad.Min(), quad01.Min()), quad12.Min()); Vector2 quadMax = Vector2.Max(Vector2.Max(passingQuad.Max(), quad01.Max()), quad12.Max()); float yMin = Mathf.Min(Mathf.Min(vehicleData.m_targetPos0.y, vehicleData.m_targetPos1.y), Mathf.Min(vehicleData.m_targetPos2.y, vehicleData.m_targetPos3.y)); float yMax = Mathf.Max(Mathf.Max(vehicleData.m_targetPos0.y, vehicleData.m_targetPos1.y), Mathf.Max(vehicleData.m_targetPos2.y, vehicleData.m_targetPos3.y)); int minGridX = Math.Max((int)((quadMin.x - 72f) / 64f + 135f), 0); int minGridZ = Math.Max((int)((quadMin.y - 72f) / 64f + 135f), 0); int maxGridX = Math.Min((int)((quadMax.x + 72f) / 64f + 135f), 269); int maxGridZ = Math.Min((int)((quadMax.y + 72f) / 64f + 135f), 269); float minY = yMin - vehicleInfo.m_generatedInfo.m_negativeHeight - 2f; float maxY = yMax + vehicleInfo.m_generatedInfo.m_size.y + 2f; BuildingManager buildingManager = Singleton <BuildingManager> .instance; for (int gridZ = minGridZ; gridZ <= maxGridZ; gridZ++) { for (int gridX = minGridX; gridX <= maxGridX; gridX++) { ushort buildingID = buildingManager.m_buildingGrid[gridZ * 270 + gridX]; while (buildingID != 0) { bool overlap01 = buildingManager.m_buildings.m_buffer[buildingID].OverlapQuad(buildingID, quad01, minY, maxY, ItemClass.CollisionType.Terrain); bool overlap02 = buildingManager.m_buildings.m_buffer[buildingID].OverlapQuad(buildingID, quad12, minY, maxY, ItemClass.CollisionType.Terrain); if (overlap01 || overlap02) { return(0f); } buildingID = buildingManager.m_buildings.m_buffer[buildingID].m_nextGridBuilding; } } } return(20f); }
[MethodImpl(MethodImplOptions.NoInlining)] //to prevent inlining private static void TrySpreadFire(Quad2 quad, float minY, float maxY, ushort buildingID, ref Building buildingData, InstanceManager.Group group) { //this should never get reached. if (OptionsWrapper <Configuration> .Options.IsLoggingEnabled()) { Logger.dbgLog("try spread fire"); } }
public static Quad3 ToCS3D(this Quad2 q) { return(new Quad3( q.a.ToCS3D(), q.b.ToCS3D(), q.c.ToCS3D(), q.d.ToCS3D())); }
IEnumerator WaitAndSetInactive(float waitTime) { // Quad1 = GameObject.Find ("Quad1"); // Quad2 = GameObject.Find ("Quad2"); yield return(new WaitForSeconds(waitTime)); Quad1.SetActive(false); Quad2.SetActive(false); }
public new bool QuadOutOfArea(Quad2 quad) { //begin mod if (_isCrossingLineProhibited != null) { if (!(bool)_isCrossingLineProhibited.Invoke(null, new object[] {})) { return(false); } } //end mod ItemClass.Availability availability = Singleton <ToolManager> .instance.m_properties.m_mode; if ((availability & ItemClass.Availability.AssetEditor) != ItemClass.Availability.None) { //begin mod //end mod } else { bool flag = (availability & ItemClass.Availability.Editors) != ItemClass.Availability.None; Vector2 vector2_1 = quad.Min(); Vector2 vector2_2 = quad.Max(); //begin mod int num1 = Mathf.FloorToInt((float)(((double)vector2_1.x - 8.0) / 1920.0 + HALFGRID)); int num2 = Mathf.FloorToInt((float)(((double)vector2_1.y - 8.0) / 1920.0 + HALFGRID)); int num3 = Mathf.FloorToInt((float)(((double)vector2_2.x + 8.0) / 1920.0 + HALFGRID)); int num4 = Mathf.FloorToInt((float)(((double)vector2_2.y + 8.0) / 1920.0 + HALFGRID)); //end mod for (int z = num2; z <= num4; ++z) { for (int x = num1; x <= num3; ++x) { int area = this.GetArea(x, z); if (area == -2 || !flag && area <= 0) { //begin mod if (quad.Intersect(new Quad2() { a = new Vector2((float)(((double)x - HALFGRID) * 1920.0 - 8.0), (float)(((double)z - HALFGRID) * 1920.0 - 8.0)), b = new Vector2((float)(((double)x - HALFGRID) * 1920.0 - 8.0), (float)(((double)z - HALFGRID + 1.0) * 1920.0 + 8.0)), c = new Vector2((float)(((double)x - HALFGRID + 1.0) * 1920.0 + 8.0), (float)(((double)z - HALFGRID + 1.0) * 1920.0 + 8.0)), d = new Vector2((float)(((double)x - HALFGRID + 1.0) * 1920.0 + 8.0), (float)(((double)z - HALFGRID) * 1920.0 - 8.0)) })) { //end mod return(true); } } } } } return(false); }
// ========================================================================== GAME AREA COLLISION ========================================================================== public static bool IsQuadOutOfGameArea(Quad2 quad) { bool _result = false; if (Singleton <GameAreaManager> .instance.QuadOutOfArea(quad)) { _result = true; } return(_result); }
public static bool DoesTreeCollideWithTrees(Quad2 quad, float minY, float maxY, ItemClass.CollisionType collisionType, TreeInfo treeInfo) { bool _result = false; if (Singleton <TreeManager> .instance.OverlapQuad(quad, minY, maxY, collisionType, 0, 0u)) { _result = true; } return(_result); }
// ========================================================================== PROP COLLISION ========================================================================== public static bool DoesPropCollideWithProps(Quad2 quad, float minY, float maxY, ItemClass.CollisionType collisionType, PropInfo propInfo) { bool _result = false; if (Singleton <PropManager> .instance.OverlapQuad(quad, minY, maxY, collisionType, 0, 0)) { _result = true; } return(_result); }
private ushort CheckForParkingSpaces(Vector3 pos, float angle, int width, int length) { Vector2 a = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); Vector2 a2 = new Vector2(a.y, 0f - a.x); a *= (float)width * 4f; a2 *= (float)length * 4f; Vector2 vector = VectorUtils.XZ(pos); Quad2 quad = default(Quad2); quad.a = vector - a - a2; quad.b = vector + a - a2; quad.c = vector + a + a2; quad.d = vector - a + a2; BuildingManager instance = Singleton <BuildingManager> .instance; Vector2 vector3 = quad.Min(); Vector2 vector2 = quad.Max(); int num = Mathf.Max((int)((vector3.x - 72f) / 64f + 135f), 0); int num2 = Mathf.Max((int)((vector3.y - 72f) / 64f + 135f), 0); int num3 = Mathf.Min((int)((vector2.x + 72f) / 64f + 135f), 269); int num4 = Mathf.Min((int)((vector2.y + 72f) / 64f + 135f), 269); //bool result = false; for (int i = num2; i <= num4; i++) { for (int j = num; j <= num3; j++) { ushort num5 = instance.m_buildingGrid[i * 270 + j]; int num6 = 0; while (num5 != 0) { BuildingInfo info = instance.m_buildings.m_buffer[num5].Info; ItemClass.CollisionType collisionType = ItemClass.CollisionType.Zoned; if ((object)info != null && instance.m_buildings.m_buffer[num5].OverlapQuad(num5, quad, pos.y - 1000f, pos.y + 1000f, collisionType)) { if (info.m_buildingAI is ParkingSpaceAssetAI) { return(num5); } } num5 = instance.m_buildings.m_buffer[num5].m_nextGridBuilding; if (++num6 >= 49152) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } return((ushort)0); }
public void UpdateBlocks(Quad2 quad) { Vector2 vector2_1 = quad.Min(); Vector2 vector2_2 = quad.Max(); //begin mod int num1 = Mathf.Max((int)(((double)vector2_1.x - 46.0) / 64.0 + HALFGRID), 0); int num2 = Mathf.Max((int)(((double)vector2_1.y - 46.0) / 64.0 + HALFGRID), 0); int num3 = Mathf.Min((int)(((double)vector2_2.x + 46.0) / 64.0 + HALFGRID), GRIDSIZE - 1); int num4 = Mathf.Min((int)(((double)vector2_2.y + 46.0) / 64.0 + HALFGRID), GRIDSIZE - 1); //end mod for (int index1 = num2; index1 <= num4; ++index1) { for (int index2 = num1; index2 <= num3; ++index2) { //begin mod ushort num5 = this.m_zoneGrid[index1 * GRIDSIZE + index2]; //end mod int num6 = 0; while ((int)num5 != 0) { Vector3 v = this.m_blocks.m_buffer[(int)num5].m_position; if ((double)Mathf.Max(Mathf.Max(vector2_1.x - 46f - v.x, vector2_1.y - 46f - v.z), Mathf.Max((float)((double)v.x - (double)vector2_2.x - 46.0), (float)((double)v.z - (double)vector2_2.y - 46.0))) < 0.0 && ((int)this.m_blocks.m_buffer[(int)num5].m_flags & 3) == 1) { int rowCount = this.m_blocks.m_buffer[(int)num5].RowCount; float f = this.m_blocks.m_buffer[(int)num5].m_angle; Vector2 vector2_3 = new Vector2(Mathf.Cos(f), Mathf.Sin(f)) * 8f; Vector2 vector2_4 = new Vector2(vector2_3.y, -vector2_3.x); Vector2 vector2_5 = VectorUtils.XZ(v); if (quad.Intersect(new Quad2() { a = vector2_5 - 4f * vector2_3 - 4f * vector2_4, b = vector2_5 + 0.0f * vector2_3 - 4f * vector2_4, c = vector2_5 + 0.0f * vector2_3 + (float)(rowCount - 4) * vector2_4, d = vector2_5 - 4f * vector2_3 + (float)(rowCount - 4) * vector2_4 })) { this.m_updatedBlocks[(int)num5 >> 6] |= (ulong)(1L << (int)num5); this.m_blocksUpdated = true; } } num5 = this.m_blocks.m_buffer[(int)num5].m_nextGridBlock; if (++num6 >= 49152) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace); break; } } } } }
public static bool CheckTreeBlocked(Quad2 quad, float minY, float maxY, ItemClass.CollisionType collisionType, TreeInfo treeInfo) { bool _result = false; if (Singleton <NetManager> .instance.OverlapQuad(quad, minY, maxY, collisionType, treeInfo.m_class.m_layer, 0, 0, 0)) { _result = true; } if (Singleton <BuildingManager> .instance.OverlapQuad(quad, minY, maxY, collisionType, treeInfo.m_class.m_layer, 0, 0, 0)) { _result = true; } return(_result); }
private static void CheckOverlap(ref TreeInstance tree, uint treeID) //this method reproduces original code for most part to prevent exceptions { TreeInfo info = tree.Info; if (info == null) { return; } ItemClass.CollisionType collisionType = ((int)tree.m_flags & 32) != 0 ? ItemClass.CollisionType.Elevated : ItemClass.CollisionType.Terrain; Randomizer randomizer = new Randomizer(treeID); float num1 = info.m_minScale + (float)((double)randomizer.Int32(10000U) * ((double)info.m_maxScale - (double)info.m_minScale) * 9.99999974737875E-05); float num2 = info.m_generatedInfo.m_size.y * num1; Vector3 position = tree.Position; float minY = position.y; float maxY = position.y + num2; float num3 = !tree.Single ? 4.5f : 0.3f; Quad2 quad = new Quad2(); Vector2 vector2 = VectorUtils.XZ(position); quad.a = vector2 + new Vector2(-num3, -num3); quad.b = vector2 + new Vector2(-num3, num3); quad.c = vector2 + new Vector2(num3, num3); quad.d = vector2 + new Vector2(num3, -num3); bool flag = false; if (Singleton <NetManager> .instance.OverlapQuad(quad, minY, maxY, collisionType, info.m_class.m_layer, (ushort)0, (ushort)0, (ushort)0)) { flag = true; } if (Singleton <BuildingManager> .instance.OverlapQuad(quad, minY, maxY, collisionType, info.m_class.m_layer, (ushort)0, (ushort)0, (ushort)0)) { flag = true; } //begin mod if (!OptionsWrapper <Options> .Options.unhideAllTreesOnLevelLoading) { return; } if (tree.GrowState != 0) { return; } tree.GrowState = 1; //end mod }
public static bool TestNodeBuilding(ushort nodeID, BuildingInfo info, Vector3 position, float angle) { Vector2 a = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle)); Vector2 a2 = new Vector3(a.y, 0f - a.x); if (info.m_placementMode == BuildingInfo.PlacementMode.Roadside || info.m_placementMode == BuildingInfo.PlacementMode.PathsideOrGround) { a *= (float)info.m_cellWidth * 4f - 0.8f; a2 *= (float)info.m_cellLength * 4f - 0.8f; } else { a *= (float)info.m_cellWidth * 4f; a2 *= (float)info.m_cellLength * 4f; } if (info.m_circular) { a *= 0.7f; a2 *= 0.7f; } ItemClass.CollisionType collisionType = info.m_buildingAI.GetCollisionType(); Vector2 a3 = VectorUtils.XZ(position); Quad2 quad = default(Quad2); quad.a = a3 - a - a2; quad.b = a3 - a + a2; quad.c = a3 + a + a2; quad.d = a3 + a - a2; float minY = Mathf.Min(position.y, Singleton <TerrainManager> .instance.SampleRawHeightSmooth(position)); float maxY = position.y + info.m_generatedInfo.m_size.y; if (collisionType == ItemClass.CollisionType.Elevated) { minY = position.y + info.m_generatedInfo.m_min.y; } if (Singleton <NetManager> .instance.OverlapQuad(quad, minY, maxY, collisionType, info.m_class.m_layer, nodeID, 0, 0, null)) { return(false); } if (Singleton <BuildingManager> .instance.OverlapQuad(quad, minY, maxY, collisionType, info.m_class.m_layer, 0, nodeID, 0, null)) { return(false); } return(true); }
private void ExtraTrySpreadFire(Quad2 quad, float minY, float maxY, ushort buildingID, ref Building buildingData) { BuildingInfo info = buildingData.Info; int num; int num2; int num3; info.m_buildingAI.GetFireParameters(buildingID, ref buildingData, out num, out num2, out num3); ItemClass.CollisionType tmpIC = 0; if (num != 0 && (buildingData.m_flags & (Building.Flags.Completed | Building.Flags.Abandoned)) == Building.Flags.Completed && buildingData.m_fireIntensity == 0 && buildingData.GetLastFrameData().m_fireDamage == 0 && buildingData.OverlapQuad( buildingID, quad, minY, maxY,tmpIC)) { if (fireSet.Contains(buildingID)) { return; } else { var temp = ""; foreach (ushort fs in fireSet) { temp += fs.ToString(); } fireQueue.Enqueue(buildingID); fireSet.Add(buildingID); if (fireSet.Count > 50) { fireSet.Remove(fireQueue.Dequeue()); } } float num4 = Singleton<TerrainManager>.instance.WaterLevel(VectorUtils.XZ(buildingData.m_position)); if (num4 <= buildingData.m_position.y) { Building.Flags flags = buildingData.m_flags; buildingData.m_fireIntensity = (byte)num2; info.m_buildingAI.BuildingDeactivated(buildingID, ref buildingData); Building.Flags flags2 = buildingData.m_flags; Singleton<BuildingManager>.instance.UpdateBuildingRenderer(buildingID, true); if (flags2 != flags) { Singleton<BuildingManager>.instance.UpdateFlags(buildingID, flags2 ^ flags); } } } }
public static ItemCollisionType CheckAllCollisionsTree(Vector3 worldPosition, TreeInfo treeInfo) { ItemCollisionType _result = ItemCollisionType.None; Vector2 _center = VectorUtils.XZ(worldPosition); float _radius = 0.5f; Quad2 _quad = default(Quad2); _quad.a = _center + new Vector2(-_radius, -_radius); _quad.b = _center + new Vector2(-_radius, _radius); _quad.c = _center + new Vector2(_radius, _radius); _quad.d = _center + new Vector2(_radius, -_radius); float _minY = worldPosition.y; float _maxY = worldPosition.y + treeInfo.m_generatedInfo.m_size.y * Mathf.Max(treeInfo.m_maxScale, treeInfo.m_minScale); ItemClass.CollisionType _collisionType = ItemClass.CollisionType.Terrain; if (DoesTreeCollideWithProps(_quad, _minY, _maxY, _collisionType, treeInfo)) { _result |= ItemCollisionType.Props; } if (DoesTreeCollideWithTrees(_quad, _minY, _maxY, _collisionType, treeInfo)) { _result |= ItemCollisionType.Trees; } if (CheckTreeBlocked(_quad, _minY, _maxY, _collisionType, treeInfo)) { _result |= ItemCollisionType.Blocked; } if (DoesPositionHaveWater(worldPosition)) { _result |= ItemCollisionType.Water; } if (IsQuadOutOfGameArea(_quad)) { _result |= ItemCollisionType.GameArea; } return(_result); }
public static bool CheckValidPlacementTreeLite(Vector3 worldPosition, TreeInfo treeInfo) { bool _result = true; Vector2 _center = VectorUtils.XZ(worldPosition); float _radius = 0.5f; Quad2 _quad = default(Quad2); _quad.a = _center + new Vector2(-_radius, -_radius); _quad.b = _center + new Vector2(-_radius, _radius); _quad.c = _center + new Vector2(_radius, _radius); _quad.d = _center + new Vector2(_radius, -_radius); float _minY = worldPosition.y; float _maxY = worldPosition.y + treeInfo.m_generatedInfo.m_size.y * Mathf.Max(treeInfo.m_maxScale, treeInfo.m_minScale); ItemClass.CollisionType _collisionType = ItemClass.CollisionType.Terrain; if (IsQuadOutOfGameArea(_quad)) { _result = false; } else if (CheckTreeBlocked(_quad, _minY, _maxY, _collisionType, treeInfo)) { _result = false; } else if (DoesPositionHaveWater(worldPosition)) { _result = false; } else if (DoesTreeCollideWithTrees(_quad, _minY, _maxY, _collisionType, treeInfo)) { _result = false; } else if (DoesTreeCollideWithProps(_quad, _minY, _maxY, _collisionType, treeInfo)) { _result = false; } return(_result); }
public bool QuadOutOfArea(Quad2 quad) { var result = CrossTheLine.IsCrossingLineProhibited(); if (result) { do { } while (!Monitor.TryEnter(_lock, SimulationManager.SYNCHRONIZE_TIMEOUT)); try { RedirectionHelper.RevertJumpTo(_originalPtr, _state); result = Singleton<GameAreaManager>.instance.QuadOutOfArea(quad); RedirectionHelper.PatchJumpTo(_originalPtr, _detourPtr); } finally { Monitor.Exit(_lock); } } return result; }
private static bool OverlapQuad(TreeManager tm, Quad2 quad, float minY, float maxY, int layer, uint ignoreTree) { unsafe { Vector2 vector2 = quad.Min(); Vector2 vector21 = quad.Max(); int num = Mathf.Max((int)(((double)vector2.x - 8) / 32 + 270), 0); int num1 = Mathf.Max((int)(((double)vector2.y - 8) / 32 + 270), 0); int num2 = Mathf.Min((int)(((double)vector21.x + 8) / 32 + 270), 539); int num3 = Mathf.Min((int)(((double)vector21.y + 8) / 32 + 270), 539); for (int i = num1; i <= num3; i++) { for (int j = num; j <= num2; j++) { uint mTreeGrid = tm.m_treeGrid[i * 540 + j]; int num4 = 0; while (mTreeGrid != 0) { Vector3 position = tm.m_trees.m_buffer[mTreeGrid].Position; if ((double)Mathf.Max(Mathf.Max(vector2.x - 8f - position.x, vector2.y - 8f - position.z), Mathf.Max((float)((double)position.x - (double)vector21.x - 8), (float)((double)position.z - (double)vector21.y - 8))) < 0 && tm.m_trees.m_buffer[mTreeGrid].OverlapQuad(mTreeGrid, quad, minY, maxY)) { return true; } mTreeGrid = tm.m_trees.m_buffer[mTreeGrid].m_nextGridTree; int num5 = num4 + 1; num4 = num5; if (num5 < LimitTreeManager.Helper.TreeLimit) { continue; } CODebugBase<LogChannel>.Error(LogChannel.Core, string.Concat("Invalid list detected!\n", Environment.StackTrace)); break; } } } return false; } }
public bool OverlapQuad(Quad2 quad, float minY, float maxY, ItemClass.CollisionType collisionType, ItemClass.Layer layers, ushort ignoreBuilding, ushort ignoreNode1, ushort ignoreNode2, ulong[] buildingMask) { Vector2 vector2_1 = quad.Min(); Vector2 vector2_2 = quad.Max(); int num1 = Mathf.Max((int)(((double)vector2_1.x - 72.0) / 64.0 + 135.0), 0); int num2 = Mathf.Max((int)(((double)vector2_1.y - 72.0) / 64.0 + 135.0), 0); int num3 = Mathf.Min((int)(((double)vector2_2.x + 72.0) / 64.0 + 135.0), 269); int num4 = Mathf.Min((int)(((double)vector2_2.y + 72.0) / 64.0 + 135.0), 269); bool flag = false; for (int index1 = num2; index1 <= num4; ++index1) { for (int index2 = num1; index2 <= num3; ++index2) { ushort num5 = this.m_buildingGrid[index1 * 270 + index2]; int num6 = 0; while ((int)num5 != 0) { BuildingInfo info = this.m_buildings.m_buffer[(int)num5].Info; //mod: add null check if ((layers == ItemClass.Layer.None || (info != null && (info.m_class.m_layer & layers) != ItemClass.Layer.None)) && (!(bool)ignoreOverlap.Invoke(this, new object[] { num5, ignoreBuilding, ignoreNode1, ignoreNode2 }) && this.m_buildings.m_buffer[(int)num5].OverlapQuad(num5, quad, minY, maxY, collisionType))) { if (buildingMask == null) return true; buildingMask[(int)num5 >> 6] |= (ulong)(1L << (int)num5); flag = true; } num5 = this.m_buildings.m_buffer[(int)num5].m_nextGridBuilding; if (++num6 >= 49152) { CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } return flag; }
/// <summary> /// Intersects zone block with other zone block, updates "valid" and "shared" masks. /// </summary> /// <param name="_this"></param> /// <param name="blockID"></param> /// <param name="other"></param> /// <param name="valid"></param> /// <param name="shared"></param> /// <param name="minX"></param> /// <param name="minZ"></param> /// <param name="maxX"></param> /// <param name="maxZ"></param> private static void CalculateImplementation2(ref ZoneBlock _this, ushort otherBlockID, ushort blockID, ref ZoneBlock other, ref ulong valid, ref ulong shared, float minX, float minZ, float maxX, float maxZ) { // 92 = sqrt(64^2+64^2) // if the other zone block is not marked as "created" or too far away, do nothing if (((int)other.m_flags & ZoneBlock.FLAG_CREATED) == 0 || (double)Mathf.Abs(other.m_position.x - _this.m_position.x) >= 92.0 || (double)Mathf.Abs(other.m_position.z - _this.m_position.z) >= 92.0) { return; } // checks if the other zone block is marked as "deleted" bool deleted = ((int)other.m_flags & ZoneBlock.FLAG_DELETED) != 0; // width of block and other block int rowCount = _this.RowCount; int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified int otherRowCount = other.RowCount; int otherColumnCount = ZoneBlockDetour.GetColumnCount(ref other); // modified // directions of the rows and columns of the block, multiplied by 8 (cell size) Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f; Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x); // directions of the rows and columns of the other block, multiplied by 8 (cell size) Vector2 otherColumnDirection = new Vector2(Mathf.Cos(other.m_angle), Mathf.Sin(other.m_angle)) * 8f; Vector2 otherRowDirection = new Vector2(otherColumnDirection.y, -otherColumnDirection.x); // origin of the other block Vector2 otherPositionXZ = VectorUtils.XZ(other.m_position); // area of the other zone block Quad2 otherZoneBlockQuad = new Quad2 { a = otherPositionXZ - 4f * otherColumnDirection - 4f * otherRowDirection, b = otherPositionXZ + (otherColumnCount - 4f) * otherColumnDirection - 4f * otherRowDirection, c = otherPositionXZ + (otherColumnCount - 4f) * otherColumnDirection + (float)(otherRowCount - 4) * otherRowDirection, d = otherPositionXZ - 4f * otherColumnDirection + (float)(otherRowCount - 4) * otherRowDirection }; Vector2 otherQuadMin = otherZoneBlockQuad.Min(); Vector2 otherQuadMax = otherZoneBlockQuad.Max(); // return if there is no chance that the 2 quads collide if ((double)otherQuadMin.x > (double)maxX || (double)otherQuadMin.y > (double)maxZ || ((double)minX > (double)otherQuadMax.x || (double)minZ > (double)otherQuadMax.y)) { return; } // origin of the block Vector2 positionXZ = VectorUtils.XZ(_this.m_position); // area of the zone block (8x4 cells) Quad2 zoneBlockQuad = new Quad2 { a = positionXZ - 4f * columnDirection - 4f * rowDirection, b = positionXZ + (columnCount - 4f) * columnDirection - 4f * rowDirection, c = positionXZ + (columnCount - 4f) * columnDirection + (float)(rowCount - 4) * rowDirection, d = positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection }; // return if the quads are not intersecting if (!zoneBlockQuad.Intersect(otherZoneBlockQuad)) return; for (int row = 0; row < rowCount; ++row) { // calculate 2 relative row positions: // * one 0.01m from previous row // * one 0.01m from next row Vector2 rowNearPreviousLength = ((float)row - 3.99f) * rowDirection; Vector2 rowNearNextLength = ((float)row - 3.01f) * rowDirection; // set the quad to the row (4 cells) zoneBlockQuad.a = positionXZ - 4f * columnDirection + rowNearPreviousLength; zoneBlockQuad.b = positionXZ + (columnCount - 4f) * columnDirection + rowNearPreviousLength; zoneBlockQuad.c = positionXZ + (columnCount - 4f) * columnDirection + rowNearNextLength; zoneBlockQuad.d = positionXZ - 4f * columnDirection + rowNearNextLength; // Intersect the row quad with the other zone block quad if (zoneBlockQuad.Intersect(otherZoneBlockQuad)) { for (int column = 0; column < columnCount && (valid & 1uL << (row << 3 | column)) != 0uL; ++column) { // calculate 2 relative column positions: // * one 0.01m from previous column // * one 0.01m from next column Vector2 columnNearPreviousLength = ((float)column - 3.99f) * columnDirection; Vector2 columnNearNextLength = ((float)column - 3.01f) * columnDirection; // middle position of the cell Vector2 cellMiddlePos = positionXZ + (columnNearNextLength + columnNearPreviousLength + rowNearNextLength + rowNearPreviousLength) * 0.5f; // check if the middle position of the cell is contained in the quad of the other zone block (1 cell tolerance) if (Quad2.Intersect(otherZoneBlockQuad.a - otherColumnDirection - otherRowDirection, otherZoneBlockQuad.b + otherColumnDirection - otherRowDirection, otherZoneBlockQuad.c + otherColumnDirection + otherRowDirection, otherZoneBlockQuad.d - otherColumnDirection + otherRowDirection, cellMiddlePos)) { // Create a quad for the cell Quad2 cellQuad = new Quad2 { a = positionXZ + columnNearPreviousLength + rowNearPreviousLength, b = positionXZ + columnNearNextLength + rowNearPreviousLength, c = positionXZ + columnNearNextLength + rowNearNextLength, d = positionXZ + columnNearPreviousLength + rowNearNextLength }; // cycle through the cells of the other zone block bool cellIsValid = true; bool shareCell = false; for (int otherRow = 0; otherRow < otherRowCount && cellIsValid; ++otherRow) { // calculate 2 relative row positions for the cell in the other zone block: // * one 0.01m from previous row // * one 0.01m from next row Vector2 otherRowNearPreviousLength = ((float)otherRow - 3.99f) * otherRowDirection; Vector2 otherRowNearNextLength = ((float)otherRow - 3.01f) * otherRowDirection; for (int otherColumn = 0; otherColumn < otherColumnCount && cellIsValid; ++otherColumn) { // checks if the cell is marked as valid in the valid mask of the other block, and that it is not contained in the shared mask if ((other.m_valid & ~other.m_shared & 1uL << (otherRow << 3 | otherColumn)) != 0uL) { // calculate 2 relative column positions for the cell in the other zone block: // * one 0.01m from previous column // * one 0.01m from next column Vector2 otherColumnNearPreviousLength = ((float)otherColumn - 3.99f) * otherColumnDirection; Vector2 otherColumnNearNextLength = ((float)otherColumn - 3.01f) * otherColumnDirection; // squared distance between the 2 cell middle positions float cellMiddleDist = Vector2.SqrMagnitude(otherPositionXZ + (otherColumnNearNextLength + otherColumnNearPreviousLength + otherRowNearNextLength + otherRowNearPreviousLength) * 0.5f - cellMiddlePos); // check if the 2 cells can touch if ((double)cellMiddleDist < 144.0) { if (!deleted) // other zone block not deleted: { // difference of 2 radian angles (360 deg = 2*PI * 0.6366197f = 4f) // that means an angle difference of 90 deg would result in 1f float angleDiff = Mathf.Abs(other.m_angle - _this.m_angle) * 0.6366197f; float rightAngleDiff = angleDiff - Mathf.Floor(angleDiff); // difference from 90 deg // if the 2 cells are almost in the same spot with an angle difference of 0 90 180 270 deg, mark one of them as shared if ((double)cellMiddleDist < 0.00999999977648258 && ((double)rightAngleDiff < 0.00999999977648258 || (double)rightAngleDiff > 0.990000009536743)) { // The cell closer to road (or that was created earler) is kept, the other marked as shared if (column < otherColumn || column == otherColumn && _this.m_buildIndex < other.m_buildIndex) other.m_shared |= 1UL << (otherRow << 3 | otherColumn); else shareCell = true; } // angles not right or not in the same place: Intersect the 2 cells else if (cellQuad.Intersect(new Quad2() { a = otherPositionXZ + otherColumnNearPreviousLength + otherRowNearPreviousLength, b = otherPositionXZ + otherColumnNearNextLength + otherRowNearPreviousLength, c = otherPositionXZ + otherColumnNearNextLength + otherRowNearNextLength, d = otherPositionXZ + otherColumnNearPreviousLength + otherRowNearNextLength })) { // mark the cell which is further away from the road (or was created later) as invalid // TODO adapt for 8 cell zones (low priority) if (otherColumn >= 4 && column >= 4 || otherColumn < 4 && column < 4) { if (otherColumn >= 2 && column >= 2 || otherColumn < 2 && column < 2) { if (_this.m_buildIndex < other.m_buildIndex) other.m_valid &= ~(1UL << (otherRow << 3 | otherColumn)); else cellIsValid = false; } else if (otherColumn < 2) cellIsValid = false; else other.m_valid &= ~(1UL << (otherRow << 3 | otherColumn)); } else if (otherColumn < 4) cellIsValid = false; else other.m_valid &= ~(1UL << (otherRow << 3 | otherColumn)); } } // distance between cell middle pos < 6 = cells colliding // if the cell is unzoned, take over the zone type of the other one if ((double)cellMiddleDist < 36.0 && column < 8 && otherColumn < 8) // modifed 4 --> 8 { ItemClass.Zone zone1 = GetZoneDeep(ref _this, blockID, column, row); ItemClass.Zone zone2 = GetZoneDeep(ref other, otherBlockID, otherColumn, otherRow); if (zone1 == ItemClass.Zone.Unzoned) SetZoneDeep(ref _this, blockID, column, row, zone2); else if (zone2 == ItemClass.Zone.Unzoned && !deleted) SetZoneDeep(ref other, otherBlockID, otherColumn, otherRow, zone1); } } } } } if (!cellIsValid) { valid = valid & ~(1UL << (row << 3 | column)); break; } if (shareCell) shared = shared | 1UL << (row << 3 | column); } } } } }
/// <summary> /// This method marks zone cells overlapped by network segments as invalid. Called by CalculateBlock1. /// </summary> /// <param name="_this"></param> /// <param name="blockID"></param> /// <param name="segmentID"></param> /// <param name="data"></param> /// <param name="valid"></param> /// <param name="minX"></param> /// <param name="minZ"></param> /// <param name="maxX"></param> /// <param name="maxZ"></param> private static void CalculateImplementation1(ref ZoneBlock _this, ushort blockID, ushort segmentID, ref NetSegment data, ref ulong valid, float minX, float minZ, float maxX, float maxZ) { // do nothing if the block belongs to the network segment if ((int)data.m_blockStartLeft == (int)blockID || (int)data.m_blockStartRight == (int)blockID || ((int)data.m_blockEndLeft == (int)blockID || (int)data.m_blockEndRight == (int)blockID)) { return; } NetInfo info = data.Info; if (!info.m_canCollide) return; // water pipes etc. float collisionHalfWidth = info.m_netAI.GetCollisionHalfWidth(); NetNode[] netNodeArray = Singleton<NetManager>.instance.m_nodes.m_buffer; // calculate network bezier curve Bezier3 bezier = new Bezier3(); bezier.a = netNodeArray[(int)data.m_startNode].m_position; bezier.d = netNodeArray[(int)data.m_endNode].m_position; NetSegment.CalculateMiddlePoints(bezier.a, data.m_startDirection, bezier.d, data.m_endDirection, true, true, out bezier.b, out bezier.c); // remove vertical component Bezier2 bezierXZ = Bezier2.XZ(bezier); // do nothing if the collision hitbox is outside of the hitbox of the zone block Vector2 collisionAreaMin = bezierXZ.Min() + new Vector2(-collisionHalfWidth, -collisionHalfWidth); Vector2 collisionAreaMax = bezierXZ.Max() + new Vector2(collisionHalfWidth, collisionHalfWidth); if ((double)collisionAreaMin.x > (double)maxX || (double)collisionAreaMin.y > (double)maxZ || ((double)minX > (double)collisionAreaMax.x || (double)minZ > (double)collisionAreaMax.y)) { return; } // width of the zone block int rowCount = _this.RowCount; // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size) Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f; Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x); // origin of the zone block // this position is in the center of the 8x8 zone block (4 columns and 4 rows away from the lower corner) Vector2 positionXZ = VectorUtils.XZ(_this.m_position); // area of the zone block (8x8 cells) Quad2 zoneBlockQuad = new Quad2 { a = positionXZ - 4f * columnDirection - 4f * rowDirection, b = positionXZ + 4f * columnDirection - 4f * rowDirection, c = positionXZ + 4f * columnDirection + (float)(rowCount - 4) * rowDirection, d = positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection }; // Calculate the bounds of the network segment at the start node float start; float end; info.m_netAI.GetTerrainModifyRange(out start, out end); float halfStart = start * 0.5f; // e.g. 0.25f ---> 0.125f float halfEnd = (float)(1.0 - (1.0 - (double)end) * 0.5); // e.g. 0.75f --> 0.875f float t = halfStart; Vector2 startBezierPos = bezierXZ.Position(halfStart); Vector2 startBezierTan = bezierXZ.Tangent(halfStart); Vector2 startOrthogonalNormalized = new Vector2(-startBezierTan.y, startBezierTan.x).normalized; // tangent rotated by -90 deg = orthogonal Quad2 bezierQuad = new Quad2(); // set the initial a/b bounds if ((double)t < 0.00999999977648258 && (info.m_clipSegmentEnds || (netNodeArray[(int)data.m_startNode].m_flags & NetNode.Flags.Bend) != NetNode.Flags.None)) { Vector2 ortho4m = startOrthogonalNormalized * 4f; bezierQuad.a = startBezierPos + ortho4m - VectorUtils.XZ(data.m_startDirection) * 4f; bezierQuad.d = startBezierPos - ortho4m - VectorUtils.XZ(data.m_startDirection) * 4f; } else { Vector2 orthoHalfWidth = startOrthogonalNormalized * collisionHalfWidth; bezierQuad.a = startBezierPos + orthoHalfWidth; bezierQuad.d = startBezierPos - orthoHalfWidth; } // overlap 8 quads describing the position int steps = 8; for (int step = 1; step <= steps; ++step) { float interp = halfStart + (halfEnd - halfStart) * (float)step / (float)steps; Vector2 interpBezierPos = bezierXZ.Position(interp); Vector2 interpBezierTangent = bezierXZ.Tangent(interp); interpBezierTangent = new Vector2(-interpBezierTangent.y, interpBezierTangent.x).normalized; // set the c/d bounds if ((double)interp > 0.990000009536743 && (info.m_clipSegmentEnds || (netNodeArray[(int)data.m_endNode].m_flags & NetNode.Flags.Bend) != NetNode.Flags.None)) { interpBezierTangent *= 4f; bezierQuad.b = interpBezierPos + interpBezierTangent - VectorUtils.XZ(data.m_endDirection) * 4f; bezierQuad.c = interpBezierPos - interpBezierTangent - VectorUtils.XZ(data.m_endDirection) * 4f; } else { interpBezierTangent *= collisionHalfWidth; bezierQuad.b = interpBezierPos + interpBezierTangent; bezierQuad.c = interpBezierPos - interpBezierTangent; } Vector2 quadMin = bezierQuad.Min(); Vector2 quadMax = bezierQuad.Max(); // Overlap the quad with the zone block quad if ((double)quadMin.x <= (double)maxX && (double)quadMin.y <= (double)maxZ && ((double)minX <= (double)quadMax.x && (double)minZ <= (double)quadMax.y) && zoneBlockQuad.Intersect(bezierQuad)) { // mark colliding cells as invalid valid = valid & ~OverlapQuad(ref _this, bezierQuad); } // set the a/b bounds for the next quad bezierQuad.a = bezierQuad.b; bezierQuad.d = bezierQuad.c; } }
public bool QuadOutOfArea(Quad2 quad) { Vector2 vector = quad.Min(); Vector2 vector2 = quad.Max(); int num6 = Mathf.FloorToInt((vector.x - 8f) / 1920f + 4.5f); int num7 = Mathf.FloorToInt((vector.y - 8f) / 1920f + 4.5f); int num8 = Mathf.FloorToInt((vector2.x + 8f) / 1920f + 4.5f); int num9 = Mathf.FloorToInt((vector2.y + 8f) / 1920f + 4.5f); for (int i = num7; i <= num9; i++) { for (int j = num6; j <= num8; j++) { int area = GetArea(j, i); if ((area == -2 ) && quad.Intersect(new Quad2 { a = new Vector2(((float)j - 4.5f) * 1920f - 8f, ((float)i - 4.5f) * 1920f - 8f), b = new Vector2(((float)j - 4.5f) * 1920f - 8f, ((float)i - 4.5f + 1f) * 1920f + 8f), c = new Vector2(((float)j - 4.5f + 1f) * 1920f + 8f, ((float)i - 4.5f + 1f) * 1920f + 8f), d = new Vector2(((float)j - 4.5f + 1f) * 1920f + 8f, ((float)i - 4.5f) * 1920f - 8f) })) { return true; } } } return false; }
private static void ApplyBrush(TreeTool tt) { //uint useless1 = 0; unsafe { float single; float single1; uint num; int num1; Vector3 vector3 = new Vector3(); Randomizer value = (Randomizer)tt.GetType().GetField("m_randomizer", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(tt); ToolController toolController = (ToolController)tt.GetType().GetField("m_toolController", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(tt); Vector3 value1 = (Vector3)tt.GetType().GetField("m_mousePosition", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(tt); bool flag = (bool)tt.GetType().GetField("m_mouseLeftDown", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(tt); bool flag1 = (bool)tt.GetType().GetField("m_mouseRightDown", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(tt); TreeInfo treeInfo = (TreeInfo)tt.GetType().GetField("m_treeInfo", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(tt); float[] brushData = toolController.BrushData; float mBrushSize = tt.m_brushSize * 0.5f; float single2 = 32f; int num2 = 540; TreeInstance[] mBuffer = Singleton <TreeManager> .instance.m_trees.m_buffer; uint[] mTreeGrid = Singleton <TreeManager> .instance.m_treeGrid; float mStrength = tt.m_strength; int num3 = Mathf.Max((int)((value1.x - mBrushSize) / single2 + (float)num2 * 0.5f), 0); int num4 = Mathf.Max((int)((value1.z - mBrushSize) / single2 + (float)num2 * 0.5f), 0); int num5 = Mathf.Min((int)((value1.x + mBrushSize) / single2 + (float)num2 * 0.5f), num2 - 1); int num6 = Mathf.Min((int)((value1.z + mBrushSize) / single2 + (float)num2 * 0.5f), num2 - 1); for (int i = num4; i <= num6; i++) { float mBrushSize1 = (float)(((float)i - (float)num2 * 0.5f + 0.5f) * single2 - value1.z + mBrushSize) / tt.m_brushSize * 64f - 0.5f; int num7 = Mathf.Clamp(Mathf.FloorToInt(mBrushSize1), 0, 63); int num8 = Mathf.Clamp(Mathf.CeilToInt(mBrushSize1), 0, 63); for (int j = num3; j <= num5; j++) { float mBrushSize2 = (float)(((float)j - (float)num2 * 0.5f + 0.5f) * single2 - value1.x + mBrushSize) / tt.m_brushSize * 64f - 0.5f; int num9 = Mathf.Clamp(Mathf.FloorToInt(mBrushSize2), 0, 63); int num10 = Mathf.Clamp(Mathf.CeilToInt(mBrushSize2), 0, 63); float single3 = brushData[num7 * 64 + num9]; float single4 = brushData[num7 * 64 + num10]; float single5 = brushData[num8 * 64 + num9]; float single6 = brushData[num8 * 64 + num10]; float single7 = single3 + (float)((single4 - single3) * (mBrushSize2 - (float)num9)); float single8 = single5 + (float)((single6 - single5) * (mBrushSize2 - (float)num9)); float single9 = single7 + (float)((single8 - single7) * (mBrushSize1 - (float)num7)); int num11 = (int)(mStrength * (single9 * 1.2f - 0.2f) * 10000f); if (flag && tt.m_prefab != null) { if (value.Int32(10000) < num11) { TreeInfo treeInfo1 = ((Singleton <ToolManager> .instance.m_properties.m_mode & ItemClass.Availability.AssetEditor) == ItemClass.Availability.None ? tt.m_prefab.GetVariation(ref value) : tt.m_prefab); vector3.x = ((float)j - (float)num2 * 0.5f) * single2; vector3.z = ((float)i - (float)num2 * 0.5f) * single2; vector3.x = vector3.x + (float)(((float)value.Int32(10000) + 0.5f) * (single2 / 10000f)); vector3.z = vector3.z + (float)(((float)value.Int32(10000) + 0.5f) * (single2 / 10000f)); vector3.y = 0f; vector3.y = Singleton <TerrainManager> .instance.SampleDetailHeight(vector3, out single, out single1); if (Mathf.Max(Mathf.Abs(single), Mathf.Abs(single1)) < (float)value.Int32(10000) * 5E-05f) { float mSize = treeInfo.m_generatedInfo.m_size.y; float mMinScale = treeInfo.m_minScale; Randomizer randomizer = new Randomizer(Singleton <TreeManager> .instance.m_trees.NextFreeItem(ref value)); mMinScale = mMinScale + (float)randomizer.Int32(10000) * ((treeInfo.m_maxScale - treeInfo.m_minScale) * 0.0001f); mSize = mSize * mMinScale; float single11 = 4.5f; Vector2 vector2 = VectorUtils.XZ(vector3); Quad2 quad22 = new Quad2() { a = vector2 + new Vector2(-single11, -single11), b = vector2 + new Vector2(-single11, single11), c = vector2 + new Vector2(single11, single11), d = vector2 + new Vector2(single11, -single11) }; Quad2 quad2 = quad22; Quad2 quad23 = new Quad2() { a = vector2 + new Vector2(-8f, -8f), b = vector2 + new Vector2(-8f, 8f), c = vector2 + new Vector2(8f, 8f), d = vector2 + new Vector2(8f, -8f) }; Quad2 quad21 = quad23; float single12 = value1.y - 1000f; float single13 = value1.y + mSize; ItemClass.CollisionType collisionType = ItemClass.CollisionType.Terrain; if (!Singleton <PropManager> .instance.OverlapQuad(quad2, single12, single13, collisionType, 0, 0) && !Singleton <TreeManager> .instance.OverlapQuad(quad21, single12, single13, collisionType, 0, 0) && !Singleton <NetManager> .instance.OverlapQuad(quad2, single12, single13, collisionType, treeInfo1.m_class.m_layer, 0, 0, 0) && !Singleton <BuildingManager> .instance.OverlapQuad(quad2, single12, single13, collisionType, treeInfo1.m_class.m_layer, 0, 0, 0) && !Singleton <TerrainManager> .instance.HasWater(vector2) && !Singleton <GameAreaManager> .instance.QuadOutOfArea(quad2) && !Singleton <TreeManager> .instance.CreateTree(out num, ref value, treeInfo1, vector3, false)) { } } } } else if (flag1 || tt.m_prefab == null) { uint num12 = mTreeGrid[i * num2 + j]; int num13 = 0; do { if (num12 == 0) { goto Label10; } uint mNextGridTree = mBuffer[num12].m_nextGridTree; if (value.Int32(10000) < num11) { Singleton <TreeManager> .instance.ReleaseTree(num12); } num12 = mNextGridTree; num1 = num13 + 1; num13 = num1; }while (num1 < LimitTreeManager.Helper.TreeLimit); CODebugBase <LogChannel> .Error(LogChannel.Core, string.Concat("Invalid list detected!\n", Environment.StackTrace)); } Label10: ;//useless1++; } } } }
public void Changed(float x, float y) { // Quad1 = GameObject.Find ("Quad1"); // Quad2 = GameObject.Find ("Quad2"); int correct = PlayerPrefs.GetInt("Correct cube"); if (x < 0.25f && y < 0.6f) { if (correct == 1) { StartCoroutine(WaitAndCorrect(2.0f)); } else { WrongSound.audio.Play(); Quad1.SetActive(true); Quad2.SetActive(true); StartCoroutine(WaitAndSetInactive(1.0F)); } } else if (x < 0.5f && y < 0.6f && x > 0.25f) { if (correct == 2) { StartCoroutine(WaitAndCorrect(2.0f)); } else { WrongSound.audio.Play(); Quad1.SetActive(true); Quad2.SetActive(true); StartCoroutine(WaitAndSetInactive(1.0F)); } } else if (x >= 0.5f && y < 0.6f && x < 0.75f) { if (correct == 3) { StartCoroutine(WaitAndCorrect(2.0f)); } else { WrongSound.audio.Play(); Quad1.SetActive(true); Quad2.SetActive(true); StartCoroutine(WaitAndSetInactive(1.0F)); } } else if (x >= 0.75f && y < 0.6f) { if (correct == 4) { StartCoroutine(WaitAndCorrect(2.0f)); } else { WrongSound.audio.Play(); Quad1.SetActive(true); Quad2.SetActive(true); StartCoroutine(WaitAndSetInactive(1.0F)); } } }
private static void HandleFireSpread(CommonBuildingAI CBAI, ushort buildingID, ref Building buildingData, int fireDamage) { unsafe { Quad2 quad2 = new Quad2(); int width = buildingData.Width; int length = buildingData.Length; Vector2 vector2 = VectorUtils.XZ(buildingData.m_position); Vector2 vector21 = new Vector2(Mathf.Cos(buildingData.m_angle), Mathf.Sin(buildingData.m_angle)); Vector2 vector22 = new Vector2(vector21.y, -vector21.x); float single = (float)Singleton <SimulationManager> .instance.m_randomizer.Int32(8, 32); quad2.a = (vector2 - (((float)width * 4f + single) * vector21)) - (((float)length * 4f + single) * vector22); quad2.b = (vector2 + (((float)width * 4f + single) * vector21)) - (((float)length * 4f + single) * vector22); quad2.c = (vector2 + (((float)width * 4f + single) * vector21)) + (((float)length * 4f + single) * vector22); quad2.d = (vector2 - (((float)width * 4f + single) * vector21)) + (((float)length * 4f + single) * vector22); Vector2 vector23 = quad2.Min(); Vector2 vector24 = quad2.Max(); float mPosition = buildingData.m_position.y - (float)buildingData.m_baseHeight; //krn //CBAI.m_info is private\instance /use reflection, should do reverse redirect. BuildingInfo bldgInfo; bldgInfo = (BuildingInfo)CBAI.GetType().GetField("m_info", BindingFlags.Instance | BindingFlags.Public).GetValue(CBAI); if (bldgInfo == null && bldgInfo.m_size == null) { Logger.dbgLog("bldgInfo was null"); } float mPosition1 = buildingData.m_position.y + bldgInfo.m_size.y; //org //float mPosition1 = buildingData.m_position.y + this.m_info.m_size.y; //end org float mFireIntensity = (float)(buildingData.m_fireIntensity * (64 - Mathf.Abs(fireDamage - 192))); InstanceID instanceID = new InstanceID() { Building = buildingID }; InstanceManager.Group group = Singleton <InstanceManager> .instance.GetGroup(instanceID); if (group != null) { ushort disaster = group.m_ownerInstance.Disaster; if (disaster != 0) { DisasterManager disasterManager = Singleton <DisasterManager> .instance; DisasterInfo info = disasterManager.m_disasters.m_buffer[disaster].Info; int fireSpreadProbability = info.m_disasterAI.GetFireSpreadProbability(disaster, ref disasterManager.m_disasters.m_buffer[disaster]); mFireIntensity = mFireIntensity * ((float)fireSpreadProbability * 0.01f); } } int num = Mathf.Max((int)((vector23.x - 72f) / 64f + 135f), 0); int num1 = Mathf.Max((int)((vector23.y - 72f) / 64f + 135f), 0); int num2 = Mathf.Min((int)((vector24.x + 72f) / 64f + 135f), 269); int num3 = Mathf.Min((int)((vector24.y + 72f) / 64f + 135f), 269); BuildingManager buildingManager = Singleton <BuildingManager> .instance; for (int i = num1; i <= num3; i++) { for (int j = num; j <= num2; j++) { ushort mBuildingGrid = buildingManager.m_buildingGrid[i * 270 + j]; int num4 = 0; object[] paramcall; while (mBuildingGrid != 0) { //Should we change this 262144? if (mBuildingGrid != buildingID && (float)Singleton <SimulationManager> .instance.m_randomizer.Int32(262144) * single < mFireIntensity) { //Logger.dbgLog("Handlefire1"); paramcall = new object[] { quad2, mPosition, mPosition1, mBuildingGrid, buildingManager.m_buildings.m_buffer[mBuildingGrid], group }; //var x = CBAI.GetType().GetMethod("TrySpreadFire", BindingFlags.Static | BindingFlags.NonPublic).Invoke(CBAI, paramcall); LimitCommonBuildingAI.TrySpreadFire(quad2, mPosition, mPosition1, mBuildingGrid, ref buildingManager.m_buildings.m_buffer[mBuildingGrid], group); //Logger.dbgLog("Handlefire2"); //orginal //CommonBuildingAI.TrySpreadFire(quad2, mPosition, mPosition1, mBuildingGrid, ref buildingManager.m_buildings.m_buffer[mBuildingGrid], group); } mBuildingGrid = buildingManager.m_buildings.m_buffer[mBuildingGrid].m_nextGridBuilding; int num5 = num4 + 1; num4 = num5; if (num5 < 49152) { continue; } CODebugBase <LogChannel> .Error(LogChannel.Core, string.Concat("Invalid list detected!\n", Environment.StackTrace)); break; } } } Vector3 vector3 = VectorUtils.X_Y(vector21); Vector3 vector31 = VectorUtils.X_Y(vector22); int num6 = Mathf.Max((int)((vector23.x - 32f) / 32f + 270f), 0); int num7 = Mathf.Max((int)((vector23.y - 32f) / 32f + 270f), 0); int num8 = Mathf.Min((int)((vector24.x + 32f) / 32f + 270f), 539); int num9 = Mathf.Min((int)((vector24.y + 32f) / 32f + 270f), 539); TreeManager treeManager = Singleton <TreeManager> .instance; for (int k = num7; k <= num9; k++) { for (int l = num6; l <= num8; l++) { uint mTreeGrid = treeManager.m_treeGrid[k * 540 + l]; int num10 = 0; while (mTreeGrid != 0) { Vector3 position = treeManager.m_trees.m_buffer[mTreeGrid].Position; Vector3 mPosition2 = position - buildingData.m_position; mPosition2 = mPosition2 - (Mathf.Clamp(Vector3.Dot(mPosition2, vector3), (float)(-width) * 4f, (float)width * 4f) * vector3); mPosition2 = mPosition2 - (Mathf.Clamp(Vector3.Dot(mPosition2, vector31), (float)(-length) * 4f, (float)length * 4f) * vector31); float single1 = mPosition2.magnitude; //Should we change this 131072? //Logger.dbgLog("Handlefire3"); if (single1 < 32f && (float)Singleton <SimulationManager> .instance.m_randomizer.Int32(131072) * single1 < mFireIntensity) { treeManager.BurnTree(mTreeGrid, group, (int)buildingData.m_fireIntensity); } mTreeGrid = treeManager.m_trees.m_buffer[mTreeGrid].m_nextGridTree; int num11 = num10 + 1; num10 = num11; if (num11 < LimitTreeManager.Helper.TreeLimit) { continue; } CODebugBase <LogChannel> .Error(LogChannel.Core, string.Concat("Invalid list detected!\n", Environment.StackTrace)); break; } } } } }
public static void SimulationStep(ref ZoneBlock _this, ushort blockID) { ZoneManager zoneManager = Singleton<ZoneManager>.instance; // width of the zone block int rowCount = _this.RowCount; // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size) Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f; Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x); // bitmask of valid cells that are not occupied ulong validFreeCellMask = _this.m_valid & ~(_this.m_occupied1 | _this.m_occupied2); // select a random zoned, unoccupied row and get its zone type // this will be our seed row int seedRow = 0; ItemClass.Zone zone = ItemClass.Zone.Unzoned; for (int index = 0; index < 4 && zone == ItemClass.Zone.Unzoned; ++index) { seedRow = Singleton<SimulationManager>.instance.m_randomizer.Int32((uint)rowCount); if ((validFreeCellMask & 1UL << (seedRow << 3)) != 0UL) { zone = GetZoneDeep(ref _this, blockID, 0, seedRow); } } // get the demand for the given zone type in the district DistrictManager districtManager = Singleton<DistrictManager>.instance; byte district = districtManager.GetDistrict(_this.m_position); int demand; switch (zone) { case ItemClass.Zone.ResidentialLow: demand = zoneManager.m_actualResidentialDemand + districtManager.m_districts.m_buffer[(int)district].CalculateResidentialLowDemandOffset(); break; case ItemClass.Zone.ResidentialHigh: demand = zoneManager.m_actualResidentialDemand + districtManager.m_districts.m_buffer[(int)district].CalculateResidentialHighDemandOffset(); break; case ItemClass.Zone.CommercialLow: demand = zoneManager.m_actualCommercialDemand + districtManager.m_districts.m_buffer[(int)district].CalculateCommercialLowDemandOffset(); break; case ItemClass.Zone.CommercialHigh: demand = zoneManager.m_actualCommercialDemand + districtManager.m_districts.m_buffer[(int)district].CalculateCommercialHighDemandOffset(); break; case ItemClass.Zone.Industrial: demand = zoneManager.m_actualWorkplaceDemand + districtManager.m_districts.m_buffer[(int)district].CalculateIndustrialDemandOffset(); break; case ItemClass.Zone.Office: demand = zoneManager.m_actualWorkplaceDemand + districtManager.m_districts.m_buffer[(int)district].CalculateOfficeDemandOffset(); break; default: return; } // origin of the zone block Vector2 positionXZ = VectorUtils.XZ(_this.m_position); // middle position of random row (roadside seed cell) Vector2 seedCellMiddlePosition = positionXZ - 3.5f * columnDirection + ((float)seedRow - 3.5f) * rowDirection; // This buffer contains 13 masks (for 13 rows) // The masks are split into two 16-bit segments // The higher 16 bits store which columns have road access // The lower 16 bits store which columns are unoccupied int[] xBuffer = zoneManager.m_tmpXBuffer; // TODO maybe use a bigger buffer? for (int index = 0; index < 13; ++index) xBuffer[index] = 0; // reset the buffer // put the surrounding area of the seed cell into a quad // TODO maybe check a bigger area? Quad2 seedPointAreaQuad = new Quad2 { a = positionXZ - 4f * columnDirection + ((float)seedRow - 10f) * rowDirection, b = positionXZ + 3f * columnDirection + ((float)seedRow - 10f) * rowDirection, c = positionXZ + 3f * columnDirection + ((float)seedRow + 2f) * rowDirection, d = positionXZ - 4f * columnDirection + ((float)seedRow + 2f) * rowDirection }; Vector2 seedPointAreaMin = seedPointAreaQuad.Min(); Vector2 seedPointAreaMax = seedPointAreaQuad.Max(); // calculate which zone block grid cells are touched by this zone block int gridMinX = Mathf.Max((int)(((double)seedPointAreaMin.x - 46.0) / 64.0 + 75.0), 0); int gridMinZ = Mathf.Max((int)(((double)seedPointAreaMin.y - 46.0) / 64.0 + 75.0), 0); int gridMaxX = Mathf.Min((int)(((double)seedPointAreaMax.x + 46.0) / 64.0 + 75.0), 149); int gridMaxZ = Mathf.Min((int)(((double)seedPointAreaMax.y + 46.0) / 64.0 + 75.0), 149); // Cycle through all touched grid cells for (int gridZ = gridMinZ; gridZ <= gridMaxZ; ++gridZ) { for (int gridX = gridMinX; gridX <= gridMaxX; ++gridX) { // Cycle through all zone blocks in grid cell ushort otherBlockID = zoneManager.m_zoneGrid[gridZ * 150 + gridX]; int counter = 0; while ((int)otherBlockID != 0) { Vector3 otherPosition = zoneManager.m_blocks.m_buffer[(int)otherBlockID].m_position; // check if other zone block is in range if ((double)Mathf.Max(Mathf.Max(seedPointAreaMin.x - 46f - otherPosition.x, seedPointAreaMin.y - 46f - otherPosition.z), Mathf.Max((float)((double)otherPosition.x - (double)seedPointAreaMax.x - 46.0), (float)((double)otherPosition.z - (double)seedPointAreaMax.y - 46.0))) < 0.0) { // Checks if the other block intersects and extends this block (orthogonal) and marks unoccupied cells and cells with road access in the XBuffer CheckBlock(ref _this, otherBlockID, ref zoneManager.m_blocks.m_buffer[(int)otherBlockID], xBuffer, zone, seedCellMiddlePosition, columnDirection, rowDirection, seedPointAreaQuad); } // next zone block in grid cell (linked list) otherBlockID = zoneManager.m_blocks.m_buffer[(int)otherBlockID].m_nextGridBlock; if (++counter >= 49152) { CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace); break; } } } } for (int row = 0; row < 13; ++row) { uint columnMask = (uint)xBuffer[row]; int columnCount = 0; // counts the unoccupied columns // check if the first the 2 cells in the column have road access // that means the area is suitable for corner buildings // 196608 = 0000 0000 0000 0011 0000 0000 0000 0000 bool cornerRoadAccess = ((int)columnMask & 196608) == 196608; // stores if the last checked cell has road access bool backsideRoadAccess = false; // count unoccupied cells in this column while (((int)columnMask & 1) != 0) { ++columnCount; // check if the cell has road access // 65536 = 0000 0000 0000 0001 0000 0000 0000 0000 backsideRoadAccess = ((int)columnMask & 65536) != 0; // move on to the next cell columnMask >>= 1; } if (columnCount == 5 || columnCount == 6) { // if the last checked cell has road access, decrease max depth to number between 2 and 4, otherwise set it to 4 // always set the "depth shortened flag" (131072) columnCount = (!backsideRoadAccess ? 4 : columnCount - (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) + 2)) | 131072; } else if (columnCount == 7) { // 131072 = 0000 0000 0000 0010 0000 0000 0000 0000 // set the "depth shortened flag" and and set max depth to 4 columnCount = 4 | 131072; } // TODO add support for larger lots! (8,9,10,11,12,13,14,15) if (cornerRoadAccess) { // set corner flag // 65536 = 0000 0000 0000 0001 0000 0000 0000 0000 columnCount |= 65536; } // store result in buffer xBuffer[row] = columnCount; } // use bitmask to read depth at seed row // 0000 0000 0000 0000 1111 1111 1111 1111 int targetColumnCount = xBuffer[6] & 65535; // all columns at seed row occupied? bad seed row! if (targetColumnCount == 0) return; // checks if there is electricity available bool isGoodPlace = IsGoodPlace(ref _this, seedCellMiddlePosition); // if demand is too low, only report that a good area was found and return // (or instantly return if area is bad) if (Singleton<SimulationManager>.instance.m_randomizer.Int32(100U) >= demand) { if (isGoodPlace) // no electricity? f**k this. { zoneManager.m_goodAreaFound[(int)zone] = (short)1024; // note that a good area was found } return; } // if area is bad but a good area was found some time ago else if (!isGoodPlace && (int)zoneManager.m_goodAreaFound[(int)zone] > -1024) { if ((int)zoneManager.m_goodAreaFound[(int)zone] == 0) { zoneManager.m_goodAreaFound[(int)zone] = (short)-1; // note that no good area was found today } return; } // let's spawn a building! // STEP 1: this calculates a left and right row range for the building to spawn else { int calculatedLeftRow = 6; int calculatedRightRow = 6; bool firstTry = true; // search loop for plot size finding // The goal is to avoid one cell width holes in the zone grid // the minimum targeted width is 2 while (true) { if (firstTry) // in first try search for exact matching rows { // search for rows left and right of seed row with a similar depth while (calculatedLeftRow != 0 && (xBuffer[calculatedLeftRow - 1] & 65535) == targetColumnCount) --calculatedLeftRow; while (calculatedRightRow != 12 && (xBuffer[calculatedRightRow + 1] & 65535) == targetColumnCount) ++calculatedRightRow; } else // in the second/third try search for any matching rows { // search for rows left and right of seed row with a similar or larger depth while (calculatedLeftRow != 0 && (xBuffer[calculatedLeftRow - 1] & 65535) >= targetColumnCount) --calculatedLeftRow; while (calculatedRightRow != 12 && (xBuffer[calculatedRightRow + 1] & 65535) >= targetColumnCount) ++calculatedRightRow; } int extraLeftRange = calculatedLeftRow; int extraRightRange = calculatedRightRow; // search for further rows with a min depth of 2 while (extraLeftRange != 0 && (xBuffer[extraLeftRange - 1] & 65535) >= 2) --extraLeftRange; while (extraRightRange != 12 && (xBuffer[extraRightRange + 1] & 65535) >= 2) ++extraRightRange; // checks if a exactly one single extra row with min depth of 2 was found // if that is the case, the algorithm will try to preserve space on that side so a 2 cells width building can fit bool exactlyOneRowLeftFound = extraLeftRange != 0 && extraLeftRange == calculatedLeftRow - 1; bool exactlyOneRowRightFound = extraRightRange != 12 && extraRightRange == calculatedRightRow + 1; // 1-cell space found on both sides // goal: preserve space on both sides if (exactlyOneRowLeftFound && exactlyOneRowRightFound) { // if 3 or less regular rows found if (calculatedRightRow - calculatedLeftRow <= 2) { // if target depth 2 or less if (targetColumnCount <= 2) { if (!firstTry) // if second try { // 1x1, 1x2, 2x1, 2x2, 3x1, 3x2 goto selectRandomRows; // --> next step } // --> search again (exact mode off) } // if target depth is at least 3 (but only 3 or less rows found) else { // decrease target depth by one --targetColumnCount; // --> search again (exact mode off) } } // 4 regular rows found else { // reserve space on both sides for 2-cell wide buildings // (++rowLeft;--rowRight;) break; // --> next step } } // 1-cell space found on left side only else if (exactlyOneRowLeftFound) { // if 2 or less regular rows found if (calculatedRightRow - calculatedLeftRow <= 1) { // if target depth 2 or less if (targetColumnCount <= 2) { if (!firstTry) // if second try { goto selectRandomRows; // --> next step } // --> search again (exact mode off) } // if target depth is at least 3 (but only 2 or less rows found) else { // decrease target depth by one --targetColumnCount; // --> search again (exact mode off) } } // 4 regular rows found else { // reserve space on left side for 2-cell wide buildings // (++rowLeft;) goto selectRandomRowsPreserveL; // --> next step } } // 1-cell space found on right side only else if (exactlyOneRowRightFound) { // if 2 or less regular rows found if (calculatedRightRow - calculatedLeftRow <= 1) { // if target depth 2 or less if (targetColumnCount <= 2) { if (!firstTry) // if second try { goto selectRandomRows; // --> next step } } // if target depth is at least 3 (but only 2 or less rows found) else { // decrease target depth by one --targetColumnCount; // --> search again (exact mode off) } } // 4 regular rows found else { // reserve space on right side for 2-cell wide buildings // (--rowRight;) goto selectRandomRowsPreserveR; // --> next step } } // only one row found // we don't want 1-cell wide buildings! else if (calculatedLeftRow == calculatedRightRow) { // if target depth 2 or less if (targetColumnCount <= 2) { if (!firstTry) // if second try { goto selectRandomRows; // --> next step } // --> search again (exact mode off) } // if target depth is at least 3 (but only 1 row found) else { --targetColumnCount; // --> search again (exact mode off) } } // no 1-cell spaces found. Everything is ok! else { goto selectRandomRows; // --> next step } firstTry = false; // turn off exact mode and search again } // fix 1-cell space on both sides // selectRandomRowsPreserveBoth: ++calculatedLeftRow; --calculatedRightRow; goto selectRandomRows; // fix 1-cell space on left side selectRandomRowsPreserveL: ++calculatedLeftRow; goto selectRandomRows; // fix 1-cell space on right side selectRandomRowsPreserveR: --calculatedRightRow; // NEXT STEP: Create an alternative randomized row range for the building to spawn // (alternative width and spawn position) // Goal: Leave no small gaps selectRandomRows: // the randomized row values int randomozedLeftRow; int randomizedRightRow; // if only one cell deep, but 2 or more cells wide // select one of the rows and set the width to 1 if (targetColumnCount == 1 && calculatedRightRow - calculatedLeftRow >= 1) { // select a random row in the valid range calculatedLeftRow += Singleton<SimulationManager>.instance.m_randomizer.Int32((uint)(calculatedRightRow - calculatedLeftRow)); calculatedRightRow = calculatedLeftRow + 1; randomozedLeftRow = calculatedLeftRow + Singleton<SimulationManager>.instance.m_randomizer.Int32(2U); randomizedRightRow = randomozedLeftRow; } else { do { randomozedLeftRow = calculatedLeftRow; randomizedRightRow = calculatedRightRow; if (calculatedRightRow - calculatedLeftRow == 2) // 3 cells wide { // coin toss: reduce width by 1 (taking only from one side) if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0) --randomizedRightRow; else ++randomozedLeftRow; } else if (calculatedRightRow - calculatedLeftRow == 3) // 4 cells wide { // coin toss: reduce width by 2 (taking only from one side) if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0) randomizedRightRow -= 2; else randomozedLeftRow += 2; } else if (calculatedRightRow - calculatedLeftRow == 4) // 5 cells wide { // coin toss: reduce width by 2 from one side and 3 from the other if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0) { calculatedRightRow -= 2; randomizedRightRow -= 3; } else { calculatedLeftRow += 2; randomozedLeftRow += 3; } } else if (calculatedRightRow - calculatedLeftRow == 5) // 6 cells wide { // coin toss: reduce width by 2 from one side and 3 from the other if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0) { calculatedRightRow -= 3; randomizedRightRow -= 2; } else { calculatedLeftRow += 3; randomozedLeftRow += 2; } } else if (calculatedRightRow - calculatedLeftRow >= 6) // 7 cells wide { // check if one range is far away from seed point // reduce width by 2 from that side, also reduce that range by 3 if (calculatedLeftRow == 0 || calculatedRightRow == 12) { if (calculatedLeftRow == 0) { calculatedLeftRow = 3; randomozedLeftRow = 2; } if (calculatedRightRow == 12) { calculatedRightRow = 9; randomizedRightRow = 10; } } // otherwise: // coin toss: reduce width by 2 from one side and 3 from the other else if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0) { calculatedRightRow = calculatedLeftRow + 3; randomizedRightRow = randomozedLeftRow + 2; } else { calculatedLeftRow = calculatedRightRow - 3; randomozedLeftRow = randomizedRightRow - 2; } } } // do this while the selected width or the width range are greater than 4 // TODO this needs to be changed to 8 while (calculatedRightRow - calculatedLeftRow > 3 || randomizedRightRow - randomozedLeftRow > 3); } // STEP 3: Calculate final position, width, depth and zoning mode based on calculated row range int calculatedDepth = 4; int calculatedWidth = calculatedRightRow - calculatedLeftRow + 1; BuildingInfo.ZoningMode calculatedZoningMode = BuildingInfo.ZoningMode.Straight; // stores if there is reserve space for a higher depth bool calculatedSpaceBehindAllColumns = true; for (int row = calculatedLeftRow; row <= calculatedRightRow; ++row) { // calculate the maximum possible depth in the range calculatedDepth = Mathf.Min(calculatedDepth, xBuffer[row] & 65535); if ((xBuffer[row] & 131072) == 0) // check for depth shortened flag { calculatedSpaceBehindAllColumns = false; } } if (calculatedRightRow > calculatedLeftRow) // width at least 2 { // check for left corner flag if ((xBuffer[calculatedLeftRow] & 65536) != 0) { // move building to left side, set corner mode calculatedZoningMode = BuildingInfo.ZoningMode.CornerLeft; randomizedRightRow = calculatedLeftRow + randomizedRightRow - randomozedLeftRow; randomozedLeftRow = calculatedLeftRow; } // check for right corner flag (coin toss if left corner flag found) if ((xBuffer[calculatedRightRow] & 65536) != 0 && (calculatedZoningMode != BuildingInfo.ZoningMode.CornerLeft || Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0)) { // move building to right side, set corner mode calculatedZoningMode = BuildingInfo.ZoningMode.CornerRight; randomozedLeftRow = calculatedRightRow + randomozedLeftRow - randomizedRightRow; randomizedRightRow = calculatedRightRow; } } // STEP 4: Calculate final position, width, depth and zoning mode based on randomized row range int randomizedDepth = 4; int randomizedWidth = randomizedRightRow - randomozedLeftRow + 1; BuildingInfo.ZoningMode randomizedZoningMode = BuildingInfo.ZoningMode.Straight; // stores if there is reserve space for a higher depth bool randomizedSpaceBehindAllColumns = true; for (int row = randomozedLeftRow; row <= randomizedRightRow; ++row) { // calculate the maximum possible depth in the range randomizedDepth = Mathf.Min(randomizedDepth, xBuffer[row] & (int)ushort.MaxValue); if ((xBuffer[row] & 131072) == 0) // check for depth shortened flag { randomizedSpaceBehindAllColumns = false; } } if (randomizedRightRow > randomozedLeftRow) // width at least 2 { // check for left corner flag if ((xBuffer[randomozedLeftRow] & 65536) != 0) { randomizedZoningMode = BuildingInfo.ZoningMode.CornerLeft; // set corner mode } // check for right corner flag (coin toss if left corner flag found) if ((xBuffer[randomizedRightRow] & 65536) != 0 && (randomizedZoningMode != BuildingInfo.ZoningMode.CornerLeft || Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0)) { randomizedZoningMode = BuildingInfo.ZoningMode.CornerRight; // set corner mode } } // STEP 5: Assemble ItemClass information ItemClass.SubService subService = ItemClass.SubService.None; ItemClass.Level level = ItemClass.Level.Level1; ItemClass.Service service; switch (zone) { case ItemClass.Zone.ResidentialLow: service = ItemClass.Service.Residential; subService = ItemClass.SubService.ResidentialLow; break; case ItemClass.Zone.ResidentialHigh: service = ItemClass.Service.Residential; subService = ItemClass.SubService.ResidentialHigh; break; case ItemClass.Zone.CommercialLow: service = ItemClass.Service.Commercial; subService = ItemClass.SubService.CommercialLow; break; case ItemClass.Zone.CommercialHigh: service = ItemClass.Service.Commercial; subService = ItemClass.SubService.CommercialHigh; break; case ItemClass.Zone.Industrial: service = ItemClass.Service.Industrial; break; case ItemClass.Zone.Office: service = ItemClass.Service.Office; subService = ItemClass.SubService.None; break; default: return; } // STEP 6: Find a prefab using either calculated or randomized size, spawn position and zoning mode // The fallback if no corner was found is always straight mode BuildingInfo info = (BuildingInfo)null; Vector3 buildingSpawnPos = Vector3.zero; int finalSpawnRowDouble = 0; // this is the doubled relative spawn position int finalDepth = 0; int finalWidth = 0; BuildingInfo.ZoningMode finalZoningMode = BuildingInfo.ZoningMode.Straight; for (int iteration = 0; iteration < 6; ++iteration) { switch (iteration) { case 0: //corner, calculated if (calculatedZoningMode != BuildingInfo.ZoningMode.Straight) { finalSpawnRowDouble = calculatedLeftRow + calculatedRightRow + 1; finalDepth = calculatedDepth; finalWidth = calculatedWidth; finalZoningMode = calculatedZoningMode; goto default; } else break; case 1: //corner, randomized if (randomizedZoningMode != BuildingInfo.ZoningMode.Straight) { finalSpawnRowDouble = randomozedLeftRow + randomizedRightRow + 1; finalDepth = randomizedDepth; finalWidth = randomizedWidth; finalZoningMode = randomizedZoningMode; goto default; } else break; case 2: //corner, calculated, limited depth if (calculatedZoningMode != BuildingInfo.ZoningMode.Straight && calculatedDepth >= 4) { finalSpawnRowDouble = calculatedLeftRow + calculatedRightRow + 1; finalDepth = !calculatedSpaceBehindAllColumns ? 2 : 3; // prevent 1-cell gaps finalWidth = calculatedWidth; finalZoningMode = calculatedZoningMode; goto default; } else break; case 3: //corner, randomized, limited depth if (randomizedZoningMode != BuildingInfo.ZoningMode.Straight && randomizedDepth >= 4) { finalSpawnRowDouble = randomozedLeftRow + randomizedRightRow + 1; finalDepth = !randomizedSpaceBehindAllColumns ? 2 : 3; // prevent 1-cell gaps finalWidth = randomizedWidth; finalZoningMode = randomizedZoningMode; goto default; } else break; case 4: // straight, calculated finalSpawnRowDouble = calculatedLeftRow + calculatedRightRow + 1; finalDepth = calculatedDepth; finalWidth = calculatedWidth; finalZoningMode = BuildingInfo.ZoningMode.Straight; goto default; case 5: // straight, randomized finalSpawnRowDouble = randomozedLeftRow + randomizedRightRow + 1; finalDepth = randomizedDepth; finalWidth = randomizedWidth; finalZoningMode = BuildingInfo.ZoningMode.Straight; goto default; default: // calculate building spawn position (plot center) buildingSpawnPos = _this.m_position + VectorUtils.X_Y( (float)((double)finalDepth * 0.5 - 4.0) * columnDirection + (float)((double)finalSpawnRowDouble * 0.5 + ((double)seedRow - 6) - 4) * rowDirection); // industrial specialisations if (zone == ItemClass.Zone.Industrial) { ZoneBlock.GetIndustryType(buildingSpawnPos, out subService, out level); } // commercial specialisations else if (zone == ItemClass.Zone.CommercialLow || zone == ItemClass.Zone.CommercialHigh) { ZoneBlock.GetCommercialType(buildingSpawnPos, zone, finalWidth, finalDepth, out subService, out level); } // get district style byte buildingDistrict = districtManager.GetDistrict(buildingSpawnPos); ushort style = districtManager.m_districts.m_buffer[(int)buildingDistrict].m_Style; // find random building info = Singleton<BuildingManager>.instance.GetRandomBuildingInfo(ref Singleton<SimulationManager>.instance.m_randomizer, service, subService, level, finalWidth, finalDepth, finalZoningMode, (int)style); // no building found? go back to switch statement and use different calculations if (info == null) break; // spawn the building! goto spawnBuilding; } } // STEP 7: Spawn the building! spawnBuilding: // No underwater buildings! if (info == null || (double)Singleton<TerrainManager>.instance.WaterLevel(VectorUtils.XZ(buildingSpawnPos)) > (double)buildingSpawnPos.y) return; // Rotate corner buildings correctly float angle = _this.m_angle + 1.570796f; // 0.5*PI = 180 deg if (finalZoningMode == BuildingInfo.ZoningMode.CornerLeft && info.m_zoningMode == BuildingInfo.ZoningMode.CornerRight) { angle -= 1.570796f; finalDepth = finalWidth; } else if (finalZoningMode == BuildingInfo.ZoningMode.CornerRight && info.m_zoningMode == BuildingInfo.ZoningMode.CornerLeft) { angle += 1.570796f; finalDepth = finalWidth; } // Try to spawn the building ushort buildingID; if (Singleton<BuildingManager>.instance.CreateBuilding(out buildingID, ref Singleton<SimulationManager>.instance.m_randomizer, info, buildingSpawnPos, angle, finalDepth, Singleton<SimulationManager>.instance.m_currentBuildIndex)) { ++Singleton<SimulationManager>.instance.m_currentBuildIndex; // Lower demand switch (service) { case ItemClass.Service.Residential: zoneManager.m_actualResidentialDemand = Mathf.Max(0, zoneManager.m_actualResidentialDemand - 5); break; case ItemClass.Service.Commercial: zoneManager.m_actualCommercialDemand = Mathf.Max(0, zoneManager.m_actualCommercialDemand - 5); break; case ItemClass.Service.Industrial: zoneManager.m_actualWorkplaceDemand = Mathf.Max(0, zoneManager.m_actualWorkplaceDemand - 5); break; case ItemClass.Service.Office: zoneManager.m_actualWorkplaceDemand = Mathf.Max(0, zoneManager.m_actualWorkplaceDemand - 5); break; } // Apply high-density building flag switch (zone) { case ItemClass.Zone.ResidentialHigh: case ItemClass.Zone.CommercialHigh: Singleton<BuildingManager>.instance.m_buildings.m_buffer[(int)buildingID].m_flags |= Building.Flags.HighDensity; break; } } zoneManager.m_goodAreaFound[(int)zone] = (short)1024; // note that a good area was found and a building was spawned } }
/// <summary> /// Overlaps the quad of the zone block with a colliding quad and returns a "invalid" bitmask for the colliding cells. Internal helper method. /// </summary> /// <param name="_this"></param> /// <param name="quad"></param> /// <returns></returns> private static ulong OverlapQuad(ref ZoneBlock _this, Quad2 quad) { // width of the zone block int rowCount = _this.RowCount; int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size) Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f; Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x); // bounds of the colliding quad Vector2 collidingQuadMin = quad.Min(); Vector2 collidingQuadMax = quad.Max(); // origin of the zone block // this position is in the center of the 8x8 zone block (4 columns and 4 rows away from the lower corner) Vector2 positionXZ = VectorUtils.XZ(_this.m_position); // the "invalid" bitmask ("0" = valid, "1" = invalid) ulong invalid = 0; for (int row = 0; row < rowCount; ++row) { // calculate 2 relative row positions: // * one 0.1m from previous row // * one 0.1m from next row Vector2 rowNearPreviousLength = ((float)row - 3.9f) * rowDirection; Vector2 rowNearNextLength = ((float)row - 3.1f) * rowDirection; for (int column = 0; column < columnCount; ++column) { // calculate 2 relative column positions: // * one 0.1m from previous column // * one 0.1m from next column Vector2 columnNearPreviousLength = ((float)column - 3.9f) * columnDirection; Vector2 columnNearNextLength = ((float)column - 3.1f) * columnDirection; // middle position of the cell Vector2 cellMiddlePos = positionXZ + (columnNearNextLength + columnNearPreviousLength + rowNearNextLength + rowNearPreviousLength) * 0.5f; if ((double)collidingQuadMin.x <= (double)cellMiddlePos.x + 6.0 && (double)collidingQuadMin.y <= (double)cellMiddlePos.y + 6.0 && ((double)cellMiddlePos.x - 6.0 <= (double)collidingQuadMax.x && (double)cellMiddlePos.y - 6.0 <= (double)collidingQuadMax.y)) { // Create a quad for the cell and intersect it with the colliding quad if (quad.Intersect(new Quad2() { a = positionXZ + columnNearPreviousLength + rowNearPreviousLength, b = positionXZ + columnNearNextLength + rowNearPreviousLength, c = positionXZ + columnNearNextLength + rowNearNextLength, d = positionXZ + columnNearPreviousLength + rowNearNextLength })) { // if the cell is colliding, mark it as "1" invalid |= 1uL << (row << 3 | column); } } } } return invalid; }
/// <summary> /// Marks cells colliding with buildings as occupied and removes the zoning if the building is plopable. /// </summary> /// <param name="_this"></param> /// <param name="blockID"></param> /// <param name="info"></param> /// <param name="building"></param> /// <param name="occupied1"></param> /// <param name="occupied2"></param> /// <param name="zone1"></param> /// <param name="zone2"></param> /// <param name="minX"></param> /// <param name="minZ"></param> /// <param name="maxX"></param> /// <param name="maxZ"></param> private static void CalculateImplementation3(ref ZoneBlock _this, ref ulong zone3, ref ulong zone4, ushort blockID, BuildingInfo info, ref Building building, ref ulong occupied1, ref ulong occupied2, ref ulong zone1, ref ulong zone2, float minX, float minZ, float maxX, float maxZ) { // width of the zone block int rowCount = _this.RowCount; int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size) Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f; Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x); // size of the building int width = building.Width; int length = building.Length; // direction of building width and length vectors Vector2 widthDirection = new Vector2(Mathf.Cos(building.m_angle), Mathf.Sin(building.m_angle)); Vector2 lengthDirection = new Vector2(widthDirection.y, -widthDirection.x); // building width and length vectors (-0.8m tolerance) Vector2 halfWidthVector = widthDirection * (float)((double)width * 4.0 - 0.800000011920929); Vector2 halfLengthVector = lengthDirection * (float)((double)length * 4.0 - 0.800000011920929); if (info.m_circular) { halfWidthVector *= 0.7f; halfLengthVector *= 0.7f; } // position of the building Vector2 buildingPositionXZ = VectorUtils.XZ(building.m_position); // quad of the building lot Quad2 buildingQuad = new Quad2 { a = buildingPositionXZ - halfWidthVector - halfLengthVector, b = buildingPositionXZ + halfWidthVector - halfLengthVector, c = buildingPositionXZ + halfWidthVector + halfLengthVector, d = buildingPositionXZ - halfWidthVector + halfLengthVector }; Vector2 quadMin = buildingQuad.Min(); Vector2 quadMax = buildingQuad.Max(); // return if building not in collision range if ((double)quadMin.x > (double)maxX || (double)quadMin.y > (double)maxZ || ((double)minX > (double)quadMax.x || (double)minZ > (double)quadMax.y)) { return; } // zone block position Vector2 positionXZ = VectorUtils.XZ(_this.m_position); // return if zone block quad does not intersect with building quad if (!new Quad2() { a = (positionXZ - 4f * columnDirection - 4f * rowDirection), b = (positionXZ + (columnCount - 4f) * columnDirection - 4f * rowDirection), c = (positionXZ + (columnCount - 4f) * columnDirection + (float)(rowCount - 4) * rowDirection), d = (positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection) }.Intersect(buildingQuad)) { return; } // Calculate which cells are colliding with the building ulong overlapCellMask = OverlapQuad(ref _this, buildingQuad); if (info.m_buildingAI.ClearOccupiedZoning()) // for non-growables { // set cells as occupied (use occupied2 mask) occupied2 = occupied2 | overlapCellMask; // Use zone1 mask for cells close to road (column 1 and 2) // 72340172838076673 - do not shift // 0000 0001 0000 0001 0000 0001 0000 0001 // 0000 0001 0000 0001 0000 0001 0000 0001 // 144680345676153346 - shift 3 to left // 0000 0010 0000 0010 0000 0010 0000 0010 // 0000 0010 0000 0010 0000 0010 0000 0010 ulong zoneClearMask = overlapCellMask & 72340172838076673UL | (overlapCellMask & 144680345676153346UL) << 3; zoneClearMask = zoneClearMask | zoneClearMask << 1; zoneClearMask = zoneClearMask | zoneClearMask << 2; // clear all 4 bits of each cell zone1 = zone1 & ~zoneClearMask; // Use zone2 mask for cells away to road (column 3 and 4) // 289360691352306692 - shift 2 to right // 0000 0100 0000 0100 0000 0100 0000 0100 // 0000 0100 0000 0100 0000 0100 0000 0100 // 578721382704613384 - shift 1 to left // 0000 1000 0000 1000 0000 1000 0000 1000 // 0000 1000 0000 1000 0000 1000 0000 1000 zoneClearMask = (overlapCellMask & 289360691352306692UL) >> 2 | (overlapCellMask & 578721382704613384UL) << 1; zoneClearMask = zoneClearMask | zoneClearMask << 1; zoneClearMask = zoneClearMask | zoneClearMask << 2; // clear all 4 bits of each cell zone2 = zone2 & ~zoneClearMask; // --- support for deeper zones --- // Use zone3 mask for cells away to road (column 5 and 6) // 1157442765409226768 - shift 4 to right // 0001 0000 0001 0000 0001 0000 0001 0000 // 0001 0000 0001 0000 0001 0000 0001 0000 // 2314885530818453536 - shift 1 to right // 0010 0000 0010 0000 0010 0000 0010 0000 // 0010 0000 0010 0000 0010 0000 0010 0000 zoneClearMask = (overlapCellMask & 1157442765409226768UL) >> 4 | (overlapCellMask & 2314885530818453536UL) >> 1; zoneClearMask = zoneClearMask | zoneClearMask << 1; zoneClearMask = zoneClearMask | zoneClearMask << 2; // clear all 4 bits of each cell zone3 = zone3 & ~zoneClearMask; // Use zone4 mask for cells away to road (column 7 and 8) // 4629771061636907072 - shift 6 to right // 0100 0000 0100 0000 0100 0000 0100 0000 // 0100 0000 0100 0000 0100 0000 0100 0000 // 0x8080808080808080 - shift 3 to right // 1000 0000 1000 0000 1000 0000 1000 0000 // 1000 0000 1000 0000 1000 0000 1000 0000 zoneClearMask = (overlapCellMask & 4629771061636907072UL) >> 6 | (overlapCellMask & 0x8080808080808080UL) >> 3; zoneClearMask = zoneClearMask | zoneClearMask << 1; zoneClearMask = zoneClearMask | zoneClearMask << 2; // clear all 4 bits of each cell zone4 = zone4 & ~zoneClearMask; } else // set cells as occupied (use occupied1 mask) occupied1 = occupied1 | overlapCellMask; }
private static void ApplyZoning(ZoneTool z) { Vector3 m_startPosition = (Vector3)z.GetType().GetField("m_startPosition", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z); Vector3 m_mousePosition = (Vector3)z.GetType().GetField("m_mousePosition", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z); Vector3 m_startDirection = (Vector3)z.GetType().GetField("m_startDirection", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z); Vector2 vector2_1 = VectorUtils.XZ(m_startPosition); Vector2 vector2_2 = VectorUtils.XZ(m_mousePosition); Vector2 vector2_3 = VectorUtils.XZ(m_startDirection); Vector2 vector2_4 = new Vector2(vector2_3.y, -vector2_3.x); float num1 = Mathf.Round((float)((((double)vector2_2.x - (double)vector2_1.x) * (double)vector2_3.x + ((double)vector2_2.y - (double)vector2_1.y) * (double)vector2_3.y) * 0.125)) * 8f; float num2 = Mathf.Round((float)((((double)vector2_2.x - (double)vector2_1.x) * (double)vector2_4.x + ((double)vector2_2.y - (double)vector2_1.y) * (double)vector2_4.y) * 0.125)) * 8f; float num3 = (double)num1 < 0.0 ? -4f : 4f; float num4 = (double)num2 < 0.0 ? -4f : 4f; Quad2 quad2 = new Quad2(); quad2.a = vector2_1 - vector2_3 * num3 - vector2_4 * num4; quad2.b = vector2_1 - vector2_3 * num3 + vector2_4 * (num2 + num4); quad2.c = vector2_1 + vector2_3 * (num1 + num3) + vector2_4 * (num2 + num4); quad2.d = vector2_1 + vector2_3 * (num1 + num3) - vector2_4 * num4; if ((double)num3 == (double)num4) { Vector2 vector2_5 = quad2.b; quad2.b = quad2.d; quad2.d = vector2_5; } Vector2 vector2_6 = quad2.Min(); Vector2 vector2_7 = quad2.Max(); int num5 = Mathf.Max((int)((vector2_6.x - 46f) / 64f + FakeZoneManager.HALFGRID), 0); int num6 = Mathf.Max((int)((vector2_6.y - 46f) / 64f + FakeZoneManager.HALFGRID), 0); int num7 = Mathf.Min((int)((vector2_7.x + 46f) / 64f + FakeZoneManager.HALFGRID), FakeZoneManager.GRIDSIZE - 1); int num8 = Mathf.Min((int)((vector2_7.y + 46f) / 64f + FakeZoneManager.HALFGRID), FakeZoneManager.GRIDSIZE - 1); var instance1 = ZoneManager.instance; bool flag = false; for (int index1 = num6; index1 <= num8; ++index1) { for (int index2 = num5; index2 <= num7; ++index2) { ushort blockIndex = instance1.m_zoneGrid[index1 * FakeZoneManager.GRIDSIZE + index2]; int num9 = 0; while ((int)blockIndex != 0) { Vector3 vector3 = instance1.m_blocks.m_buffer[(int)blockIndex].m_position; if ((double)Mathf.Max(Mathf.Max(vector2_6.x - 46f - vector3.x, vector2_6.y - 46f - vector3.z), Mathf.Max((float)((double)vector3.x - (double)vector2_7.x - 46.0), (float)((double)vector3.z - (double)vector2_7.y - 46.0))) < 0.0 && ApplyZoning(z, blockIndex, ref instance1.m_blocks.m_buffer[(int)blockIndex], quad2)) { flag = true; } blockIndex = instance1.m_blocks.m_buffer[(int)blockIndex].m_nextGridBlock; if (++num9 >= ZoneManager.MAX_BLOCK_COUNT) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace); break; } } } } if (!flag) { return; } bool m_zoning = (bool)z.GetType().GetField("m_validPosition", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z); if (m_zoning) { UsedZone(z, z.m_zone); } EffectInfo effect = instance1.m_properties.m_fillEffect; if (effect == null) { return; } InstanceID instance2 = new InstanceID(); EffectInfo.SpawnArea spawnArea = new EffectInfo.SpawnArea((Vector3)((vector2_1 + vector2_2) * 0.5f), Vector3.up, 1f); Singleton <EffectManager> .instance.DispatchEffect(effect, instance2, spawnArea, Vector3.zero, 0.0f, 1f, Singleton <AudioManager> .instance.DefaultGroup); }
public bool OverlapQuad(Quad2 quad, float minY, float maxY, ItemClass.CollisionType collisionType, ItemClass.Layer layers, ushort ignoreNode1, ushort ignoreNode2, ushort ignoreSegment, ulong[] segmentMask) { return(false); }
private static void TestLine(NetInfo netInfo, Vector3 startPoint, Vector3 endPoint, Vector3 l1, Vector3 l2, IList <GuideLine> lines, ushort segmentId = 0, ushort nodeId = 0) { var p = Util.LineIntersectionPoint(startPoint.xz(), endPoint.xz(), l1.xz(), l2.xz()); // Lines never meet, discard if (!p.HasValue) { return; } var intersect = new Vector3(p.Value.x, 0, p.Value.y); var intersectDistanceSqr = Vector3Extensions.DistanceSquared(intersect, endPoint.Flatten()); // Discard if intersect is silly distance away if (intersectDistanceSqr > Settings.MaxGuideLineQueryDistanceSqr) { return; } var guideDirection = l1.Flatten().DirectionTo(l2.Flatten()); var intersectDirection = l1.Flatten().DirectionTo(intersect); // Ignore guides in the wrong direction if (Mathf.Abs(Vector3Extensions.GetSignedAngleBetween(guideDirection, intersectDirection, Vector3.up)) > 90f) { return; } intersect.y = TerrainManager.instance.SampleRawHeightSmooth(intersect); var intersectDistance = Mathf.Sqrt(intersectDistanceSqr); var line = new GuideLine(l1, intersect, netInfo.m_halfWidth * 2f, intersectDistance, segmentId); int index; if (IsDuplicate(lines, line, out index)) { var d = lines[index]; // If a duplicate, check if it is closer than the duplicate if (Vector3Extensions.DistanceSquared(d.Origin, endPoint) > Vector3Extensions.DistanceSquared(l1, endPoint)) { lines[index] = line; } return; } // Check for intersection with existing nodes var ra = Vector3.Cross(guideDirection, Vector3.up); var quad = new Quad3(l1 + ra, l1 - ra, intersect + ra, intersect - ra); if (NetManager.instance.OverlapQuad(Quad2.XZ(quad), 0, 1280f, ItemClass.CollisionType.Undefined, netInfo.m_class.m_layer, nodeId, 0, segmentId)) { return; } lines.Add(line); }
public static void DestroyBuildings(int seed, InstanceManager.Group group, Vector3 position, float preRadius, float removeRadius, float destructionRadiusMin, float destructionRadiusMax, float burnRadiusMin, float burnRadiusMax, float probability) { int num = Mathf.Max((int)((position.x - preRadius - 72f) / 64f + 135f), 0); int num2 = Mathf.Max((int)((position.z - preRadius - 72f) / 64f + 135f), 0); int num3 = Mathf.Min((int)((position.x + preRadius + 72f) / 64f + 135f), 269); int num4 = Mathf.Min((int)((position.z + preRadius + 72f) / 64f + 135f), 269); Array16 <Building> buildings = Singleton <BuildingManager> .instance.m_buildings; ushort[] buildingGrid = Singleton <BuildingManager> .instance.m_buildingGrid; for (int i = num2; i <= num4; i++) { for (int j = num; j <= num3; j++) { ushort num5 = buildingGrid[i * 270 + j]; int num6 = 0; while (num5 != 0) { ushort nextGridBuilding = buildings.m_buffer[(int)num5].m_nextGridBuilding; Building.Flags flags = buildings.m_buffer[(int)num5].m_flags; if ((flags & (Building.Flags.Created | Building.Flags.Deleted | Building.Flags.Untouchable | Building.Flags.Demolishing)) == Building.Flags.Created) { Vector3 position2 = buildings.m_buffer[(int)num5].m_position; float num7 = VectorUtils.LengthXZ(position2 - position); if (num7 < preRadius) { Randomizer randomizer = new Randomizer((int)num5 | seed << 16); float num8 = (destructionRadiusMax - num7) / Mathf.Max(1f, destructionRadiusMax - destructionRadiusMin); float num9 = (burnRadiusMax - num7) / Mathf.Max(1f, burnRadiusMax - burnRadiusMin); bool flag = false; bool flag2 = (float)randomizer.Int32(10000u) < num8 * probability * 10000f; bool flag3 = (float)randomizer.Int32(10000u) < num9 * probability * 10000f; if (removeRadius != 0f && num7 - 72f < removeRadius) { BuildingInfo info = buildings.m_buffer[(int)num5].Info; if (info.m_circular) { float num10 = (float)(buildings.m_buffer[(int)num5].Width + buildings.m_buffer[(int)num5].Length) * 2f; flag = (num7 < removeRadius + num10); } else { float angle = buildings.m_buffer[(int)num5].m_angle; Vector2 a = VectorUtils.XZ(position2); Vector2 vector = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); Vector2 vector2 = new Vector2(vector.y, -vector.x); vector *= (float)buildings.m_buffer[(int)num5].Width * 4f; vector2 *= (float)buildings.m_buffer[(int)num5].Length * 4f; Quad2 quad = default(Quad2); quad.a = a - vector - vector2; quad.b = a + vector - vector2; quad.c = a + vector + vector2; quad.d = a - vector + vector2; float num11 = VectorUtils.LengthXZ(position - new Vector3(quad.a.x, position2.y, quad.a.y)); float num12 = VectorUtils.LengthXZ(position - new Vector3(quad.b.x, position2.y, quad.b.y)); float num13 = VectorUtils.LengthXZ(position - new Vector3(quad.c.x, position2.y, quad.c.y)); float num14 = VectorUtils.LengthXZ(position - new Vector3(quad.d.x, position2.y, quad.d.y)); flag = (quad.Intersect(VectorUtils.XZ(position)) || num11 < removeRadius || num12 < removeRadius || num13 < removeRadius || num14 < removeRadius); } } if (flag) { BuildingInfo info2 = buildings.m_buffer[(int)num5].Info; info2.m_buildingAI.CollapseBuilding(num5, ref buildings.m_buffer[(int)num5], group, false, true, Mathf.RoundToInt(num9 * 255f)); } else if (flag2) { BuildingInfo info3 = buildings.m_buffer[(int)num5].Info; ItemClass.Level lvl = (ItemClass.Level)buildings.m_buffer[(int)num5].m_level; float p = 0.5f; if (info3.m_buildingAI as OfficeBuildingAI != null || info3.m_buildingAI as CommercialBuildingAI != null || info3.m_buildingAI as IndustrialBuildingAI != null) { switch (lvl) { case ItemClass.Level.Level1: p = 1f; break; case ItemClass.Level.Level2: p = 0.6f; break; case ItemClass.Level.Level3: p = 0.2f; break; } } else if (info3.m_buildingAI as ResidentialBuildingAI != null) { switch (lvl) { case ItemClass.Level.Level1: p = 1f; break; case ItemClass.Level.Level2: p = 0.8f; break; case ItemClass.Level.Level3: p = 0.6f; break; case ItemClass.Level.Level4: p = 0.4f; break; case ItemClass.Level.Level5: p = 0.2f; break; } } // Large buildings are tougher float s = Mathf.Sqrt(buildings.m_buffer[(int)num5].Length * buildings.m_buffer[(int)num5].Width); if (s > 4) { p -= s / 16; } // Make shelters a little more useful if ((flags & Building.Flags.Evacuating) == Building.Flags.Evacuating) { p -= 0.2f; } if (p > 0 && (float)randomizer.Int32(10000u) < p * 10000f) { //Debug.Log("Destroyed: " + info3.name + " (" + info3.m_buildingAI.name + "), level: " + lvl.ToString()); info3.m_buildingAI.CollapseBuilding(num5, ref buildings.m_buffer[(int)num5], group, false, false, Mathf.RoundToInt(num9 * 255f)); } } else if (flag3 && (flags & Building.Flags.Collapsed) == Building.Flags.None && buildings.m_buffer[(int)num5].m_fireIntensity == 0) { BuildingInfo info4 = buildings.m_buffer[(int)num5].Info; info4.m_buildingAI.BurnBuilding(num5, ref buildings.m_buffer[(int)num5], group, false); } } } num5 = nextGridBuilding; if (++num6 >= 49152) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } }
/// <summary> /// Compares zone block with other block. /// </summary> /// <param name="_this"></param> /// <param name="other"></param> /// <param name="xBuffer"></param> /// <param name="zone"></param> /// <param name="startPos"></param> /// <param name="xDir"></param> /// <param name="zDir"></param> /// <param name="quad"></param> private static void CheckBlock(ref ZoneBlock _this, ushort otherBlockID, ref ZoneBlock other, int[] xBuffer, ItemClass.Zone zone, Vector2 startPos, Vector2 xDir, Vector2 zDir, Quad2 quad) { // difference of 2 radian angles (360 deg = 2*PI * 0.6366197f = 4f) // that means an angle difference of 90 deg would result in 1f float angleDiff = Mathf.Abs(other.m_angle - _this.m_angle) * 0.6366197f; float rightAngleDiff = angleDiff - Mathf.Floor(angleDiff); // check if the zone block and the other zone block are in right angle (0 90 180 270 deg), otherwise return if ((double)rightAngleDiff >= 0.00999999977648258 && (double)rightAngleDiff <= 0.990000009536743) return; // width of other block int otherRowCount = other.RowCount; int otherColumnCount = ZoneBlockDetour.GetColumnCount(ref other); // modified Vector2 otherColumnDirection = new Vector2(Mathf.Cos(other.m_angle), Mathf.Sin(other.m_angle)) * 8f; Vector2 otherRowDirection = new Vector2(otherColumnDirection.y, -otherColumnDirection.x); ulong otherValidFreeCellMask = other.m_valid & ~(other.m_occupied1 | other.m_occupied2); Vector2 otherPositionXZ = VectorUtils.XZ(other.m_position); // check if the zone block quad of the other block intersects with the zone block, otherwise return if (!quad.Intersect(new Quad2() { a = otherPositionXZ - 4f * otherColumnDirection - 4f * otherRowDirection, b = otherPositionXZ + (otherColumnCount - 4f) * otherColumnDirection - 4f * otherRowDirection, c = otherPositionXZ + (otherColumnCount - 4f) * otherColumnDirection + (float)(otherRowCount - 4) * otherRowDirection, d = otherPositionXZ - 4f * otherColumnDirection + (float)(otherRowCount - 4) * otherRowDirection })) { return; } // Cycle through all cells of the other block for (int row = 0; row < otherRowCount; ++row) { Vector2 rowMiddleLength = ((float)row - 3.5f) * otherRowDirection; for (int column = 0; column < otherColumnCount; ++column) { // check if the cell is unoccupied and zoned correctly if ((otherValidFreeCellMask & 1UL << (row << 3 | column)) != 0UL && GetZoneDeep(ref other, otherBlockID, column, row) == zone) { Vector2 columnMiddleLength = ((float)column - 3.5f) * otherColumnDirection; // Calculate the distance between the seed point and the current cell Vector2 cellStartPosDistance = otherPositionXZ + columnMiddleLength + rowMiddleLength - startPos; // dot product divided by 8*8 (normalized to cell size) // cell distance in x direction between the seed cell and the current cell float distColumnDirection = (float)(((double)cellStartPosDistance.x * (double)xDir.x + (double)cellStartPosDistance.y * (double)xDir.y) * (1.0 / 64.0)); // cell distance in z direction (rowDirection between the seed cell and the current cell float distRowDirection = (float)(((double)cellStartPosDistance.x * (double)zDir.x + (double)cellStartPosDistance.y * (double)zDir.y) * (1.0 / 64.0)); // rounded distances int roundedDistColumnDirection = Mathf.RoundToInt(distColumnDirection); // must be >=0 (behind road) and <=6 (7 cells to the back) int roundedDistRowDirection = Mathf.RoundToInt(distRowDirection); // must be >=-6 and <=6 (6 cells to the left or 6 cells to the right) // TODO raise numbers and array size for 8x8 lot support if (roundedDistColumnDirection >= 0 && roundedDistColumnDirection <= 6 && (roundedDistRowDirection >= -6 && roundedDistRowDirection <= 6) // cells must be aligned in the same grid + 1% tolerance && ((double)Mathf.Abs(distColumnDirection - (float)roundedDistColumnDirection) < 0.0125000001862645 && (double)Mathf.Abs(distRowDirection - (float)roundedDistRowDirection) < 0.0125000001862645 // must have road access or be behind one of the cells touching the road of the seed block // column == 0 means access to the road belonging to the zone block // roundedDistColumnDirection != 0 && (column == 0 || roundedDistColumnDirection != 0))) { // Mark the cell in the column mask (in the row buffer array) xBuffer[roundedDistRowDirection + 6] |= 1 << roundedDistColumnDirection; // If the column touches the road, also mark it in the second part of the int mask if (column == 0) { xBuffer[roundedDistRowDirection + 6] |= 1 << roundedDistColumnDirection + 16; // shift by 16 } } } } } }
public static bool Prefix(Quad2 quad, float minY, float maxY, ItemClass.CollisionType collisionType, ItemClass.Layer requireLayers, ItemClass.Layer forbidLayers, ushort ignoreNode1, ushort ignoreNode2, ushort ignoreSegment, ulong[] segmentMask, ref bool __result) { NetManager instance = Singleton <NetManager> .instance; Vector2 vector = quad.Min(); Vector2 vector2 = quad.Max(); int num = Mathf.Max((int)((vector.x - 64f) / 64f + 135f), 0); int num2 = Mathf.Max((int)((vector.y - 64f) / 64f + 135f), 0); int num3 = Mathf.Min((int)((vector2.x + 64f) / 64f + 135f), 269); int num4 = Mathf.Min((int)((vector2.y + 64f) / 64f + 135f), 269); ushort num5 = 0; ushort num6 = 0; if (ignoreSegment != 0) { ushort startNode = instance.m_segments.m_buffer[ignoreSegment].m_startNode; ushort endNode = instance.m_segments.m_buffer[ignoreSegment].m_endNode; NetNode.Flags flags = instance.m_nodes.m_buffer[startNode].m_flags; NetNode.Flags flags2 = instance.m_nodes.m_buffer[endNode].m_flags; if ((flags & NetNode.Flags.Middle) != 0) { num5 = startNode; } if ((flags2 & NetNode.Flags.Middle) != 0) { num6 = endNode; } } bool result = false; for (int i = num2; i <= num4; i++) { for (int j = num; j <= num3; j++) { ushort num7 = instance.m_segmentGrid[i * 270 + j]; int num8 = 0; while (num7 != 0) { if (num7 != ignoreSegment && ((long)instance.m_updatedSegments[num7 >> 6] & (1L << (int)num7)) == 0) { NetInfo info = instance.m_segments.m_buffer[num7].Info; if ((object)info != null) { ItemClass.Layer collisionLayers = info.m_netAI.GetCollisionLayers(); if ((object)info != null && (requireLayers == ItemClass.Layer.None || (collisionLayers & requireLayers) != 0) && (collisionLayers & forbidLayers) == ItemClass.Layer.None) { ushort startNode2 = instance.m_segments.m_buffer[num7].m_startNode; ushort endNode2 = instance.m_segments.m_buffer[num7].m_endNode; if (startNode2 != ignoreNode1 && startNode2 != ignoreNode2 && startNode2 != num5 && startNode2 != num6 && endNode2 != ignoreNode1 && endNode2 != ignoreNode2 && endNode2 != num5 && endNode2 != num6) { Vector3 position = instance.m_nodes.m_buffer[startNode2].m_position; Vector3 position2 = instance.m_nodes.m_buffer[endNode2].m_position; // NON-STOCK CODE STARTS if (CSURUtil.IsCSUROffset(instance.m_nodes.m_buffer[startNode2].Info)) { bool lht = false; if (instance.m_nodes.m_buffer[startNode2].CountSegments() != 0) { float collisionHalfWidth = Mathf.Max(3f, (instance.m_nodes.m_buffer[startNode2].Info.m_halfWidth + instance.m_nodes.m_buffer[startNode2].Info.m_pavementWidth) / 2f); NetSegment mysegment = CSURUtil.GetSameInfoSegment(instance.m_nodes.m_buffer[startNode2]); Vector3 direction = CSURUtil.CheckNodeEq(mysegment.m_startNode, instance.m_nodes.m_buffer[startNode2]) ? mysegment.m_startDirection : -mysegment.m_endDirection; if ((mysegment.m_flags & NetSegment.Flags.Invert) != 0) { lht = true; } // normal to the right hand side Vector3 normal = new Vector3(direction.z, 0, -direction.x).normalized; position = position + (lht ? -collisionHalfWidth : collisionHalfWidth) * normal; } } if (CSURUtil.IsCSUROffset(instance.m_nodes.m_buffer[endNode2].Info)) { bool lht = false; if (instance.m_nodes.m_buffer[endNode2].CountSegments() != 0) { float collisionHalfWidth = Mathf.Max(3f, (instance.m_nodes.m_buffer[endNode2].Info.m_halfWidth + instance.m_nodes.m_buffer[endNode2].Info.m_pavementWidth) / 2f); NetSegment mysegment = CSURUtil.GetSameInfoSegment(instance.m_nodes.m_buffer[endNode2]); Vector3 direction = CSURUtil.CheckNodeEq(mysegment.m_startNode, instance.m_nodes.m_buffer[endNode2]) ? mysegment.m_startDirection : -mysegment.m_endDirection; if ((mysegment.m_flags & NetSegment.Flags.Invert) != 0) { lht = true; } // normal to the right hand side Vector3 normal = new Vector3(direction.z, 0, -direction.x).normalized; position2 = position2 + (lht ? -collisionHalfWidth : collisionHalfWidth) * normal; } } // NON-STOCK CODE ENDS float num9 = Mathf.Max(Mathf.Max(vector.x - 64f - position.x, vector.y - 64f - position.z), Mathf.Max(position.x - vector2.x - 64f, position.z - vector2.y - 64f)); float num10 = Mathf.Max(Mathf.Max(vector.x - 64f - position2.x, vector.y - 64f - position2.z), Mathf.Max(position2.x - vector2.x - 64f, position2.z - vector2.y - 64f)); if ((num9 < 0f || num10 < 0f) && instance.m_segments.m_buffer[num7].OverlapQuad(num7, quad, minY, maxY, collisionType)) { if (segmentMask == null) { __result = true; return(false); } segmentMask[num7 >> 6] |= (ulong)(1L << (int)num7); result = true; } } } } } num7 = instance.m_segments.m_buffer[num7].m_nextGridSegment; if (++num8 >= 36864) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } __result = result; return(false); }
public static void CalculateBlock1(ref ZoneBlock _this, ushort blockID) { // skip zone blocks which are not in use if (((int)_this.m_flags & 3) != ZoneBlock.FLAG_CREATED) return; // width of the zone block int rowCount = _this.RowCount; int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size) Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f; Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x); // origin of the zone block // this position is in the center of the 8x8 zone block (4 columns and 4 rows away from the lower corner) Vector2 positionXZ = VectorUtils.XZ(_this.m_position); // area of the zone block (8x4 cells) Quad2 zoneBlockQuad = new Quad2() { a = positionXZ - 4f * columnDirection - 4f * rowDirection, b = positionXZ + (columnCount - 4f) * columnDirection - 4f * rowDirection, c = positionXZ + (columnCount - 4f) * columnDirection + (float)(rowCount - 4) * rowDirection, d = positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection }; Vector2 quadMin = zoneBlockQuad.Min(); Vector2 quadMax = zoneBlockQuad.Max(); NetManager netManager = Singleton<NetManager>.instance; // calculate which net segment grid cells are touched by this zone block int gridMinX = Mathf.Max((int)(((double)quadMin.x - 64.0) / 64.0 + 135.0), 0); int gridMinY = Mathf.Max((int)(((double)quadMin.y - 64.0) / 64.0 + 135.0), 0); int gridMaxX = Mathf.Min((int)(((double)quadMax.x + 64.0) / 64.0 + 135.0), 269); int gridMaxY = Mathf.Min((int)(((double)quadMax.y + 64.0) / 64.0 + 135.0), 269); // This bitmask stores which which cells are "valid" and which are "invalid" // (e.g. colliding with existing buildings or height too steep) // This mask limits the maximum size of a zone block to 64 cells (e.g. 8x8) // Sort order: (row 8|col 8)(row 8|col 7)...(row 8|col 2)(row 8|col 1)(row 7|col 4)(row 7|col 3)...(row 1|col 1) ulong valid = ulong.MaxValue; bool quadOutOfArea = Singleton<GameAreaManager>.instance.QuadOutOfArea(zoneBlockQuad); // Mark cells which are on too steep terrain or outside of the purchased tiles as invalid for (int row = 0; row < rowCount; ++row) { // calculate 3 relative row positions: // * One in between 2 cell grid points // * one 0.1m from previous row // * one 0.1m from next row Vector2 rowMiddleLength = ((float)row - 3.5f) * rowDirection; Vector2 rowNearPreviousLength = ((float)row - 3.9f) * rowDirection; Vector2 rowNearNextLength = ((float)row - 3.1f) * rowDirection; // calculate terrain height of the row (5 columns away from zone block origin) // that's where the road is float height = Singleton<TerrainManager>.instance.SampleRawHeightSmooth(VectorUtils.X_Y(positionXZ + rowMiddleLength - 5f * columnDirection)); for (int column = 0; column < columnCount; ++column) { // calculate 2 relative column positions: // * one 0.1m from previous column // * one 0.1m from next column Vector2 columnNearPreviousLength = ((float)column - 3.9f) * columnDirection; Vector2 columnNearNextLength = ((float)column - 3.1f) * columnDirection; // calculate terrain height of the cell (row middle, side away from road) float cellHeight = Singleton<TerrainManager>.instance.SampleRawHeightSmooth(VectorUtils.X_Y(positionXZ + rowMiddleLength + columnNearNextLength)); // if the height difference between road and cell is greater than 8m, mark the cell as invalid if ((double)Mathf.Abs(cellHeight - height) > 8.0) // TODO maybe this should be raised for 8 cell deep zones? { valid &= ~(1UL << (row << 3 | column)); } else if (quadOutOfArea) { // if the cell is outside of the purchased tiles, mark the cell as invalid if (Singleton<GameAreaManager>.instance.QuadOutOfArea(new Quad2() { a = positionXZ + columnNearPreviousLength + rowNearPreviousLength, b = positionXZ + columnNearNextLength + rowNearPreviousLength, c = positionXZ + columnNearNextLength + rowNearNextLength, d = positionXZ + columnNearPreviousLength + rowNearNextLength })) valid &= ~(1UL << (row << 3 | column)); } } } // Mark cells which are overlapped by network segments as invalid for (int gridY = gridMinY; gridY <= gridMaxY; ++gridY) { for (int gridX = gridMinX; gridX <= gridMaxX; ++gridX) { // cycle through all net segments in the grid cell ushort segmentID = netManager.m_segmentGrid[gridY * 270 + gridX]; int counter = 0; while ((int)segmentID != 0) { if (netManager.m_segments.m_buffer[(int)segmentID].Info.m_class.m_layer == ItemClass.Layer.Default) { ushort startNode = netManager.m_segments.m_buffer[(int)segmentID].m_startNode; ushort endNode = netManager.m_segments.m_buffer[(int)segmentID].m_endNode; Vector3 startNodePos = netManager.m_nodes.m_buffer[(int)startNode].m_position; Vector3 endNodePos = netManager.m_nodes.m_buffer[(int)endNode].m_position; // check if the segment (one of its nodes) is in the area of zone block if ((double)Mathf.Max(Mathf.Max(quadMin.x - 64f - startNodePos.x, quadMin.y - 64f - startNodePos.z), Mathf.Max((float)((double)startNodePos.x - (double)quadMax.x - 64.0), (float)((double)startNodePos.z - (double)quadMax.y - 64.0))) < 0.0 || (double)Mathf.Max(Mathf.Max(quadMin.x - 64f - endNodePos.x, quadMin.y - 64f - endNodePos.z), Mathf.Max((float)((double)endNodePos.x - (double)quadMax.x - 64.0), (float)((double)endNodePos.z - (double)quadMax.y - 64.0))) < 0.0) { // Mark zone cells overlapped by network segments as invalid CalculateImplementation1(ref _this, blockID, segmentID, ref netManager.m_segments.m_buffer[(int)segmentID], ref valid, quadMin.x, quadMin.y, quadMax.x, quadMax.y); } } // next segment in grid cell (linked list) segmentID = netManager.m_segments.m_buffer[(int)segmentID].m_nextGridSegment; if (++counter >= 36864) { CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace); break; } } } } // This part marks all cells as invalid which are behind existing invalid cells (so that there are no cells with no road access) // 0000 0100 0000 0100 0000 0100 0000 0100 // 0000 0100 0000 0100 0000 0100 0000 0100 ulong mask = 144680345676153346; for (int iteration = 0; iteration < 7; ++iteration) { valid = valid & ~mask | valid & valid << 1 & mask; mask <<= 1; } // apply the new mask, reset shared mask _this.m_valid = valid; _this.m_shared = 0UL; }
internal static void CheckBlock(ZoneBlock b, ref ZoneBlock other, int[] xBuffer, ItemClass.Zone zone, Vector2 startPos, Vector2 xDir, Vector2 zDir, Quad2 quad) { float f1 = Mathf.Abs(other.m_angle - b.m_angle) * 0.6366197f; float num1 = f1 - Mathf.Floor(f1); if ((double)num1 >= 0.00999999977648258 && (double)num1 <= 0.990000009536743) return; int rowCount = other.RowCount; Vector2 vector2_1 = new Vector2(Mathf.Cos(other.m_angle), Mathf.Sin(other.m_angle)) * 8f; Vector2 vector2_2 = new Vector2(vector2_1.y, -vector2_1.x); ulong num2 = other.m_valid & (ulong)~((long)other.m_occupied1 | (long)other.m_occupied2); Vector2 vector2_3 = VectorUtils.XZ(other.m_position); if (!quad.Intersect(new Quad2() { a = vector2_3 - 4f * vector2_1 - 4f * vector2_2, b = vector2_3 - 4f * vector2_2, c = vector2_3 + (float)(rowCount - 4) * vector2_2, d = vector2_3 - 4f * vector2_1 + (float)(rowCount - 4) * vector2_2 })) return; for (int z = 0; z < rowCount; ++z) { Vector2 vector2_4 = ((float)z - 3.5f) * vector2_2; for (int x = 0; x < 4; ++x) { if (((long)num2 & 1L << (z << 3 | x)) != 0L && other.GetZone(x, z) == zone) { Vector2 vector2_5 = ((float)x - 3.5f) * vector2_1; Vector2 vector2_6 = vector2_3 + vector2_5 + vector2_4 - startPos; float f2 = (float)(((double)vector2_6.x * (double)xDir.x + (double)vector2_6.y * (double)xDir.y) * (1.0 / 64.0)); float f3 = (float)(((double)vector2_6.x * (double)zDir.x + (double)vector2_6.y * (double)zDir.y) * (1.0 / 64.0)); int num3 = Mathf.RoundToInt(f2); int num4 = Mathf.RoundToInt(f3); if (num3 >= 0 && num3 <= 6 && (num4 >= -6 && num4 <= 6) && ((double)Mathf.Abs(f2 - (float)num3) < 0.0125000001862645 && (double)Mathf.Abs(f3 - (float)num4) < 0.0125000001862645 && (x == 0 || num3 != 0))) { xBuffer[num4 + 6] |= 1 << num3; if (x == 0) xBuffer[num4 + 6] |= 1 << num3 + 16; } } } } }
private static void ApplyZoning(ZoneTool z) { Vector3 m_startPosition = (Vector3)z.GetType().GetField("m_startPosition", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z); Vector3 m_mousePosition = (Vector3)z.GetType().GetField("m_mousePosition", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z); Vector3 m_startDirection = (Vector3)z.GetType().GetField("m_startDirection", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z); Vector2 vector2_1 = VectorUtils.XZ(m_startPosition); Vector2 vector2_2 = VectorUtils.XZ(m_mousePosition); Vector2 vector2_3 = VectorUtils.XZ(m_startDirection); Vector2 vector2_4 = new Vector2(vector2_3.y, -vector2_3.x); float num1 = Mathf.Round((float)((((double)vector2_2.x - (double)vector2_1.x) * (double)vector2_3.x + ((double)vector2_2.y - (double)vector2_1.y) * (double)vector2_3.y) * 0.125)) * 8f; float num2 = Mathf.Round((float)((((double)vector2_2.x - (double)vector2_1.x) * (double)vector2_4.x + ((double)vector2_2.y - (double)vector2_1.y) * (double)vector2_4.y) * 0.125)) * 8f; float num3 = (double)num1 < 0.0 ? -4f : 4f; float num4 = (double)num2 < 0.0 ? -4f : 4f; Quad2 quad2 = new Quad2(); quad2.a = vector2_1 - vector2_3 * num3 - vector2_4 * num4; quad2.b = vector2_1 - vector2_3 * num3 + vector2_4 * (num2 + num4); quad2.c = vector2_1 + vector2_3 * (num1 + num3) + vector2_4 * (num2 + num4); quad2.d = vector2_1 + vector2_3 * (num1 + num3) - vector2_4 * num4; if ((double)num3 == (double)num4) { Vector2 vector2_5 = quad2.b; quad2.b = quad2.d; quad2.d = vector2_5; } Vector2 vector2_6 = quad2.Min(); Vector2 vector2_7 = quad2.Max(); int num5 = Mathf.Max((int)((vector2_6.x - 46f) / 64f + FakeZoneManager.HALFGRID), 0); int num6 = Mathf.Max((int)((vector2_6.y - 46f) / 64f + FakeZoneManager.HALFGRID), 0); int num7 = Mathf.Min((int)((vector2_7.x + 46f) / 64f + FakeZoneManager.HALFGRID), FakeZoneManager.GRIDSIZE - 1); int num8 = Mathf.Min((int)((vector2_7.y + 46f) / 64f + FakeZoneManager.HALFGRID), FakeZoneManager.GRIDSIZE - 1); var instance1 = ZoneManager.instance; bool flag = false; for (int index1 = num6; index1 <= num8; ++index1) { for (int index2 = num5; index2 <= num7; ++index2) { ushort blockIndex = FakeZoneManager.zoneGrid[index1 * FakeZoneManager.GRIDSIZE + index2]; int num9 = 0; while ((int)blockIndex != 0) { Vector3 vector3 = instance1.m_blocks.m_buffer[(int)blockIndex].m_position; if ((double)Mathf.Max(Mathf.Max(vector2_6.x - 46f - vector3.x, vector2_6.y - 46f - vector3.z), Mathf.Max((float)((double)vector3.x - (double)vector2_7.x - 46.0), (float)((double)vector3.z - (double)vector2_7.y - 46.0))) < 0.0 && ApplyZoning(z, blockIndex, ref instance1.m_blocks.m_buffer[(int)blockIndex], quad2)) flag = true; blockIndex = instance1.m_blocks.m_buffer[(int)blockIndex].m_nextGridBlock; if (++num9 >= 32768) { CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace); break; } } } } if (!flag) return; bool m_zoning = (bool)z.GetType().GetField("m_validPosition", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z); if (m_zoning) z.GetType().GetMethod("UsedZone", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(z, new object[] { z.m_zone }); EffectInfo effect = instance1.m_properties.m_fillEffect; if (effect == null) return; InstanceID instance2 = new InstanceID(); EffectInfo.SpawnArea spawnArea = new EffectInfo.SpawnArea((Vector3)((vector2_1 + vector2_2) * 0.5f), Vector3.up, 1f); Singleton<EffectManager>.instance.DispatchEffect(effect, instance2, spawnArea, Vector3.zero, 0.0f, 1f, Singleton<AudioManager>.instance.DefaultGroup); }
private static void CalculateImplementation2(ref ZoneBlock z, ushort blockID, ref ZoneBlock other, ref ulong valid, ref ulong shared, float minX, float minZ, float maxX, float maxZ) { if (((int)other.m_flags & 1) == 0 || (double)Mathf.Abs(other.m_position.x - z.m_position.x) >= 92.0 || (double)Mathf.Abs(other.m_position.z - z.m_position.z) >= 92.0) return; bool flag1 = ((int)other.m_flags & 2) != 0; int rowCount1 = z.RowCount; int rowCount2 = other.RowCount; Vector2 vector2_1 = new Vector2(Mathf.Cos(z.m_angle), Mathf.Sin(z.m_angle)) * 8f; Vector2 vector2_2 = new Vector2(vector2_1.y, -vector2_1.x); Vector2 vector2_3 = new Vector2(Mathf.Cos(other.m_angle), Mathf.Sin(other.m_angle)) * 8f; Vector2 vector2_4 = new Vector2(vector2_3.y, -vector2_3.x); Vector2 vector2_5 = VectorUtils.XZ(other.m_position); Quad2 quad = new Quad2(); quad.a = vector2_5 - 4f * vector2_3 - 4f * vector2_4; quad.b = vector2_5 + 0.0f * vector2_3 - 4f * vector2_4; quad.c = vector2_5 + 0.0f * vector2_3 + (float)(rowCount2 - 4) * vector2_4; quad.d = vector2_5 - 4f * vector2_3 + (float)(rowCount2 - 4) * vector2_4; Vector2 vector2_6 = quad.Min(); Vector2 vector2_7 = quad.Max(); if ((double)vector2_6.x > (double)maxX || (double)vector2_6.y > (double)maxZ || ((double)minX > (double)vector2_7.x || (double)minZ > (double)vector2_7.y)) return; Vector2 vector2_8 = VectorUtils.XZ(z.m_position); Quad2 quad2_1 = new Quad2(); quad2_1.a = vector2_8 - 4f * vector2_1 - 4f * vector2_2; quad2_1.b = vector2_8 + 0.0f * vector2_1 - 4f * vector2_2; quad2_1.c = vector2_8 + 0.0f * vector2_1 + (float)(rowCount1 - 4) * vector2_2; quad2_1.d = vector2_8 - 4f * vector2_1 + (float)(rowCount1 - 4) * vector2_2; if (!quad2_1.Intersect(quad)) return; for (int z1 = 0; z1 < rowCount1; ++z1) { Vector2 vector2_9 = ((float)z1 - 3.99f) * vector2_2; Vector2 vector2_10 = ((float)z1 - 3.01f) * vector2_2; quad2_1.a = vector2_8 - 4f * vector2_1 + vector2_9; quad2_1.b = vector2_8 + 0.0f * vector2_1 + vector2_9; quad2_1.c = vector2_8 + 0.0f * vector2_1 + vector2_10; quad2_1.d = vector2_8 - 4f * vector2_1 + vector2_10; if (quad2_1.Intersect(quad)) { for (int x1 = 0; (long)x1 < 4L && ((long)valid & 1L << (z1 << 3 | x1)) != 0L; ++x1) { Vector2 vector2_11 = ((float)x1 - 3.99f) * vector2_1; Vector2 vector2_12 = ((float)x1 - 3.01f) * vector2_1; Vector2 p = vector2_8 + (vector2_12 + vector2_11 + vector2_10 + vector2_9) * 0.5f; if (Quad2.Intersect(quad.a - vector2_3 - vector2_4, quad.b + vector2_3 - vector2_4, quad.c + vector2_3 + vector2_4, quad.d - vector2_3 + vector2_4, p)) { Quad2 quad2_2 = new Quad2(); quad2_2.a = vector2_8 + vector2_11 + vector2_9; quad2_2.b = vector2_8 + vector2_12 + vector2_9; quad2_2.c = vector2_8 + vector2_12 + vector2_10; quad2_2.d = vector2_8 + vector2_11 + vector2_10; bool flag2 = true; bool flag3 = false; for (int z2 = 0; z2 < rowCount2 && flag2; ++z2) { Vector2 vector2_13 = ((float)z2 - 3.99f) * vector2_4; Vector2 vector2_14 = ((float)z2 - 3.01f) * vector2_4; for (int x2 = 0; (long)x2 < 4L && flag2; ++x2) { if (((long)other.m_valid & ~(long)other.m_shared & 1L << (z2 << 3 | x2)) != 0L) { Vector2 vector2_15 = ((float)x2 - 3.99f) * vector2_3; Vector2 vector2_16 = ((float)x2 - 3.01f) * vector2_3; float num1 = Vector2.SqrMagnitude(vector2_5 + (vector2_16 + vector2_15 + vector2_14 + vector2_13) * 0.5f - p); if ((double)num1 < 144.0) { if (!flag1) { float f = Mathf.Abs(other.m_angle - z.m_angle) * 0.6366197f; float num2 = f - Mathf.Floor(f); if ((double)num1 < 0.00999999977648258 && ((double)num2 < 0.00999999977648258 || (double)num2 > 0.990000009536743)) { if (x1 < x2 || x1 == x2 && z.m_buildIndex < other.m_buildIndex) other.m_shared |= (ulong)(1L << (z2 << 3 | x2)); else flag3 = true; } else if (quad2_2.Intersect(new Quad2() { a = vector2_5 + vector2_15 + vector2_13, b = vector2_5 + vector2_16 + vector2_13, c = vector2_5 + vector2_16 + vector2_14, d = vector2_5 + vector2_15 + vector2_14 })) { if (x2 >= 4 && x1 >= 4 || x2 < 4 && x1 < 4) { if (x2 >= 2 && x1 >= 2 || x2 < 2 && x1 < 2) { if (z.m_buildIndex < other.m_buildIndex) other.m_valid &= (ulong)~(1L << (z2 << 3 | x2)); else flag2 = false; } else if (x2 < 2) flag2 = false; else other.m_valid &= (ulong)~(1L << (z2 << 3 | x2)); } else if (x2 < 4) flag2 = false; else other.m_valid &= (ulong)~(1L << (z2 << 3 | x2)); } } if ((double)num1 < 36.0 && x1 < 4 && x2 < 4) { ItemClass.Zone zone1 = z.GetZone(x1, z1); ItemClass.Zone zone2 = other.GetZone(x2, z2); if (zone1 == ItemClass.Zone.Unzoned) z.SetZone(x1, z1, zone2); else if (zone2 == ItemClass.Zone.Unzoned && !flag1) other.SetZone(x2, z2, zone1); } } } } } if (!flag2) { valid = valid & (ulong)~(1L << (z1 << 3 | x1)); break; } if (flag3) shared = shared | (ulong)(1L << (z1 << 3 | x1)); } } } } }
private static bool ApplyZoning(ZoneTool _this, ushort blockIndex, ref ZoneBlock data, Quad2 quad2) { int rowCount = data.RowCount; int columnCount = ZoneBlockDetour.GetColumnCount(ref data); // modified Vector2 vector2_1 = new Vector2(Mathf.Cos(data.m_angle), Mathf.Sin(data.m_angle)) * 8f; Vector2 vector2_2 = new Vector2(vector2_1.y, -vector2_1.x); Vector2 vector2_3 = VectorUtils.XZ(data.m_position); if (!new Quad2() { a = (vector2_3 - 4f * vector2_1 - 4f * vector2_2), b = (vector2_3 + 4f * vector2_1 - 4f * vector2_2), c = (vector2_3 + 4f * vector2_1 + (float)(rowCount - 4) * vector2_2), d = (vector2_3 - 4f * vector2_1 + (float)(rowCount - 4) * vector2_2) }.Intersect(quad2)) return false; bool flag = false; var m_zoning = IsZoningEnabled(_this); // custom var m_dezoning = IsDezoningEnabled(_this); // custom var blockID = ZoneBlockDetour.FindBlockId(ref data); // modified for (int z = 0; z < rowCount; ++z) { Vector2 vector2_4 = ((float)z - 3.5f) * vector2_2; for (int x = 0; x < columnCount; ++x) // custom { Vector2 vector2_5 = ((float)x - 3.5f) * vector2_1; Vector2 p = vector2_3 + vector2_5 + vector2_4; if (quad2.Intersect(p)) { if (m_zoning) { if ((_this.m_zone == ItemClass.Zone.Unzoned || ZoneBlockDetour.GetZoneDeep(ref data, blockID, x, z) == ItemClass.Zone.Unzoned) && ZoneBlockDetour.SetZoneDeep(ref data, blockID, x, z, _this.m_zone)) flag = true; } else if (m_dezoning && ZoneBlockDetour.SetZoneDeep(ref data, blockID, x, z, ItemClass.Zone.Unzoned)) flag = true; } } } if (!flag) return false; data.RefreshZoning(blockIndex); return true; }
// Detours public static void SimulationStep(ref ZoneBlock zoneBlock, ushort blockID) { // This is the decompiled ZoneBlock.SimulationStep() method // Segments which were changed are marked with "begin mod" and "end mod" if (Debugger.Enabled && debugCount < 10) { debugCount++; Debugger.LogFormat("Building Themes: Detoured ZoneBlock.SimulationStep was called. blockID: {0}, position: {1}.", blockID, zoneBlock.m_position); } ZoneManager zoneManager = Singleton <ZoneManager> .instance; int rowCount = zoneBlock.RowCount; float m_angle = zoneBlock.m_angle; Vector2 xDirection = new Vector2(Mathf.Cos(m_angle), Mathf.Sin(m_angle)) * 8f; Vector2 zDirection = new Vector2(xDirection.y, -xDirection.x); ulong num = zoneBlock.m_valid & ~(zoneBlock.m_occupied1 | zoneBlock.m_occupied2); int spawnpointRow = 0; ItemClass.Zone zone = ItemClass.Zone.Unzoned; int num3 = 0; while (num3 < 4 && zone == ItemClass.Zone.Unzoned) { spawnpointRow = Singleton <SimulationManager> .instance.m_randomizer.Int32((uint)rowCount); if ((num & 1uL << (spawnpointRow << 3)) != 0uL) { zone = zoneBlock.GetZone(0, spawnpointRow); } num3++; } DistrictManager instance2 = Singleton <DistrictManager> .instance; Vector3 m_position = (Vector3)zoneBlock.m_position; byte district = instance2.GetDistrict(m_position); int num4; switch (zone) { case ItemClass.Zone.ResidentialLow: num4 = zoneManager.m_actualResidentialDemand; num4 += instance2.m_districts.m_buffer[(int)district].CalculateResidentialLowDemandOffset(); break; case ItemClass.Zone.ResidentialHigh: num4 = zoneManager.m_actualResidentialDemand; num4 += instance2.m_districts.m_buffer[(int)district].CalculateResidentialHighDemandOffset(); break; case ItemClass.Zone.CommercialLow: num4 = zoneManager.m_actualCommercialDemand; num4 += instance2.m_districts.m_buffer[(int)district].CalculateCommercialLowDemandOffset(); break; case ItemClass.Zone.CommercialHigh: num4 = zoneManager.m_actualCommercialDemand; num4 += instance2.m_districts.m_buffer[(int)district].CalculateCommercialHighDemandOffset(); break; case ItemClass.Zone.Industrial: num4 = zoneManager.m_actualWorkplaceDemand; num4 += instance2.m_districts.m_buffer[(int)district].CalculateIndustrialDemandOffset(); break; case ItemClass.Zone.Office: num4 = zoneManager.m_actualWorkplaceDemand; num4 += instance2.m_districts.m_buffer[(int)district].CalculateOfficeDemandOffset(); break; default: return; } Vector2 a = VectorUtils.XZ(m_position); Vector2 vector3 = a - 3.5f * xDirection + ((float)spawnpointRow - 3.5f) * zDirection; int[] tmpXBuffer = zoneManager.m_tmpXBuffer; for (int i = 0; i < 13; i++) { tmpXBuffer[i] = 0; } Quad2 quad = default(Quad2); quad.a = a - 4f * xDirection + ((float)spawnpointRow - 10f) * zDirection; quad.b = a + 3f * xDirection + ((float)spawnpointRow - 10f) * zDirection; quad.c = a + 3f * xDirection + ((float)spawnpointRow + 2f) * zDirection; quad.d = a - 4f * xDirection + ((float)spawnpointRow + 2f) * zDirection; Vector2 vector4 = quad.Min(); Vector2 vector5 = quad.Max(); //begin mod int num5 = Mathf.Max((int)((vector4.x - 46f) / 64f + _zoneGridHalfResolution), 0); int num6 = Mathf.Max((int)((vector4.y - 46f) / 64f + _zoneGridHalfResolution), 0); int num7 = Mathf.Min((int)((vector5.x + 46f) / 64f + _zoneGridHalfResolution), _zoneGridResolution - 1); int num8 = Mathf.Min((int)((vector5.y + 46f) / 64f + _zoneGridHalfResolution), _zoneGridResolution - 1); //end mod for (int j = num6; j <= num8; j++) { for (int k = num5; k <= num7; k++) { //begin mod ushort num9 = zoneManager.m_zoneGrid[j * _zoneGridResolution + k]; //end mod int num10 = 0; while (num9 != 0) { Vector3 positionVar = zoneManager.m_blocks.m_buffer[(int)num9].m_position; float num11 = Mathf.Max(Mathf.Max(vector4.x - 46f - positionVar.x, vector4.y - 46f - positionVar.z), Mathf.Max(positionVar.x - vector5.x - 46f, positionVar.z - vector5.y - 46f)); if (num11 < 0f) { _CheckBlock.Invoke(zoneBlock, new object[] { zoneManager.m_blocks.m_buffer[(int)num9], tmpXBuffer, zone, vector3, xDirection, zDirection, quad }); } num9 = zoneManager.m_blocks.m_buffer[(int)num9].m_nextGridBlock; if (++num10 >= 49152) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } for (int l = 0; l < 13; l++) { uint num12 = (uint)tmpXBuffer[l]; int num13 = 0; bool flag = (num12 & 196608u) == 196608u; bool flag2 = false; while ((num12 & 1u) != 0u) { num13++; flag2 = ((num12 & 65536u) != 0u); num12 >>= 1; } if (num13 == 5 || num13 == 6) { if (flag2) { num13 -= Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) + 2; } else { num13 = 4; } num13 |= 131072; } else if (num13 == 7) { num13 = 4; num13 |= 131072; } if (flag) { num13 |= 65536; } tmpXBuffer[l] = num13; } int num14 = tmpXBuffer[6] & 65535; if (num14 == 0) { return; } bool flag3 = (bool)_IsGoodPlace.Invoke(zoneBlock, new object[] { vector3 }); if (Singleton <SimulationManager> .instance.m_randomizer.Int32(100u) >= num4) { if (flag3) { zoneManager.m_goodAreaFound[(int)zone] = 1024; } return; } if (!flag3 && zoneManager.m_goodAreaFound[(int)zone] > -1024) { if (zoneManager.m_goodAreaFound[(int)zone] == 0) { zoneManager.m_goodAreaFound[(int)zone] = -1; } return; } int num15 = 6; int num16 = 6; bool flag4 = true; while (true) { if (flag4) { while (num15 != 0) { if ((tmpXBuffer[num15 - 1] & 65535) != num14) { break; } num15--; } while (num16 != 12) { if ((tmpXBuffer[num16 + 1] & 65535) != num14) { break; } num16++; } } else { while (num15 != 0) { if ((tmpXBuffer[num15 - 1] & 65535) < num14) { break; } num15--; } while (num16 != 12) { if ((tmpXBuffer[num16 + 1] & 65535) < num14) { break; } num16++; } } int num17 = num15; int num18 = num16; while (num17 != 0) { if ((tmpXBuffer[num17 - 1] & 65535) < 2) { break; } num17--; } while (num18 != 12) { if ((tmpXBuffer[num18 + 1] & 65535) < 2) { break; } num18++; } bool flag5 = num17 != 0 && num17 == num15 - 1; bool flag6 = num18 != 12 && num18 == num16 + 1; if (flag5 && flag6) { if (num16 - num15 > 2) { break; } if (num14 <= 2) { if (!flag4) { goto Block_34; } } else { num14--; } } else if (flag5) { if (num16 - num15 > 1) { goto Block_36; } if (num14 <= 2) { if (!flag4) { goto Block_38; } } else { num14--; } } else if (flag6) { if (num16 - num15 > 1) { goto Block_40; } if (num14 <= 2) { if (!flag4) { goto Block_42; } } else { num14--; } } else { if (num15 != num16) { goto IL_884; } if (num14 <= 2) { if (!flag4) { goto Block_45; } } else { num14--; } } flag4 = false; } num15++; num16--; Block_34: goto IL_891; Block_36: num15++; Block_38: goto IL_891; Block_40: num16--; Block_42: Block_45: IL_884: IL_891: int num19; int num20; if (num14 == 1 && num16 - num15 >= 1) { num15 += Singleton <SimulationManager> .instance.m_randomizer.Int32((uint)(num16 - num15)); num16 = num15 + 1; num19 = num15 + Singleton <SimulationManager> .instance.m_randomizer.Int32(2u); num20 = num19; } else { do { num19 = num15; num20 = num16; if (num16 - num15 == 2) { if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0) { num20--; } else { num19++; } } else if (num16 - num15 == 3) { if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0) { num20 -= 2; } else { num19 += 2; } } else if (num16 - num15 == 4) { if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0) { num16 -= 2; num20 -= 3; } else { num15 += 2; num19 += 3; } } else if (num16 - num15 == 5) { if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0) { num16 -= 3; num20 -= 2; } else { num15 += 3; num19 += 2; } } else if (num16 - num15 >= 6) { if (num15 == 0 || num16 == 12) { if (num15 == 0) { num15 = 3; num19 = 2; } if (num16 == 12) { num16 = 9; num20 = 10; } } else if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0) { num16 = num15 + 3; num20 = num19 + 2; } else { num15 = num16 - 3; num19 = num20 - 2; } } }while (num16 - num15 > 3 || num20 - num19 > 3); } int depth_A = 4; int width_A = num16 - num15 + 1; BuildingInfo.ZoningMode zoningMode = BuildingInfo.ZoningMode.Straight; bool flag7 = true; for (int m = num15; m <= num16; m++) { depth_A = Mathf.Min(depth_A, tmpXBuffer[m] & 65535); if ((tmpXBuffer[m] & 131072) == 0) { flag7 = false; } } if (num16 > num15) { if ((tmpXBuffer[num15] & 65536) != 0) { zoningMode = BuildingInfo.ZoningMode.CornerLeft; num20 = num15 + num20 - num19; num19 = num15; } if ((tmpXBuffer[num16] & 65536) != 0 && (zoningMode != BuildingInfo.ZoningMode.CornerLeft || Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0)) { zoningMode = BuildingInfo.ZoningMode.CornerRight; num19 = num16 + num19 - num20; num20 = num16; } } int depth_B = 4; int width_B = num20 - num19 + 1; BuildingInfo.ZoningMode zoningMode2 = BuildingInfo.ZoningMode.Straight; bool flag8 = true; for (int n = num19; n <= num20; n++) { depth_B = Mathf.Min(depth_B, tmpXBuffer[n] & 65535); if ((tmpXBuffer[n] & 131072) == 0) { flag8 = false; } } if (num20 > num19) { if ((tmpXBuffer[num19] & 65536) != 0) { zoningMode2 = BuildingInfo.ZoningMode.CornerLeft; } if ((tmpXBuffer[num20] & 65536) != 0 && (zoningMode2 != BuildingInfo.ZoningMode.CornerLeft || Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0)) { zoningMode2 = BuildingInfo.ZoningMode.CornerRight; } } ItemClass.SubService subService = ItemClass.SubService.None; ItemClass.Level level = ItemClass.Level.Level1; ItemClass.Service service; switch (zone) { case ItemClass.Zone.ResidentialLow: service = ItemClass.Service.Residential; subService = ItemClass.SubService.ResidentialLow; break; case ItemClass.Zone.ResidentialHigh: service = ItemClass.Service.Residential; subService = ItemClass.SubService.ResidentialHigh; break; case ItemClass.Zone.CommercialLow: service = ItemClass.Service.Commercial; subService = ItemClass.SubService.CommercialLow; break; case ItemClass.Zone.CommercialHigh: service = ItemClass.Service.Commercial; subService = ItemClass.SubService.CommercialHigh; break; case ItemClass.Zone.Industrial: service = ItemClass.Service.Industrial; break; case ItemClass.Zone.Office: service = ItemClass.Service.Office; subService = ItemClass.SubService.None; break; default: return; } BuildingInfo buildingInfo = null; Vector3 vector6 = Vector3.zero; int num25_row = 0; int length = 0; int width = 0; BuildingInfo.ZoningMode zoningMode3 = BuildingInfo.ZoningMode.Straight; int num28 = 0; // begin mod int depth_alt = Mathf.Min(depth_A, 4); int width_alt = width_A; // end mod while (num28 < 8) // while (num28 < 6) { switch (num28) { // Corner cases case 0: if (zoningMode != BuildingInfo.ZoningMode.Straight) { num25_row = num15 + num16 + 1; length = depth_A; width = width_A; zoningMode3 = zoningMode; goto IL_D6A; } break; case 1: if (zoningMode2 != BuildingInfo.ZoningMode.Straight) { num25_row = num19 + num20 + 1; length = depth_B; width = width_B; zoningMode3 = zoningMode2; goto IL_D6A; } break; case 2: if (zoningMode != BuildingInfo.ZoningMode.Straight) { if (depth_A >= 4) { num25_row = num15 + num16 + 1; length = ((!flag7) ? 2 : 3); width = width_A; zoningMode3 = zoningMode; goto IL_D6A; } } break; case 3: if (zoningMode2 != BuildingInfo.ZoningMode.Straight) { if (depth_B >= 4) { num25_row = num19 + num20 + 1; length = ((!flag8) ? 2 : 3); width = width_B; zoningMode3 = zoningMode2; goto IL_D6A; } } break; // begin mod case 4: if (zoningMode != BuildingInfo.ZoningMode.Straight) { if (width_alt > 1) { width_alt--; } else if (depth_alt > 1) { depth_alt--; width_alt = width_A; } else { break; } if (width_alt == width_A) { num25_row = num15 + num16 + 1; } else { if (zoningMode == BuildingInfo.ZoningMode.CornerLeft) { num25_row = num15 + num16 + 1 - (width_A - width_alt); } else { num25_row = num15 + num16 + 1 + (width_A - width_alt); } } length = depth_alt; width = width_alt; zoningMode3 = zoningMode; num28--; goto IL_D6A; } break; // end mod // Straight cases case 5: num25_row = num15 + num16 + 1; length = depth_A; width = width_A; zoningMode3 = BuildingInfo.ZoningMode.Straight; goto IL_D6A; case 6: // begin mod // reset variables depth_alt = Mathf.Min(depth_A, 4); width_alt = width_A; // end mod //int width_B = num20 - num19 + 1; num25_row = num19 + num20 + 1; length = depth_B; width = width_B; zoningMode3 = BuildingInfo.ZoningMode.Straight; goto IL_D6A; // begin mod case 7: if (width_alt > 1) { width_alt--; } else { break; } if (width_alt == width_A) { num25_row = num15 + num16 + 1; } else if (width_A % 2 != width_alt % 2) { num25_row = num15 + num16; } else { num25_row = num15 + num16 + 1; } length = depth_alt; width = width_alt; zoningMode3 = BuildingInfo.ZoningMode.Straight; num28--; goto IL_D6A; // end mod default: goto IL_D6A; } IL_DF0: num28++; continue; IL_D6A: vector6 = m_position + VectorUtils.X_Y(((float)length * 0.5f - 4f) * xDirection + ((float)num25_row * 0.5f + (float)spawnpointRow - 10f) * zDirection); if (zone == ItemClass.Zone.Industrial) { ZoneBlock.GetIndustryType(vector6, out subService, out level); } else if (zone == ItemClass.Zone.CommercialLow || zone == ItemClass.Zone.CommercialHigh) { ZoneBlock.GetCommercialType(vector6, zone, width, length, out subService, out level); } byte district2 = instance2.GetDistrict(vector6); ushort style = instance2.m_districts.m_buffer[(int)district2].m_Style; // begin mod // Here we are calling a custom getRandomBuildingInfo method buildingInfo = BuildingManagerDetour.GetRandomBuildingInfo_Spawn(vector6, ref Singleton <SimulationManager> .instance.m_randomizer, service, subService, level, width, length, zoningMode3, style); // end mod if (buildingInfo != null) { // begin mod // If the depth of the found prefab is smaller than the one we were looking for, recalculate the size // This is done by checking the position of every prop // Plots only get shrinked when no assets are placed on the extra space // This is needed for themes which only contain small buildings (e.g. 1x2) // because those buildings would occupy more space than needed! if (buildingInfo.GetWidth() == width && buildingInfo.GetLength() != length) { // Calculate the z position of the furthest away prop float biggestPropPosZ = 0; if (buildingInfo.m_props != null) { foreach (var prop in buildingInfo.m_props) { if (prop == null) { continue; } biggestPropPosZ = Mathf.Max(biggestPropPosZ, buildingInfo.m_expandFrontYard ? prop.m_position.z : -prop.m_position.z); } } // Check if the furthest away prop is outside of the bounds of the prefab float occupiedExtraSpace = biggestPropPosZ - buildingInfo.GetLength() * 4; if (occupiedExtraSpace <= 0) { // No? Then shrink the plot to the prefab length so no space is wasted! length = buildingInfo.GetLength(); } else { // Yes? Shrink the plot so all props are in the bounds int newLength = buildingInfo.GetLength() + Mathf.CeilToInt(occupiedExtraSpace / 8); length = Mathf.Min(length, newLength); } vector6 = m_position + VectorUtils.X_Y(((float)length * 0.5f - 4f) * xDirection + ((float)num25_row * 0.5f + (float)spawnpointRow - 10f) * zDirection); } // This block handles Corner buildings. We always shrink them else if (buildingInfo.GetLength() == width && buildingInfo.GetWidth() != length) { length = buildingInfo.GetWidth(); vector6 = m_position + VectorUtils.X_Y(((float)length * 0.5f - 4f) * xDirection + ((float)num25_row * 0.5f + (float)spawnpointRow - 10f) * zDirection); } // end mod if (Debugger.Enabled) { Debugger.LogFormat("Found prefab: {5} - {0}, {1}, {2}, {3} x {4}", service, subService, level, width, length, buildingInfo.name); } break; } if (Debugger.Enabled) { } goto IL_DF0; } if (buildingInfo == null) { if (Debugger.Enabled) { Debugger.LogFormat("No prefab found: {0}, {1}, {2}, {3} x {4}", service, subService, level, width, length); } return; } float num29 = Singleton <TerrainManager> .instance.WaterLevel(VectorUtils.XZ(vector6)); if (num29 > vector6.y) { return; } float num30 = m_angle + 1.57079637f; if (zoningMode3 == BuildingInfo.ZoningMode.CornerLeft && buildingInfo.m_zoningMode == BuildingInfo.ZoningMode.CornerRight) { num30 -= 1.57079637f; length = width; } else if (zoningMode3 == BuildingInfo.ZoningMode.CornerRight && buildingInfo.m_zoningMode == BuildingInfo.ZoningMode.CornerLeft) { num30 += 1.57079637f; length = width; } ushort num31; if (Singleton <BuildingManager> .instance.CreateBuilding(out num31, ref Singleton <SimulationManager> .instance.m_randomizer, buildingInfo, vector6, num30, length, Singleton <SimulationManager> .instance.m_currentBuildIndex)) { Singleton <SimulationManager> .instance.m_currentBuildIndex += 1u; switch (service) { case ItemClass.Service.Residential: zoneManager.m_actualResidentialDemand = Mathf.Max(0, zoneManager.m_actualResidentialDemand - 5); break; case ItemClass.Service.Commercial: zoneManager.m_actualCommercialDemand = Mathf.Max(0, zoneManager.m_actualCommercialDemand - 5); break; case ItemClass.Service.Industrial: zoneManager.m_actualWorkplaceDemand = Mathf.Max(0, zoneManager.m_actualWorkplaceDemand - 5); break; case ItemClass.Service.Office: zoneManager.m_actualWorkplaceDemand = Mathf.Max(0, zoneManager.m_actualWorkplaceDemand - 5); break; } switch (zone) { case ItemClass.Zone.ResidentialHigh: case ItemClass.Zone.CommercialHigh: { Building[] expr_FD7_cp_0 = Singleton <BuildingManager> .instance.m_buildings.m_buffer; ushort expr_FD7_cp_1 = num31; expr_FD7_cp_0[(int)expr_FD7_cp_1].m_flags = (expr_FD7_cp_0[(int)expr_FD7_cp_1].m_flags | Building.Flags.HighDensity); break; } } } zoneManager.m_goodAreaFound[(int)zone] = 1024; }
public static bool Prefix(ref NetSegment __instance, ushort segmentID, Quad2 quad, float minY, float maxY, ItemClass.CollisionType collisionType) { if ((__instance.m_flags & (NetSegment.Flags.Created | NetSegment.Flags.Deleted)) != NetSegment.Flags.Created) { return(false); } NetInfo info = __instance.Info; if (!info.m_canCollide) { return(false); } float collisionHalfWidth = info.m_netAI.GetCollisionHalfWidth(); Vector2 vector = quad.Min(); Vector2 vector2 = quad.Max(); Bezier3 bezier = default(Bezier3); bezier.a = Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_startNode].m_position; bezier.d = Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_endNode].m_position; // NON-STOCK CODE STARTS if (CSURUtil.IsCSUROffset(Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_startNode].Info)) { var width = (Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_startNode].Info.m_halfWidth + Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_startNode].Info.m_pavementWidth) / 2f; bool lht = false; Vector3 direction = __instance.m_startDirection; if ((__instance.m_flags & NetSegment.Flags.Invert) != 0) { lht = true; } // normal to the right hand side Vector3 normal = new Vector3(direction.z, 0, -direction.x).normalized; bezier.a = bezier.a + (lht ? -width : width) * normal; } if (CSURUtil.IsCSUROffset(Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_endNode].Info)) { bool lht = false; var width = (Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_endNode].Info.m_halfWidth + Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_endNode].Info.m_pavementWidth) / 2f; Vector3 direction = -__instance.m_endDirection; if ((__instance.m_flags & NetSegment.Flags.Invert) != 0) { lht = true; } // normal to the right hand side Vector3 normal = new Vector3(direction.z, 0, -direction.x).normalized; bezier.d = bezier.d + (lht ? -width : width) * normal; } // NON-STOCK CODE ENDS NetSegment.CalculateMiddlePoints(bezier.a, __instance.m_startDirection, bezier.d, __instance.m_endDirection, true, true, out bezier.b, out bezier.c); // NON-STOCK CODE STARTS float laneOffsetS = 0; float startOffsetS = 0; float endOffsetS = 0; bool IsCSURSLaneS = CSURUtil.IsCSURSLane(Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_startNode].Info, ref laneOffsetS, ref startOffsetS, ref endOffsetS); float laneOffsetE = 0; float startOffsetE = 0; float endOffsetE = 0; bool IsCSURSLaneE = CSURUtil.IsCSURSLane(Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_endNode].Info, ref laneOffsetE, ref startOffsetE, ref endOffsetE); Vector3 newBezierA1 = Vector3.zero; Vector3 newBezierB1 = Vector3.zero; Vector3 newBezierC1 = Vector3.zero; Vector3 newBezierD1 = Vector3.zero; if (IsCSURSLaneS || IsCSURSLaneE) { float vehicleLaneNum = CSURUtil.CountCSURSVehicleLanes(Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_startNode].Info); float otherLaneNum = CSURUtil.CountCSURSOtherLanes(Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_startNode].Info); float laneNum = vehicleLaneNum + otherLaneNum; startOffsetS = startOffsetS * 3.75f - laneNum * 1.875f + 1.875f + otherLaneNum * 3.75f; endOffsetE = endOffsetE * 3.75f - laneNum * 1.875f + 1.875f + otherLaneNum * 3.75f; if ((__instance.m_flags & NetSegment.Flags.Invert) != 0) { startOffsetS = -startOffsetS; endOffsetE = -endOffsetE; } if (!IsCSURSLaneS) { startOffsetS = 0; } if (!IsCSURSLaneE) { endOffsetE = 0; } //EG: before patch: point1-point4 is 1.5*3.75 //After patch, point1-point4 is (1 1.3333 1.6667 2)*3.75 newBezierA1 = bezier.a + (new Vector3(__instance.m_startDirection.z, 0, -__instance.m_startDirection.x).normalized) * (startOffsetS); Vector3 newBezierBDir = VectorUtils.NormalizeXZ(bezier.Tangent(0.333f)); newBezierB1 = bezier.b + (new Vector3(newBezierBDir.z, 0, -newBezierBDir.x).normalized) * (startOffsetS * 0.667f + endOffsetE * 0.333f); Vector3 newBezierCDir = VectorUtils.NormalizeXZ(bezier.Tangent(0.667f)); newBezierC1 = bezier.c + (new Vector3(newBezierCDir.z, 0, -newBezierCDir.x).normalized) * (startOffsetS * 0.333f + endOffsetE * 0.667f); newBezierD1 = bezier.d + (new Vector3(-__instance.m_endDirection.z, 0, __instance.m_endDirection.x).normalized) * (endOffsetE); bezier.a = newBezierA1; bezier.b = newBezierB1; bezier.c = newBezierC1; bezier.d = newBezierD1; } // NON-STOCK CODE ENDS Vector3 vector3 = bezier.Min() + new Vector3(0f - collisionHalfWidth, info.m_minHeight, 0f - collisionHalfWidth); Vector3 vector4 = bezier.Max() + new Vector3(collisionHalfWidth, info.m_maxHeight, collisionHalfWidth); ItemClass.CollisionType collisionType2 = info.m_netAI.GetCollisionType(); if (vector3.x <= vector2.x && vector3.z <= vector2.y && vector.x <= vector4.x && vector.y <= vector4.z && ItemClass.CheckCollisionType(minY, maxY, vector3.y, vector4.y, collisionType, collisionType2)) { int num = 16; info.m_netAI.GetTerrainModifyRange(out float start, out float end); start *= 0.5f; end = 1f - (1f - end) * 0.5f; float t = start; Vector3 vector5 = bezier.Position(t); Vector3 vector6 = bezier.Tangent(t); vector6 = new Vector3(0f - vector6.z, 0f, vector6.x).normalized *collisionHalfWidth; Vector3 a = vector5 + vector6; Vector3 vector7 = vector5 - vector6; float endRadius = info.m_netAI.GetEndRadius(); if (info.m_clipSegmentEnds && endRadius != 0f && start == 0f && (Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_startNode].m_flags & (NetNode.Flags.End | NetNode.Flags.Bend | NetNode.Flags.Junction)) != 0) { Vector3 vector8 = vector5; vector8.x += vector6.x * 0.8f - vector6.z * 0.6f * endRadius / collisionHalfWidth; vector8.z += vector6.z * 0.8f + vector6.x * 0.6f * endRadius / collisionHalfWidth; Vector3 vector9 = vector5; vector9.x -= vector6.x * 0.8f + vector6.z * 0.6f * endRadius / collisionHalfWidth; vector9.z -= vector6.z * 0.8f - vector6.x * 0.6f * endRadius / collisionHalfWidth; Vector3 d = vector5; d.x += vector6.x * 0.3f - vector6.z * endRadius / collisionHalfWidth; d.z += vector6.z * 0.3f + vector6.x * endRadius / collisionHalfWidth; Vector3 c = vector5; c.x -= vector6.x * 0.3f + vector6.z * endRadius / collisionHalfWidth; c.z -= vector6.z * 0.3f - vector6.x * endRadius / collisionHalfWidth; vector3.y = vector5.y + info.m_minHeight; vector4.y = vector5.y + info.m_maxHeight; if (ItemClass.CheckCollisionType(minY, maxY, vector3.y, vector4.y, collisionType, collisionType2)) { if (quad.Intersect(Quad2.XZ(a, vector7, vector9, vector8))) { return(true); } if (quad.Intersect(Quad2.XZ(vector8, vector9, c, d))) { return(true); } } } for (int i = 1; i <= num; i++) { t = start + (end - start) * (float)i / (float)num; vector5 = bezier.Position(t); vector6 = bezier.Tangent(t); vector6 = new Vector3(0f - vector6.z, 0f, vector6.x).normalized *collisionHalfWidth; Vector3 vector10 = vector5 + vector6; Vector3 vector11 = vector5 - vector6; vector3.y = Mathf.Min(Mathf.Min(a.y, vector10.y), Mathf.Min(vector11.y, vector7.y)) + info.m_minHeight; vector4.y = Mathf.Max(Mathf.Max(a.y, vector10.y), Mathf.Max(vector11.y, vector7.y)) + info.m_maxHeight; if (ItemClass.CheckCollisionType(minY, maxY, vector3.y, vector4.y, collisionType, collisionType2) && quad.Intersect(Quad2.XZ(a, vector10, vector11, vector7))) { return(true); } a = vector10; vector7 = vector11; } if (info.m_clipSegmentEnds && endRadius != 0f && end == 1f && (Singleton <NetManager> .instance.m_nodes.m_buffer[__instance.m_endNode].m_flags & (NetNode.Flags.End | NetNode.Flags.Bend | NetNode.Flags.Junction)) != 0) { Vector3 vector12 = vector5; vector12.x += vector6.x * 0.8f + vector6.z * 0.6f * endRadius / collisionHalfWidth; vector12.z += vector6.z * 0.8f - vector6.x * 0.6f * endRadius / collisionHalfWidth; Vector3 vector13 = vector5; vector13.x -= vector6.x * 0.8f - vector6.z * 0.6f * endRadius / collisionHalfWidth; vector13.z -= vector6.z * 0.8f + vector6.x * 0.6f * endRadius / collisionHalfWidth; Vector3 b = vector5; b.x += vector6.x * 0.3f + vector6.z * endRadius / collisionHalfWidth; b.z += vector6.z * 0.3f - vector6.x * endRadius / collisionHalfWidth; Vector3 c2 = vector5; c2.x -= vector6.x * 0.3f - vector6.z * endRadius / collisionHalfWidth; c2.z -= vector6.z * 0.3f + vector6.x * endRadius / collisionHalfWidth; vector3.y = vector5.y + info.m_minHeight; vector4.y = vector5.y + info.m_maxHeight; if (ItemClass.CheckCollisionType(minY, maxY, vector3.y, vector4.y, collisionType, collisionType2)) { if (quad.Intersect(Quad2.XZ(a, vector12, vector13, vector7))) { return(true); } if (quad.Intersect(Quad2.XZ(vector12, b, c2, vector13))) { return(true); } } } } return(false); }
public static void Prefix(ref Vehicle vehicleData, ref Vehicle.Frame frameData, ref float maxSpeed, float maxBraking) { VehicleInfo vehicleInfo = vehicleData.Info; Vector3 position = frameData.m_position; Vector2 xz = VectorUtils.XZ(frameData.m_position); float y = position.y; Quaternion rotation = frameData.m_rotation; Vector3 size = vehicleInfo.m_generatedInfo.m_size; float vehicleTopY = y + vehicleInfo.m_generatedInfo.m_size.y - vehicleInfo.m_generatedInfo.m_negativeHeight; Vector2 forwardDir = VectorUtils.XZ(rotation * Vector3.forward).normalized; Vector2 rightDir = VectorUtils.XZ(rotation * Vector3.right).normalized; Quad2 passingQuad = new Quad2 { a = xz - 0.5f * size.z * forwardDir - 0.5f * size.x * rightDir, b = xz - 0.5f * size.z * forwardDir + 0.5f * size.x * rightDir, c = xz + 0.5f * size.z * forwardDir + 0.5f * size.x * rightDir, d = xz + 0.5f * size.z * forwardDir - 0.5f * size.x * rightDir }; float halfWidth = size.x / 2; Quad2 quad01 = QuadUtils.GetSegmentQuad(vehicleData.m_targetPos0, vehicleData.m_targetPos1, halfWidth); Quad2 quad12 = QuadUtils.GetSegmentQuad(vehicleData.m_targetPos1, vehicleData.m_targetPos2, halfWidth); Quad2 quad23 = QuadUtils.GetSegmentQuad(vehicleData.m_targetPos2, vehicleData.m_targetPos3, halfWidth); Vector2 quadMin = Vector2.Min(Vector2.Min(passingQuad.Min(), quad01.Min()), Vector2.Min(quad12.Min(), quad23.Min())); Vector2 quadMax = Vector2.Max(Vector2.Max(passingQuad.Max(), quad01.Max()), Vector2.Max(quad12.Max(), quad23.Max())); float yMin = Mathf.Min(Mathf.Min(vehicleData.m_targetPos0.y, vehicleData.m_targetPos1.y), Mathf.Min(vehicleData.m_targetPos2.y, vehicleData.m_targetPos3.y)); float yMax = Mathf.Max(Mathf.Max(vehicleData.m_targetPos0.y, vehicleData.m_targetPos1.y), Mathf.Max(vehicleData.m_targetPos2.y, vehicleData.m_targetPos3.y)); int minGridX = Math.Max((int)((quadMin.x - 72f) / 64f + 135f), 0); int minGridZ = Math.Max((int)((quadMin.y - 72f) / 64f + 135f), 0); int maxGridX = Math.Min((int)((quadMax.x + 72f) / 64f + 135f), 269); int maxGridZ = Math.Min((int)((quadMax.y + 72f) / 64f + 135f), 269); float minY = yMin - vehicleInfo.m_generatedInfo.m_negativeHeight - 2f; float maxY = yMax + vehicleInfo.m_generatedInfo.m_size.y + 2f; BuildingManager buildingManager = Singleton <BuildingManager> .instance; for (int gridZ = minGridZ; gridZ <= maxGridZ; gridZ++) { for (int gridX = minGridX; gridX <= maxGridX; gridX++) { ushort buildingID = buildingManager.m_buildingGrid[gridZ * 270 + gridX]; while (buildingID != 0) { bool passing = buildingManager.m_buildings.m_buffer[buildingID].OverlapQuad(buildingID, passingQuad, minY, maxY, ItemClass.CollisionType.Terrain); bool near1 = buildingManager.m_buildings.m_buffer[buildingID].OverlapQuad(buildingID, quad01, minY, maxY, ItemClass.CollisionType.Terrain) || buildingManager.m_buildings.m_buffer[buildingID].OverlapQuad(buildingID, quad12, minY, maxY, ItemClass.CollisionType.Terrain); bool near2 = buildingManager.m_buildings.m_buffer[buildingID].OverlapQuad(buildingID, quad23, minY, maxY, ItemClass.CollisionType.Terrain); float maxSpeedForBridge = HandleMovableBridge(ref vehicleData, buildingID, ref buildingManager.m_buildings.m_buffer[buildingID], passing, near1, near2, minY, maxY, maxSpeed, vehicleTopY, forwardDir); if (maxSpeedForBridge < maxSpeed) { maxSpeed = CalculateMaxSpeed(0f, maxSpeedForBridge, maxBraking); } buildingID = buildingManager.m_buildings.m_buffer[buildingID].m_nextGridBuilding; } } } #if DEBUG if (InputListener.slowDown) { float targetSpeed = Mathf.Min(maxSpeed, 1f); maxSpeed = CalculateMaxSpeed(0f, targetSpeed, maxBraking); } #endif }
private static bool ApplyZoning(ZoneTool _this, ushort blockIndex, ref ZoneBlock data, Quad2 quad2) { int rowCount = data.RowCount; int columnCount = ZoneBlockDetour.GetColumnCount(ref data); // modified Vector2 vector2_1 = new Vector2(Mathf.Cos(data.m_angle), Mathf.Sin(data.m_angle)) * 8f; Vector2 vector2_2 = new Vector2(vector2_1.y, -vector2_1.x); Vector2 vector2_3 = VectorUtils.XZ(data.m_position); if (!new Quad2() { a = (vector2_3 - 4f * vector2_1 - 4f * vector2_2), b = (vector2_3 + 4f * vector2_1 - 4f * vector2_2), c = (vector2_3 + 4f * vector2_1 + (float)(rowCount - 4) * vector2_2), d = (vector2_3 - 4f * vector2_1 + (float)(rowCount - 4) * vector2_2) }.Intersect(quad2)) { return(false); } bool flag = false; var m_zoning = IsZoningEnabled(_this); // custom var m_dezoning = IsDezoningEnabled(_this); // custom var blockID = ZoneBlockDetour.FindBlockId(ref data); // modified for (int z = 0; z < rowCount; ++z) { Vector2 vector2_4 = ((float)z - 3.5f) * vector2_2; for (int x = 0; x < columnCount; ++x) // custom { Vector2 vector2_5 = ((float)x - 3.5f) * vector2_1; Vector2 p = vector2_3 + vector2_5 + vector2_4; if (quad2.Intersect(p)) { if (m_zoning) { if ((_this.m_zone == ItemClass.Zone.Unzoned || ZoneBlockDetour.GetZoneDeep(ref data, blockID, x, z) == ItemClass.Zone.Unzoned) && ZoneBlockDetour.SetZoneDeep(ref data, blockID, x, z, _this.m_zone)) { flag = true; } } else if (m_dezoning && ZoneBlockDetour.SetZoneDeep(ref data, blockID, x, z, ItemClass.Zone.Unzoned)) { flag = true; } } } } if (!flag) { return(false); } data.RefreshZoning(blockIndex); return(true); }
private static bool ApplyZoning(ZoneTool z, ushort blockIndex, ref ZoneBlock data, Quad2 quad2) { UnityEngine.Debug.Log($"{z}-{blockIndex}-{data}-{quad2}"); return(false); }