Ejemplo n.º 1
0
        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);
        }
        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);
        }
        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 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);
        }
Ejemplo n.º 5
0
        /// <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;
        }
Ejemplo n.º 6
0
        /// <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
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 7
0
        /// <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);
                        }
                    }
                }
            }
        }
Ejemplo n.º 8
0
        /// <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 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));
                 }
             }
         }
     }
 }
 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;
                 }
             }
         }
     }
 }
        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;
                        }
                    }
                }
            }
        }
Ejemplo n.º 13
0
        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;
        }