コード例 #1
0
        public static void RenderCloneGeometryImplementation(InstanceState instanceState, ref Matrix4x4 matrix4x, Vector3 deltaPosition, float deltaAngle, Vector3 center, bool followTerrain, RenderManager.CameraInfo cameraInfo)
        {
            BuildingInfo info  = instanceState.Info.Prefab as BuildingInfo;
            Color        color = GetColor(instanceState.instance.id.Building, info);

            Vector3 newPosition = matrix4x.MultiplyPoint(instanceState.position - center);

            newPosition.y = instanceState.position.y + deltaPosition.y;

            if (followTerrain)
            {
                newPosition.y = newPosition.y - instanceState.terrainHeight + TerrainManager.instance.SampleOriginalRawHeightSmooth(newPosition);
            }

            float newAngle = instanceState.angle + deltaAngle;

            info.m_buildingAI.RenderBuildGeometry(cameraInfo, newPosition, newAngle, 0);
            BuildingTool.RenderGeometry(cameraInfo, info, info.GetLength(), newPosition, newAngle, false, color);
            if (info.m_subBuildings != null && info.m_subBuildings.Length != 0)
            {
                Matrix4x4 subMatrix4x = default;
                subMatrix4x.SetTRS(newPosition, Quaternion.AngleAxis(newAngle * Mathf.Rad2Deg, Vector3.down), Vector3.one);
                for (int i = 0; i < info.m_subBuildings.Length; i++)
                {
                    BuildingInfo buildingInfo2 = info.m_subBuildings[i].m_buildingInfo;
                    Vector3      position      = subMatrix4x.MultiplyPoint(info.m_subBuildings[i].m_position);
                    float        angle         = info.m_subBuildings[i].m_angle * Mathf.Deg2Rad + newAngle;
                    buildingInfo2.m_buildingAI.RenderBuildGeometry(cameraInfo, position, angle, 0);
                    BuildingTool.RenderGeometry(cameraInfo, buildingInfo2, 0, position, angle, true, color);
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Returns the workplace breakdowns and visitor count for the given building prefab and level.
        /// </summary>
        /// <param name="buildingPrefab">Building prefab record</param>
        /// <param name="level">Building level</param>
        /// <returns>Workplace breakdowns and visitor count </returns>
        public override int[] Workplaces(BuildingInfo buildingPrefab, int level)
        {
            int[] array = LegacyAIUtils.GetOfficeArray(buildingPrefab, level);
            LegacyAIUtils.CalculateprefabWorkerVisit(buildingPrefab.GetWidth(), buildingPrefab.GetLength(), ref buildingPrefab, 10, ref array, out int[] output);

            return(output);
        }
コード例 #3
0
        /// <summary>
        /// Render and show a preview of a building.
        /// </summary>
        /// <param name="building">The building to render</param>
        public void Show(BuildingInfo building)
        {
            // Update current selection to the new building.
            currentSelection = building;

            // Generate render if there's a selection with a mesh.
            if (currentSelection != null && currentSelection.m_mesh != null)
            {
                // Set default values.
                previewRender.CameraRotation = 210f;
                previewRender.Zoom           = 4f;

                // Set mesh and material for render.
                previewRender.SetTarget(currentSelection);

                // Set background.
                previewSprite.texture     = previewRender.Texture;
                noPreviewSprite.isVisible = false;

                // Render at next update.
                RenderPreview();
            }
            else
            {
                // No valid current selection with a mesh; reset background.
                previewSprite.texture     = null;
                noPreviewSprite.isVisible = true;
            }

            // Hide any empty building names.
            if (building == null)
            {
                buildingName.isVisible  = false;
                buildingLevel.isVisible = false;
                buildingSize.isVisible  = false;
            }
            else
            {
                // Set and show building name.
                buildingName.isVisible = true;
                buildingName.text      = UIBuildingDetails.GetDisplayName(currentSelection.name);
                UIUtils.TruncateLabel(buildingName, width - 45);
                buildingName.autoHeight = true;

                // Set and show building level.
                buildingLevel.isVisible = true;
                buildingLevel.text      = Translations.Translate("RPR_OPT_LVL") + " " + Mathf.Min((int)currentSelection.GetClassLevel() + 1, MaxLevelOf(currentSelection.GetSubService()));
                UIUtils.TruncateLabel(buildingLevel, width - 45);
                buildingLevel.autoHeight = true;

                // Set and show building size.
                buildingSize.isVisible = true;
                buildingSize.text      = currentSelection.GetWidth() + "x" + currentSelection.GetLength();
                UIUtils.TruncateLabel(buildingSize, width - 45);
                buildingSize.autoHeight = true;
            }
        }
コード例 #4
0
        /// <summary>
        /// Returns the workplace breakdowns and visitor count for the given building prefab and level.
        /// </summary>
        /// <param name="buildingPrefab">Building prefab record</param>
        /// <param name="level">Building level</param>
        /// <returns>Workplace breakdowns and visitor count </returns>
        public override int[] Workplaces(BuildingInfo buildingPrefab, int level)
        {
            int[] array;
            int   minWorkers;

            // Need to test if we're an extractor or not for this one.
            if (buildingPrefab.GetAI() is IndustrialExtractorAI)
            {
                array      = LegacyAIUtils.GetExtractorArray(buildingPrefab);
                minWorkers = 3;
            }
            else
            {
                array      = LegacyAIUtils.GetIndustryArray(buildingPrefab, level);
                minWorkers = 4;
            }

            LegacyAIUtils.CalculateprefabWorkerVisit(buildingPrefab.GetWidth(), buildingPrefab.GetLength(), ref buildingPrefab, minWorkers, ref array, out int[] output);

            return(output);
        }
コード例 #5
0
        /// <summary>
        /// Sets the customised number of workers for a given prefab.
        /// If a record doesn't already exist, a new one will be created.
        /// </summary>
        /// <param name="prefab">The prefab (BuildingInfo) to set</param>
        /// <param name="workers">The updated worker count</param>
        public static void SetWorker(BuildingInfo prefab, int workers)
        {
            // Update or add entry to configuration file cache.
            if (DataStore.workerCache.ContainsKey(prefab.name))
            {
                // Prefab already has a record; update.
                DataStore.workerCache[prefab.name] = workers;
            }
            else
            {
                // Prefab doesn't already have a record; create.
                DataStore.workerCache.Add(prefab.name, workers);
            }

            // Save the updated configuration file.
            XMLUtilsWG.WriteToXML();

            // Get current building hash (for updating prefab dictionary).
            var prefabHash = prefab.gameObject.GetHashCode();

            // Calculate employment breakdown.
            int[] array = CommercialBuildingAIMod.GetArray(prefab, (int)prefab.GetClassLevel());
            PrefabEmployStruct output = new PrefabEmployStruct();

            AI_Utils.CalculateprefabWorkerVisit(prefab.GetWidth(), prefab.GetLength(), ref prefab, 4, ref array, out output);

            // Update entry in 'live' settings.
            if (DataStore.prefabWorkerVisit.ContainsKey(prefabHash))
            {
                // Prefab already has a record; update.
                DataStore.prefabWorkerVisit[prefabHash] = output;
            }
            else
            {
                // Prefab doesn't already have a record; create.
                DataStore.prefabWorkerVisit.Add(prefabHash, output);
            }
        }
コード例 #6
0
        /// <summary>
        /// Interpret and apply RICO settings to a building prefab.
        /// </summary>
        /// <param name="buildingData">RICO building data to apply</param>
        /// <param name="prefab">The building prefab to be changed</param>
        internal void ConvertPrefab(RICOBuilding buildingData, BuildingInfo prefab)
        {
            // AI class  for prefab init.
            string aiClass;


            if (prefab != null)
            {
                // Check eligibility for any growable assets.
                if (buildingData.growable)
                {
                    // Growables can't have any dimension greater than 4.
                    if (prefab.GetWidth() > 4 || prefab.GetLength() > 4)
                    {
                        buildingData.growable = false;
                        Logging.Error("building '", prefab.name, "' can't be growable because it is too big");
                    }

                    // Growables can't have net structures.
                    if (prefab.m_paths != null && prefab.m_paths.Length != 0)
                    {
                        buildingData.growable = false;
                        Logging.Error("building '", prefab.name, "' can't be growable because it contains network assets");
                    }
                }

                // Apply AI based on service.
                switch (buildingData.service)
                {
                // Dummy AI.
                case "dummy":

                    // Get AI.
                    DummyBuildingAI dummyAI = prefab.gameObject.AddComponent <DummyBuildingAI>();

                    // Use beautification ItemClass to avoid issues, and never make growable.
                    InitializePrefab(prefab, dummyAI, "Beautification Item", false);

                    // Final circular reference.
                    prefab.m_buildingAI.m_info = prefab;

                    // Dummy is a special case, and we're done here.
                    return;

                // Residential AI.
                case "residential":

                    // Get AI.
                    GrowableResidentialAI residentialAI = buildingData.growable ? prefab.gameObject.AddComponent <GrowableResidentialAI>() : prefab.gameObject.AddComponent <PloppableResidentialAI>();
                    if (residentialAI == null)
                    {
                        throw new Exception("Ploppable RICO residential AI not found.");
                    }

                    // Assign basic parameters.
                    residentialAI.m_ricoData         = buildingData;
                    residentialAI.m_constructionCost = buildingData.ConstructionCost;
                    residentialAI.m_homeCount        = buildingData.homeCount;

                    // Determine AI class string according to subservice.
                    switch (buildingData.subService)
                    {
                    case "low eco":
                        // Apply eco service if GC installed, otherwise use normal low residential.
                        if (Util.IsGCinstalled())
                        {
                            aiClass = "Low Residential Eco - Level";
                        }
                        else
                        {
                            aiClass = "Low Residential - Level";
                        }
                        break;

                    case "high eco":
                        // Apply eco service if GC installed, otherwise use normal high residential.
                        if (Util.IsGCinstalled())
                        {
                            aiClass = "High Residential Eco - Level";
                        }
                        else
                        {
                            aiClass = "High Residential - Level";
                        }
                        break;

                    case "high":
                        // Stock standard high commercial.
                        aiClass = "High Residential - Level";
                        break;

                    default:
                        // Fall back to low residential as default.
                        aiClass = "Low Residential - Level";

                        // If invalid subservice, report.
                        if (buildingData.subService != "low")
                        {
                            Logging.Message("Residential building ", buildingData.Name, " has invalid subservice ", buildingData.subService, "; reverting to low residential");
                        }
                        break;
                    }

                    // Initialize the prefab.
                    InitializePrefab(prefab, residentialAI, aiClass + buildingData.level, buildingData.growable);

                    break;

                // Office AI.
                case "office":

                    // Get AI.
                    GrowableOfficeAI officeAI = buildingData.growable ? prefab.gameObject.AddComponent <GrowableOfficeAI>() : prefab.gameObject.AddComponent <PloppableOfficeAI>();
                    if (officeAI == null)
                    {
                        throw new Exception("Ploppable RICO Office AI not found.");
                    }

                    // Assign basic parameters.
                    officeAI.m_ricoData         = buildingData;
                    officeAI.m_workplaceCount   = buildingData.WorkplaceCount;
                    officeAI.m_constructionCost = buildingData.ConstructionCost;

                    // Check if this is an IT Cluster specialisation.

                    // Determine AI class string according to subservice.
                    if (buildingData.subService == "high tech")
                    {
                        // Apply IT cluster if GC installed, otherwise use Level 3 office.
                        if (Util.IsGCinstalled())
                        {
                            aiClass = "Office - Hightech";
                        }
                        else
                        {
                            aiClass = "Office - Level3";
                        }
                    }
                    else
                    {
                        // Not IT cluster - boring old ordinary office.
                        aiClass = "Office - Level" + buildingData.level;
                    }

                    // Initialize the prefab.
                    InitializePrefab(prefab, officeAI, aiClass, buildingData.growable);

                    break;

                // Industrial AI.
                case "industrial":
                    // Get AI.
                    GrowableIndustrialAI industrialAI = buildingData.growable ? prefab.gameObject.AddComponent <GrowableIndustrialAI>() : prefab.gameObject.AddComponent <PloppableIndustrialAI>();
                    if (industrialAI == null)
                    {
                        throw new Exception("Ploppable RICO Industrial AI not found.");
                    }

                    // Assign basic parameters.
                    industrialAI.m_ricoData         = buildingData;
                    industrialAI.m_workplaceCount   = buildingData.WorkplaceCount;
                    industrialAI.m_constructionCost = buildingData.ConstructionCost;
                    industrialAI.m_pollutionEnabled = buildingData.pollutionEnabled;

                    // Determine AI class string according to subservice.
                    // Check for valid subservice.
                    if (IsValidIndSubServ(buildingData.subService))
                    {
                        // Specialised industry.
                        aiClass = ServiceName(buildingData.subService) + " - Processing";
                    }
                    else
                    {
                        // Generic industry.
                        aiClass = "Industrial - Level" + buildingData.level;
                    }

                    // Initialize the prefab.
                    InitializePrefab(prefab, industrialAI, aiClass, buildingData.growable);

                    break;

                // Extractor AI.
                case "extractor":
                    // Get AI.
                    GrowableExtractorAI extractorAI = buildingData.growable ? prefab.gameObject.AddComponent <GrowableExtractorAI>() : prefab.gameObject.AddComponent <PloppableExtractorAI>();
                    if (extractorAI == null)
                    {
                        throw new Exception("Ploppable RICO Extractor AI not found.");
                    }

                    // Assign basic parameters.
                    extractorAI.m_ricoData         = buildingData;
                    extractorAI.m_workplaceCount   = buildingData.WorkplaceCount;
                    extractorAI.m_constructionCost = buildingData.ConstructionCost;
                    extractorAI.m_pollutionEnabled = buildingData.pollutionEnabled;

                    // Check that we have a valid industry subservice.
                    if (IsValidIndSubServ(buildingData.subService))
                    {
                        // Initialise the prefab.
                        InitializePrefab(prefab, extractorAI, ServiceName(buildingData.subService) + " - Extractor", buildingData.growable);
                    }
                    else
                    {
                        Logging.Error("invalid industry subservice ", buildingData.subService, " for extractor ", buildingData.Name);
                    }

                    break;

                // Commercial AI.
                case "commercial":
                    // Get AI.
                    GrowableCommercialAI commercialAI = buildingData.growable ? prefab.gameObject.AddComponent <GrowableCommercialAI>() : prefab.gameObject.AddComponent <PloppableCommercialAI>();
                    if (commercialAI == null)
                    {
                        throw new Exception("Ploppable RICO Commercial AI not found.");
                    }

                    // Assign basic parameters.
                    commercialAI.m_ricoData         = buildingData;
                    commercialAI.m_workplaceCount   = buildingData.WorkplaceCount;
                    commercialAI.m_constructionCost = buildingData.ConstructionCost;

                    // Determine AI class string according to subservice.
                    switch (buildingData.subService)
                    {
                    // Organic and Local Produce.
                    case "eco":
                        // Apply eco specialisation if GC installed, otherwise use Level 1 low commercial.
                        if (Util.IsGCinstalled())
                        {
                            // Eco commercial buildings only import food goods.
                            commercialAI.m_incomingResource = TransferManager.TransferReason.Food;
                            aiClass = "Eco Commercial";
                        }
                        else
                        {
                            aiClass = "Low Commercial - Level1";
                        }
                        break;

                    // Tourism.
                    case "tourist":
                        // Apply tourist specialisation if AD installed, otherwise use Level 1 low commercial.
                        if (Util.IsADinstalled())
                        {
                            aiClass = "Tourist Commercial - Land";
                        }
                        else
                        {
                            aiClass = "Low Commercial - Level1";
                        }
                        break;

                    // Leisure.
                    case "leisure":
                        // Apply leisure specialisation if AD installed, otherwise use Level 1 low commercial.
                        if (Util.IsADinstalled())
                        {
                            aiClass = "Leisure Commercial";
                        }
                        else
                        {
                            aiClass = "Low Commercial - Level1";
                        }
                        break;

                    // Bog standard high commercial.
                    case "high":
                        aiClass = "High Commercial - Level" + buildingData.level;
                        break;

                    // Fall back to low commercial as default.
                    default:
                        aiClass = "Low Commercial - Level" + buildingData.level;

                        // If invalid subservice, report.
                        if (buildingData.subService != "low")
                        {
                            Logging.Message("Commercial building ", buildingData.Name, " has invalid subService ", buildingData.subService, "; reverting to low commercial.");
                        }
                        break;
                    }

                    // Initialize the prefab.
                    InitializePrefab(prefab, commercialAI, aiClass, buildingData.growable);

                    break;
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Interpret and apply RICO settings to a building prefab.
        /// </summary>
        /// <param name="buildingData">RICO building data to apply</param>
        /// <param name="prefab">The building prefab to be changed</param>
        internal void ConvertPrefab(RICOBuilding buildingData, BuildingInfo prefab)
        {
            if (prefab != null)
            {
                // Check eligibility for any growable assets.
                if (buildingData.growable)
                {
                    // Growables can't have any dimension greater than 4.
                    if (prefab.GetWidth() > 4 || prefab.GetLength() > 4)
                    {
                        buildingData.growable = false;
                        Debugging.Message("building '" + prefab.name + "' can't be growable because it is too big");
                    }

                    // Growables can't have net structures.
                    if (prefab.m_paths != null && prefab.m_paths.Length != 0)
                    {
                        buildingData.growable = false;
                        Debugging.Message("building '" + prefab.name + "' can't be growable because it contains network assets");
                    }
                }

                if (buildingData.service == "dummy")
                {
                    var ai = prefab.gameObject.AddComponent <DummyBuildingAI>();

                    // Use beautification ItemClass to avoid issues, and never make growable.
                    InitializePrefab(prefab, ai, "Beautification Item", false);

                    // Final circular reference.
                    prefab.m_buildingAI.m_info = prefab;
                }
                else if (buildingData.service == "residential")
                {
                    var ai = buildingData.growable ? prefab.gameObject.AddComponent <GrowableResidentialAI>() : prefab.gameObject.AddComponent <PloppableResidentialAI>();
                    if (ai == null)
                    {
                        throw (new Exception("Residential-AI not found."));
                    }

                    ai.m_ricoData         = buildingData;
                    ai.m_constructionCost = buildingData.constructionCost;
                    ai.m_homeCount        = buildingData.homeCount;

                    if (buildingData.subService == "low eco")
                    {
                        // Apply eco service if GC installed, otherwise use normal low residential.
                        if (Util.isGCinstalled())
                        {
                            InitializePrefab(prefab, ai, "Low Residential Eco - Level" + buildingData.level, buildingData.growable);
                        }
                        else
                        {
                            InitializePrefab(prefab, ai, "Low Residential - Level" + buildingData.level, buildingData.growable);
                        }
                    }
                    else if (buildingData.subService == "high eco")
                    {
                        // Apply eco service if GC installed, otherwise use normal high residential.
                        if (Util.isGCinstalled())
                        {
                            InitializePrefab(prefab, ai, "High Residential Eco - Level" + buildingData.level, buildingData.growable);
                        }
                        else
                        {
                            InitializePrefab(prefab, ai, "High Residential - Level" + buildingData.level, buildingData.growable);
                        }
                    }
                    else if (buildingData.subService == "high")
                    {
                        // Stock standard high commercial.
                        InitializePrefab(prefab, ai, "High Residential - Level" + buildingData.level, buildingData.growable);
                    }
                    else
                    {
                        // Fall back to low residential as default.
                        InitializePrefab(prefab, ai, "Low Residential - Level" + buildingData.level, buildingData.growable);

                        // If invalid subservice, report.
                        if (buildingData.subService != "low")
                        {
                            Debugging.ErrorBuffer.AppendLine("Residential building " + buildingData.name + " has invalid subservice " + buildingData.subService + "; reverting to low residential.");
                        }
                    }
                }
                else if (buildingData.service == "office")
                {
                    var ai = buildingData.growable ? prefab.gameObject.AddComponent <GrowableOfficeAI>() : prefab.gameObject.AddComponent <PloppableOfficeAI>();
                    if (ai == null)
                    {
                        throw (new Exception("Office-AI not found."));
                    }

                    ai.m_ricoData         = buildingData;
                    ai.m_workplaceCount   = buildingData.workplaceCount;
                    ai.m_constructionCost = buildingData.constructionCost;

                    if (buildingData.subService == "high tech")
                    {
                        // Apply IT cluster if GC installed, otherwise use Level 3 office.
                        if (Util.isGCinstalled())
                        {
                            InitializePrefab(prefab, ai, "Office - Hightech", buildingData.growable);
                        }
                        else
                        {
                            InitializePrefab(prefab, ai, "Office - Level3", buildingData.growable);
                        }
                    }
                    else
                    {
                        // Not IT cluster - boring old ordinary office.
                        InitializePrefab(prefab, ai, "Office - Level" + buildingData.level, buildingData.growable);
                    }
                }
                else if (buildingData.service == "industrial")
                {
                    var ai = buildingData.growable ? prefab.gameObject.AddComponent <GrowableIndustrialAI>() : prefab.gameObject.AddComponent <PloppableIndustrialAI>();
                    if (ai == null)
                    {
                        throw (new Exception("Industrial-AI not found."));
                    }

                    ai.m_ricoData         = buildingData;
                    ai.m_workplaceCount   = buildingData.workplaceCount;
                    ai.m_constructionCost = buildingData.constructionCost;
                    ai.m_pollutionEnabled = buildingData.pollutionEnabled;

                    if (Util.industryServices.Contains(buildingData.subService))
                    {
                        InitializePrefab(prefab, ai, Util.ucFirst(buildingData.subService) + " - Processing", buildingData.growable);
                    }
                    else
                    {
                        InitializePrefab(prefab, ai, "Industrial - Level" + buildingData.level, buildingData.growable);
                    }
                }
                else if (buildingData.service == "extractor")
                {
                    var ai = buildingData.growable ? prefab.gameObject.AddComponent <GrowableExtractorAI>() : prefab.gameObject.AddComponent <PloppableExtractorAI>();
                    if (ai == null)
                    {
                        throw (new Exception("Extractor-AI not found."));
                    }

                    ai.m_ricoData         = buildingData;
                    ai.m_workplaceCount   = buildingData.workplaceCount;
                    ai.m_constructionCost = buildingData.constructionCost;
                    ai.m_pollutionEnabled = buildingData.pollutionEnabled;

                    if (Util.industryServices.Contains(buildingData.subService))
                    {
                        InitializePrefab(prefab, ai, Util.ucFirst(buildingData.subService) + " - Extractor", buildingData.growable);
                    }
                }

                else if (buildingData.service == "commercial")
                {
                    var ai = buildingData.growable ? prefab.gameObject.AddComponent <GrowableCommercialAI>() : prefab.gameObject.AddComponent <PloppableCommercialAI>();
                    if (ai == null)
                    {
                        throw (new Exception("Commercial-AI not found."));
                    }

                    ai.m_ricoData         = buildingData;
                    ai.m_workplaceCount   = buildingData.workplaceCount;
                    ai.m_constructionCost = buildingData.constructionCost;

                    if (buildingData.subService == "eco")
                    {
                        // Apply eco specialisation if GC installed, otherwise use Level 1 low commercial.
                        if (Util.isGCinstalled())
                        {
                            // Eco commercial buildings only import food goods.
                            ai.m_incomingResource = TransferManager.TransferReason.Food;
                            InitializePrefab(prefab, ai, "Eco Commercial", buildingData.growable);
                        }
                        else
                        {
                            InitializePrefab(prefab, ai, "Low Commercial - Level1", buildingData.growable);
                        }
                    }
                    else if (buildingData.subService == "tourist")
                    {
                        // Apply tourist specialisation if AD installed, otherwise use Level 1 low commercial.
                        if (Util.isADinstalled())
                        {
                            InitializePrefab(prefab, ai, "Tourist Commercial - Land", buildingData.growable);
                        }
                        else
                        {
                            InitializePrefab(prefab, ai, "Low Commercial - Level1", buildingData.growable);
                        }
                    }
                    else if (buildingData.subService == "leisure")
                    {
                        // Apply leisure specialisation if AD installed, otherwise use Level 1 low commercial.
                        if (Util.isADinstalled())
                        {
                            InitializePrefab(prefab, ai, "Leisure Commercial", buildingData.growable);
                        }
                        else
                        {
                            InitializePrefab(prefab, ai, "Low Commercial - Level1", buildingData.growable);
                        }
                    }
                    else if (buildingData.subService == "high")
                    {
                        // Bog standard high commercial.
                        InitializePrefab(prefab, ai, "High Commercial - Level" + buildingData.level, buildingData.growable);
                    }
                    else
                    {
                        // Fall back to low commercial as default.
                        InitializePrefab(prefab, ai, "Low Commercial - Level" + buildingData.level, buildingData.growable);

                        // If invalid subservice, report.
                        if (buildingData.subService != "low")
                        {
                            Debugging.ErrorBuffer.AppendLine("Commercial building " + buildingData.name + " has invalid subService " + buildingData.subService + "; reverting to low commercial.");
                        }
                    }
                }
            }
        }
コード例 #8
0
        // 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;
        }
コード例 #9
0
        /// <summary>
        /// Perform and display volumetric calculations for the currently selected building.
        /// </summary>
        /// <param name="building">Selected building prefab</param>
        /// <param name="levelData">Population (level) calculation data to apply to calculations</param>
        /// <param name="floorData">Floor calculation data to apply to calculations</param>
        /// <param name="schoolData">School calculation data to apply to calculations</param>
        /// <param name="schoolData">Multiplier to apply to calculations</param>
        internal void CalculateVolumetric(BuildingInfo building, LevelData levelData, FloorDataPack floorData, SchoolDataPack schoolData, float multiplier)
        {
            // Safety first!
            if (building == null)
            {
                return;
            }

            // Reset message label.
            messageLabel.text = string.Empty;

            // Perform calculations.
            // Get floors and allocate area an number of floor labels.
            SortedList <int, float> floors = PopData.instance.VolumetricFloors(building.m_generatedInfo, floorData, out float totalArea);

            floorAreaLabel.text = totalArea.ToString("N0", LocaleManager.cultureInfo);
            numFloorsLabel.text = floors.Count.ToString();

            // Get total units.
            int totalUnits = PopData.instance.VolumetricPopulation(building.m_generatedInfo, levelData, floorData, multiplier, floors, totalArea);

            // Floor labels list.
            List <string> floorLabels = new List <string>();

            // What we call our units for this building.
            string unitName;

            switch (building.GetService())
            {
            case ItemClass.Service.Residential:
                // Residential - households.
                unitName = Translations.Translate("RPR_CAL_UNI_HOU");
                break;

            case ItemClass.Service.Education:
                // Education - students.
                unitName = Translations.Translate("RPR_CAL_UNI_STU");
                break;

            default:
                // Default - workplaces.
                unitName = Translations.Translate("RPR_CAL_UNI_WOR");
                break;
            }

            // See if we're using area calculations for numbers of units, i.e. areaPer is at least one.
            if (levelData.areaPer > 0)
            {
                // Determine area percentage to use for calculations (inverse of empty area percentage).
                float areaPercent = 1 - (levelData.emptyPercent / 100f);

                // Create new floor area labels by iterating through each floor.
                for (int i = 0; i < floors.Count; ++i)
                {
                    // StringBuilder, because we're doing a fair bit of manipulation here.
                    StringBuilder floorString = new StringBuilder("Floor ");

                    // Floor number
                    floorString.Append(i + 1);
                    floorString.Append(" " + Translations.Translate("RPR_CAL_VOL_ARA") + " ");
                    floorString.Append(floors[i].ToString("N0"));

                    // See if we're calculating units per individual floor.
                    if (!levelData.multiFloorUnits)
                    {
                        // Number of units on this floor - always rounded down.
                        int floorUnits = (int)((floors[i] * areaPercent) / levelData.areaPer);
                        // Adjust by multiplier (after rounded calculation above).
                        floorUnits = (int)(floorUnits * multiplier);

                        // Add extra info to label.
                        floorString.Append(" (");
                        floorString.Append(floorUnits.ToString("N0"));
                        floorString.Append(" ");
                        floorString.Append(unitName);
                        floorString.Append(")");
                    }

                    // Add new floor label item with results for this calculation.
                    floorLabels.Add(floorString.ToString());
                }
            }

            // Do we have a current school selection, and are we using school property overrides?
            if (schoolData != null && ModSettings.enableSchoolProperties)
            {
                // Yes - calculate and display school worker breakdown.
                int[] workers = SchoolData.instance.CalcWorkers(schoolData, totalUnits);
                schoolWorkerLabel.Show();
                schoolWorkerLabel.text = workers[0] + " / " + workers[1] + " / " + workers[2] + " / " + workers[3];

                // Calculate construction cost to display.
                int cost = SchoolData.instance.CalcCost(schoolData, totalUnits);
                ColossalFramework.Singleton <EconomyManager> .instance.m_EconomyWrapper.OnGetConstructionCost(ref cost, building.m_class.m_service, building.m_class.m_subService, building.m_class.m_level);

                // Calculate maintenance cost to display.
                int maintenance = SchoolData.instance.CalcMaint(schoolData, totalUnits) * 100;
                ColossalFramework.Singleton <EconomyManager> .instance.m_EconomyWrapper.OnGetMaintenanceCost(ref maintenance, building.m_class.m_service, building.m_class.m_subService, building.m_class.m_level);

                float displayMaint = Mathf.Abs(maintenance * 0.0016f);

                // And display school cost breakdown.
                costLabel.Show();
                costLabel.text = cost.ToString((!(displayMaint >= 10f)) ? Settings.moneyFormat : Settings.moneyFormatNoCents, LocaleManager.cultureInfo) + " / " + displayMaint.ToString((!(displayMaint >= 10f)) ? Settings.moneyFormat : Settings.moneyFormatNoCents, LocaleManager.cultureInfo);

                // Enforce school floors list position.
                ResetFloorListPosition();
            }
            else
            {
                // No - hide school worker breakdown and cost labels.
                schoolWorkerLabel.Hide();
                costLabel.Hide();

                // Enforce default floors list position.
                ResetFloorListPosition();
            }

            // Allocate our new list of labels to the floors list (via an interim fastlist to avoid race conditions if we 'build' manually directly into floorsList).
            FastList <object> fastList = new FastList <object>()
            {
                m_buffer = floorLabels.ToArray(),
                m_size   = floorLabels.Count
            };

            floorsList.rowsData = fastList;

            // Display total unit calculation result.
            switch (building.GetService())
            {
            case ItemClass.Service.Residential:
                // Residential building.
                totalJobsLabel.Hide();
                totalStudentsLabel.Hide();
                totalHomesLabel.Show();
                totalHomesLabel.text = totalUnits.ToString("N0", LocaleManager.cultureInfo);
                break;

            case ItemClass.Service.Education:
                // School building.
                totalHomesLabel.Hide();
                totalJobsLabel.Hide();
                totalStudentsLabel.Show();
                totalStudentsLabel.text = totalUnits.ToString("N0", LocaleManager.cultureInfo);
                break;

            default:
                // Workplace building.
                totalHomesLabel.Hide();
                totalStudentsLabel.Hide();
                totalJobsLabel.Show();
                totalJobsLabel.text = totalUnits.ToString("N0", LocaleManager.cultureInfo);
                break;
            }

            // Display commercial visit count, or hide the label if not commercial.
            if (building.GetAI() is CommercialBuildingAI)
            {
                visitCountLabel.Show();
                visitCountLabel.text = RealisticVisitplaceCount.PreviewVisitCount(building, totalUnits).ToString();
            }
            else
            {
                visitCountLabel.Hide();
            }

            // Display production count, or hide the label if not a production building.
            if (building.GetAI() is PrivateBuildingAI privateAI && (privateAI is OfficeBuildingAI || privateAI is IndustrialBuildingAI || privateAI is IndustrialExtractorAI))
            {
                productionLabel.Show();
                productionLabel.text = privateAI.CalculateProductionCapacity(building.GetClassLevel(), new ColossalFramework.Math.Randomizer(), building.GetWidth(), building.GetLength()).ToString();
            }
コード例 #10
0
        /// <summary>
        /// Called whenever the currently selected building is changed to update the panel display.
        /// </summary>
        /// <param name="building"></param>
        public void SelectionChanged(BuildingInfo building)
        {
            if ((building == null) || (building.name == null))
            {
                // If no valid building selected, then hide the calculations panel.
                detailsPanel.height    = 0;
                detailsPanel.isVisible = false;
                return;
            }

            // Variables to compare actual counts vs. mod count, to see if there's another mod overriding counts.
            int appliedCount;
            int modCount;

            // Building model size, not plot size.
            Vector3 buildingSize = building.m_size;
            int     floorCount;

            // Array used for calculations depending on building service/subservice (via DataStore).
            int[] array;
            // Default minimum number of homes or jobs is one; different service types will override this.
            int minHomesJobs = 1;
            int customHomeJobs;

            // Check for valid building AI.
            if (!(building.GetAI() is PrivateBuildingAI buildingAI))
            {
                Debugging.Message("invalid building AI type in building details");
                return;
            }

            // Residential vs. workplace AI.
            if (buildingAI is ResidentialBuildingAI)
            {
                // Get appropriate calculation array.
                array = ResidentialBuildingAIMod.GetArray(building, (int)building.GetClassLevel());

                // Set calculated homes label.
                homesJobsCalcLabel.text = Translations.Translate("RPR_CAL_HOM_CALC");

                // Set customised homes label and get value (if any).
                homesJobsCustomLabel.text = Translations.Translate("RPR_CAL_HOM_CUST");
                customHomeJobs            = ExternalCalls.GetResidential(building);

                // Applied homes is what's actually being returned by the CaclulateHomeCount call to this building AI.
                // It differs from calculated homes if there's an override value for that building with this mod, or if another mod is overriding.
                appliedCount = buildingAI.CalculateHomeCount(building.GetClassLevel(), new Randomizer(0), building.GetWidth(), building.GetLength());
                homesJobsActualLabel.text = Translations.Translate("RPR_CAL_HOM_APPL") + appliedCount;
            }
            else
            {
                // Workplace AI.
                // Default minimum number of jobs is 4.
                minHomesJobs = 4;

                // Find the correct array for the relevant building AI.
                switch (building.GetService())
                {
                case ItemClass.Service.Commercial:
                    array = CommercialBuildingAIMod.GetArray(building, (int)building.GetClassLevel());
                    break;

                case ItemClass.Service.Office:
                    array = OfficeBuildingAIMod.GetArray(building, (int)building.GetClassLevel());
                    break;

                case ItemClass.Service.Industrial:
                    if (buildingAI is IndustrialExtractorAI)
                    {
                        array = IndustrialExtractorAIMod.GetArray(building, (int)building.GetClassLevel());
                    }
                    else
                    {
                        array = IndustrialBuildingAIMod.GetArray(building, (int)building.GetClassLevel());
                    }
                    break;

                default:
                    Debugging.Message("invalid building service in building details");
                    return;
                }

                // Set calculated jobs label.
                homesJobsCalcLabel.text = Translations.Translate("RPR_CAL_JOB_CALC") + " ";

                // Set customised jobs label and get value (if any).
                homesJobsCustomLabel.text = Translations.Translate("RPR_CAL_JOB_CUST") + " ";
                customHomeJobs            = ExternalCalls.GetWorker(building);

                // Applied jobs is what's actually being returned by the CalculateWorkplaceCount call to this building AI.
                // It differs from calculated jobs if there's an override value for that building with this mod, or if another mod is overriding.
                int[] jobs = new int[4];
                buildingAI.CalculateWorkplaceCount(building.GetClassLevel(), new Randomizer(0), building.GetWidth(), building.GetLength(), out jobs[0], out jobs[1], out jobs[2], out jobs[3]);
                appliedCount = jobs[0] + jobs[1] + jobs[2] + jobs[3];
                homesJobsActualLabel.text = Translations.Translate("RPR_CAL_JOB_APPL") + " " + appliedCount;
            }

            // Reproduce CalcBase calculations to get building area.
            int calcWidth  = building.GetWidth();
            int calcLength = building.GetLength();

            floorCount = Mathf.Max(1, Mathf.FloorToInt(buildingSize.y / array[DataStore.LEVEL_HEIGHT]));

            // If CALC_METHOD is zero, then calculations are based on building model size, not plot size.
            if (array[DataStore.CALC_METHOD] == 0)
            {
                // If asset has small x dimension, then use plot width in squares x 6m (75% of standard width) instead.
                if (buildingSize.x <= 1)
                {
                    calcWidth *= 6;
                }
                else
                {
                    calcWidth = (int)buildingSize.x;
                }

                // If asset has small z dimension, then use plot length in squares x 6m (75% of standard length) instead.
                if (buildingSize.z <= 1)
                {
                    calcLength *= 6;
                }
                else
                {
                    calcLength = (int)buildingSize.z;
                }
            }
            else
            {
                // If CALC_METHOD is nonzero, then caluclations are based on plot size, not building size.
                // Plot size is 8 metres per square.
                calcWidth  *= 8;
                calcLength *= 8;
            }

            // Display calculated (and retrieved) details.
            detailLabels[(int)Details.width].text       = Translations.Translate("RPR_CAL_BLD_X") + " " + calcWidth;
            detailLabels[(int)Details.length].text      = Translations.Translate("RPR_CAL_BLD_Z") + " " + calcLength;
            detailLabels[(int)Details.height].text      = Translations.Translate("RPR_CAL_BLD_Y") + " " + (int)buildingSize.y;
            detailLabels[(int)Details.personArea].text  = Translations.Translate("RPR_CAL_BLD_M2") + " " + array[DataStore.PEOPLE];
            detailLabels[(int)Details.floorHeight].text = Translations.Translate("RPR_CAL_FLR_Y") + " " + array[DataStore.LEVEL_HEIGHT];
            detailLabels[(int)Details.floors].text      = Translations.Translate("RPR_CAL_FLR") + " " + floorCount;

            // Area calculation - will need this later.
            int calculatedArea = calcWidth * calcLength;

            detailLabels[(int)Details.area].text = Translations.Translate("RPR_CAL_M2") + " " + calculatedArea;

            // Show or hide extra floor modifier as appropriate (hide for zero or less, otherwise show).
            if (array[DataStore.DENSIFICATION] > 0)
            {
                detailLabels[(int)Details.extraFloors].text      = Translations.Translate("RPR_CAL_FLR_M") + " " + array[DataStore.DENSIFICATION];
                detailLabels[(int)Details.extraFloors].isVisible = true;
            }
            else
            {
                detailLabels[(int)Details.extraFloors].isVisible = false;
            }

            // Set minimum residences for high density.
            if ((building.GetSubService() == ItemClass.SubService.ResidentialHigh) || (building.GetSubService() == ItemClass.SubService.ResidentialHighEco))
            {
                // Minimum of 2, or 90% number of floors, whichever is greater. This helps the 1x1 high density.
                minHomesJobs = Mathf.Max(2, Mathf.CeilToInt(0.9f * floorCount));
            }

            // Perform actual household or workplace calculation.
            modCount = Mathf.Max(minHomesJobs, (calculatedArea * (floorCount + Mathf.Max(0, array[DataStore.DENSIFICATION]))) / array[DataStore.PEOPLE]);
            homesJobsCalcLabel.text += modCount;

            // Set customised homes/jobs label (leave blank if no custom setting retrieved).
            if (customHomeJobs > 0)
            {
                homesJobsCustomLabel.text += customHomeJobs.ToString();

                // Update modCount to reflect the custom figures.
                modCount = customHomeJobs;
            }

            // Check to see if Ploppable RICO Revisited is controlling this building's population.
            if (ModUtils.CheckRICO(building))
            {
                messageLabel.text = Translations.Translate("RPR_CAL_RICO");
                messageLabel.Show();
            }
            else
            {
                // Hide message text by default.
                messageLabel.Hide();
            }

            // We've got a valid building and results, so show panel.
            detailsPanel.height    = 270;
            detailsPanel.isVisible = true;
        }
コード例 #11
0
        /// <summary>
        /// Called whenever the currently selected building is changed to update the panel display.
        /// </summary>
        /// <param name="building">Newly selected building</param>
        public void SelectionChanged(BuildingInfo building)
        {
            // Make sure we have a valid selection before proceeding.
            if (building?.name == null)
            {
                return;
            }

            // Variables to compare actual counts vs. mod count, to see if there's another mod overriding counts.
            int appliedCount;
            int modCount;

            // Building model size, not plot size.
            Vector3 buildingSize = building.m_size;
            int     floorCount;

            // Array used for calculations depending on building service/subservice (via DataStore).
            int[] array;
            // Default minimum number of homes or jobs is one; different service types will override this.
            int minHomesJobs = 1;
            int customHomeJobs;

            // Check for valid building AI.
            if (!(building.GetAI() is PrivateBuildingAI buildingAI))
            {
                Logging.Error("invalid building AI type in building details for building ", building.name);
                return;
            }

            // Residential vs. workplace AI.
            if (buildingAI is ResidentialBuildingAI)
            {
                // Get appropriate calculation array.
                array = LegacyAIUtils.GetResidentialArray(building, (int)building.GetClassLevel());

                // Set calculated homes label.
                homesJobsCalcLabel.text = Translations.Translate("RPR_CAL_HOM_CALC");

                // Set customised homes label and get value (if any).
                homesJobsCustomLabel.text = Translations.Translate("RPR_CAL_HOM_CUST");
                customHomeJobs            = OverrideUtils.GetResidential(building);

                // Applied homes is what's actually being returned by the CaclulateHomeCount call to this building AI.
                // It differs from calculated homes if there's an override value for that building with this mod, or if another mod is overriding.
                appliedCount = buildingAI.CalculateHomeCount(building.GetClassLevel(), new Randomizer(0), building.GetWidth(), building.GetLength());
                homesJobsActualLabel.text = Translations.Translate("RPR_CAL_HOM_APPL") + appliedCount;
            }
            else
            {
                // Workplace AI.
                // Default minimum number of jobs is 4.
                minHomesJobs = 4;

                // Find the correct array for the relevant building AI.
                switch (building.GetService())
                {
                case ItemClass.Service.Commercial:
                    array = LegacyAIUtils.GetCommercialArray(building, (int)building.GetClassLevel());
                    break;

                case ItemClass.Service.Office:
                    array = LegacyAIUtils.GetOfficeArray(building, (int)building.GetClassLevel());
                    break;

                case ItemClass.Service.Industrial:
                    if (buildingAI is IndustrialExtractorAI)
                    {
                        array = LegacyAIUtils.GetExtractorArray(building);
                    }
                    else
                    {
                        array = LegacyAIUtils.GetIndustryArray(building, (int)building.GetClassLevel());
                    }
                    break;

                default:
                    Logging.Error("invalid building service in building details for building ", building.name);
                    return;
                }

                // Set calculated jobs label.
                homesJobsCalcLabel.text = Translations.Translate("RPR_CAL_JOB_CALC") + " ";

                // Set customised jobs label and get value (if any).
                homesJobsCustomLabel.text = Translations.Translate("RPR_CAL_JOB_CUST") + " ";
                customHomeJobs            = OverrideUtils.GetWorker(building);

                // Applied jobs is what's actually being returned by the CalculateWorkplaceCount call to this building AI.
                // It differs from calculated jobs if there's an override value for that building with this mod, or if another mod is overriding.
                int[] jobs = new int[4];
                buildingAI.CalculateWorkplaceCount(building.GetClassLevel(), new Randomizer(0), building.GetWidth(), building.GetLength(), out jobs[0], out jobs[1], out jobs[2], out jobs[3]);
                appliedCount = jobs[0] + jobs[1] + jobs[2] + jobs[3];
                homesJobsActualLabel.text = Translations.Translate("RPR_CAL_JOB_APPL") + " " + appliedCount;

                // Show visitor count for commercial buildings.
                if (buildingAI is CommercialBuildingAI commercialAI)
                {
                    visitCountLabel.Show();
                    visitCountLabel.text = Translations.Translate("RPR_CAL_VOL_VIS") + " " + commercialAI.CalculateVisitplaceCount(building.GetClassLevel(), new Randomizer(), building.GetWidth(), building.GetLength());
                }
                else
                {
                    visitCountLabel.Hide();
                }

                // Display production count, or hide the label if not a production building.
                if (building.GetAI() is PrivateBuildingAI privateAI && (privateAI is OfficeBuildingAI || privateAI is IndustrialBuildingAI || privateAI is IndustrialExtractorAI))
                {
                    productionLabel.Show();
                    productionLabel.text = Translations.Translate("RPR_CAL_VOL_PRD") + " " + privateAI.CalculateProductionCapacity(building.GetClassLevel(), new ColossalFramework.Math.Randomizer(), building.GetWidth(), building.GetLength()).ToString();
                }
コード例 #12
0
        /// <summary>
        /// Calculates the construction cost of a workplace, depending on current settings (overrides or default).
        /// </summary>
        /// <param name="thisAI">AI reference to calculate for</param>
        /// <returns>Final construction cost</returns>
        internal static int WorkplaceConstructionCost(PrivateBuildingAI thisAI, int fixedCost)
        {
            int baseCost;

            // Local references.
            BuildingInfo thisInfo = thisAI.m_info;

            ItemClass.Level thisLevel = thisInfo.GetClassLevel();

            // Are we overriding cost?
            if (ModSettings.overrideCost)
            {
                // Yes - calculate based on workplaces by level multiplied by appropriate cost-per-job setting.
                thisAI.CalculateWorkplaceCount(thisLevel, new Randomizer(), thisInfo.GetWidth(), thisInfo.GetLength(), out int jobs0, out int jobs1, out int jobs2, out int jobs3);
                baseCost = (ModSettings.costPerJob0 * jobs0) + (ModSettings.costPerJob1 * jobs1) + (ModSettings.costPerJob2 * jobs2) + (ModSettings.costPerJob3 * jobs3);
            }
            else
            {
                // No - just use the base cost provided.
                baseCost = fixedCost;
            }

            // Multiply base cost by 100 before feeding to EconomyManager for nomalization to game conditions prior to return.
            baseCost *= 100;
            Singleton <EconomyManager> .instance.m_EconomyWrapper.OnGetConstructionCost(ref baseCost, thisInfo.GetService(), thisInfo.GetSubService(), thisLevel);

            return(baseCost);
        }