Example #1
0
        public static bool Prefix(Resource resource, int amount, ItemClass.Service service, ItemClass.SubService subService,
                                  ItemClass.Level level, DistrictPolicies.Taxation taxationPolicies, ref int __result, out bool __state)
        {
            __state = false;

            // Always ignore the private income handler if it's called from AddResource
            AddPrivateIncome.DontRunPatch = true;

            // Don't run patch when we are applying from the command handler
            if (DontRunPatch)
            {
                return(true);
            }

            // Flag to prevent adding resources when it's not possible in the respective command handler
            if (DontAddResource)
            {
                __result = amount;
                // Don't run actual method
                return(false);
            }

            if (amount == 0)
            {
                return(true);
            }

            // Check for resource types that only change in the simulation tick (ignore them in the client)
            if (MultiplayerManager.Instance.CurrentRole == MultiplayerRole.Client)
            {
                switch (resource)
                {
                case Resource.RewardAmount:
                case Resource.CitizenIncome:
                case Resource.PublicIncome:
                case Resource.TourismIncome:
                case Resource.ResourcePrice:
                    // Tell the method caller that the money was added successfully
                    __result = amount;
                    return(false);

                case Resource.PrivateIncome:
                    // Return the same amount as the real method would return (see EconomyManager::AddPrivateIncome)
                    int taxRate = EconomyManager.instance.GetTaxRate(service, subService, level, taxationPolicies);
                    taxRate = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Economics, taxRate);
                    int taxMultiplier = ReflectionHelper.GetAttr <int>(EconomyManager.instance, "m_taxMultiplier");
                    __result = (int)((amount * taxRate * taxMultiplier + 999999L) / 1000000L);
                    return(false);
                }
            }

            __state = true;
            return(true);
        }
        public static bool Prefix(int amount, ItemClass.Service service, ItemClass.SubService subService, ItemClass.Level level, int taxRate)
        {
            if (amount < 0)
            {
                DebugLog.LogToFileOnly($"Error: EconomyManagerAddPrivateIncomePatch amount < 0 {service} {subService} {level}");
                amount = 0;
            }
            if (taxRate == 115333)
            {
                //115333 means playerbuilding income
                //taxRate = 100; no need to send taxRate.
                CustomAddGovermentIncome(ref amount, service);
                service    = ItemClass.Service.Industrial;
                subService = ItemClass.SubService.IndustrialGeneric;
                level      = ItemClass.Level.Level3;
            }
            else if ((taxRate == 113333) || (taxRate == 114333))
            {
                //113333 means tourist tourism income // 114333 means resident tourism income
                CustomAddTourismIncome(ref amount, taxRate);
            }
            else if (taxRate == 112333)
            {
                //112333 means personal slary tax income
                //taxRate = 100; no need to send taxRate.
                CustomAddPersonalTaxIncome(ref amount, service);
            }
            else if (taxRate == 111333)
            {
                //111333 means trade income
                //taxRate = 100; no need to send taxRate.
                CustomAddPrivateTradeIncome(ref amount, subService);
            }
            else if (taxRate >= 100)
            {
                taxRate  = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Economics, taxRate);
                taxRate /= 100;
                CustomAddPrivateLandIncome(ref amount, subService, taxRate);
            }
            else
            {
                amount = 0;
            }

            Singleton <EconomyManager> .instance.AddResource(EconomyManager.Resource.ResourcePrice, amount, service, subService, level, DistrictPolicies.Taxation.None);

            return(false);
        }
        public static float GetResourcePrice(TransferManager.TransferReason material)
        {
            //Need to sync with RealCity mod
            float num;

            if (!RealConstructionThreading.reduceVehicle)
            {
                switch (material)
                {
                case TransferManager.TransferReason.Petrol:
                    num = 3f; break;

                case TransferManager.TransferReason.Food:
                    num = 1.5f; break;

                case TransferManager.TransferReason.Lumber:
                    num = 2f; break;

                case TransferManager.TransferReason.Coal:
                    num = 2.5f; break;

                default: DebugLog.LogToFileOnly("Error: Unknow material in RealConstruction = " + material.ToString()); num = 0f; break;
                }
            }
            else
            {
                switch (material)
                {
                case TransferManager.TransferReason.Petrol:
                    num = 3f * RealConstructionThreading.reduceCargoDiv; break;

                case TransferManager.TransferReason.Food:
                    num = 1.5f * RealConstructionThreading.reduceCargoDiv; break;

                case TransferManager.TransferReason.Lumber:
                    num = 2f * RealConstructionThreading.reduceCargoDiv; break;

                case TransferManager.TransferReason.Coal:
                    num = 2.5f * RealConstructionThreading.reduceCargoDiv; break;

                default: DebugLog.LogToFileOnly("Error: Unknow material in RealConstruction = " + material.ToString()); num = 0f; break;
                }
            }
            return((float)(UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f) * num);
        }
Example #4
0
        public static bool Prefix(ref int __result, TransferManager.TransferReason material, ItemClass.Service sourceService = ItemClass.Service.None)
        {
            bool canRisePrice = true;

            switch (material)
            {
            case TransferManager.TransferReason.AnimalProducts:
                __result = 150; break;

            case TransferManager.TransferReason.Flours:
                __result = 150; break;

            case TransferManager.TransferReason.Paper:
                __result = 200; break;

            case TransferManager.TransferReason.PlanedTimber:
                __result = 200; break;

            case TransferManager.TransferReason.Petroleum:
                __result = 300; break;

            case TransferManager.TransferReason.Plastics:
                __result = 300; break;

            case TransferManager.TransferReason.Glass:
                __result = 250; break;

            case TransferManager.TransferReason.Metals:
                __result = 250; break;

            case TransferManager.TransferReason.LuxuryProducts:
                __result = 350; break;

            case TransferManager.TransferReason.Oil:
                __result = 200; break;

            case TransferManager.TransferReason.Ore:
                __result = 160; break;

            case TransferManager.TransferReason.Logs:
                __result = 130; break;

            case TransferManager.TransferReason.Grain:
                __result = 100; break;

            case TransferManager.TransferReason.Goods:
                if (sourceService == ItemClass.Service.Fishing)
                {
                    __result = 500;
                }
                else
                {
                    __result = 0;
                }
                break;

            case TransferManager.TransferReason.Fish:
                __result = 150; canRisePrice = false; break;

            case TransferManager.TransferReason.Petrol:
                __result = 0; break;

            case TransferManager.TransferReason.Food:
                __result = 0; break;

            case TransferManager.TransferReason.Lumber:
                __result = 0; break;

            case TransferManager.TransferReason.Coal:
                __result = 0; break;

            case TransferManager.TransferReason.Shopping:
            case TransferManager.TransferReason.ShoppingB:
            case TransferManager.TransferReason.ShoppingC:
            case TransferManager.TransferReason.ShoppingD:
            case TransferManager.TransferReason.ShoppingE:
            case TransferManager.TransferReason.ShoppingH:
                if (sourceService == ItemClass.Service.Fishing)
                {
                    __result     = 200;
                    canRisePrice = false;
                }
                else
                {
                    __result = 0;
                }
                break;

            case TransferManager.TransferReason.Entertainment:
            case TransferManager.TransferReason.EntertainmentB:
            case TransferManager.TransferReason.EntertainmentC:
            case TransferManager.TransferReason.EntertainmentD:
                __result = 0; break;

            default: __result = 0; break;
            }

            if (RealCity.reduceVehicle)
            {
                if (canRisePrice)
                {
                    __result <<= MainDataStore.reduceCargoDivShift;
                }
            }

            __result = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, __result);
            return(false);
        }
        public static float GetResourcePrice(TransferManager.TransferReason material)
        {
            int   priceInt = 0;
            float price;

            switch (material)
            {
            case TransferManager.TransferReason.Goods:
                price = 3.5f;
                if (RealCity.reduceVehicle)
                {
                    price *= MainDataStore.reduceCargoDiv;
                }
                price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f);
                break;

            case TransferManager.TransferReason.Petrol:
                price = 3f;
                if (RealCity.reduceVehicle)
                {
                    price *= MainDataStore.reduceCargoDiv;
                }
                price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f);
                break;

            case TransferManager.TransferReason.Food:
                price = 2.4f;
                if (RealCity.reduceVehicle)
                {
                    price *= MainDataStore.reduceCargoDiv;
                }
                price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f);
                break;

            case TransferManager.TransferReason.Lumber:
                price = 2.6f;
                if (RealCity.reduceVehicle)
                {
                    price *= MainDataStore.reduceCargoDiv;
                }
                price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f);
                break;

            case TransferManager.TransferReason.Coal:
                price = 2.8f;
                if (RealCity.reduceVehicle)
                {
                    price *= MainDataStore.reduceCargoDiv;
                }
                price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f);
                break;

            case TransferManager.TransferReason.Shopping:
            case TransferManager.TransferReason.ShoppingB:
            case TransferManager.TransferReason.ShoppingC:
            case TransferManager.TransferReason.ShoppingD:
            case TransferManager.TransferReason.ShoppingE:
            case TransferManager.TransferReason.ShoppingH:
                price = 5f;
                if (RealCity.reduceVehicle)
                {
                    price *= MainDataStore.reduceCargoDiv;
                }
                price *= (UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, 100) / 100f);
                break;

            case TransferManager.TransferReason.Entertainment:
            case TransferManager.TransferReason.EntertainmentB:
            case TransferManager.TransferReason.EntertainmentC:
            case TransferManager.TransferReason.EntertainmentD:
                price = 1f;
                break;

            default: IndustryBuildingGetResourcePricePatch.Prefix(ref priceInt, material); price = priceInt / 100f; break;
            }

            return(price);
        }
Example #6
0
        protected override void ProduceGoods(ushort buildingID, ref Building buildingData, ref Building.Frame frameData, int productionRate, int finalProductionRate, ref Citizen.BehaviourData behaviour, int aliveWorkerCount, int totalWorkerCount, int workPlaceCount, int aliveVisitorCount, int totalVisitorCount, int visitPlaceCount)
        {
            DistrictManager instance = Singleton <DistrictManager> .instance;
            byte            district = instance.GetDistrict(buildingData.m_position);
            byte            b        = instance.GetPark(buildingData.m_position);

            if (b != 0)
            {
                if (!instance.m_parks.m_buffer[(int)b].IsIndustry)
                {
                    b = 0;
                }
                else if (this.m_industryType == DistrictPark.ParkType.Industry || this.m_industryType != instance.m_parks.m_buffer[(int)b].m_parkType)
                {
                    b = 0;
                }
            }
            float num  = (float)buildingData.Width * -4f;
            float num2 = (float)buildingData.Width * 4f;
            float num3 = (float)buildingData.Length * -4f;
            float num4 = (float)buildingData.Length * 4f;

            if (this.m_info.m_subBuildings != null)
            {
                for (int i = 0; i < this.m_info.m_subBuildings.Length; i++)
                {
                    if (this.m_info.m_subBuildings[i].m_buildingInfo != null)
                    {
                        float num5 = (float)this.m_info.m_subBuildings[i].m_buildingInfo.m_cellWidth;
                        float num6 = (float)this.m_info.m_subBuildings[i].m_buildingInfo.m_cellLength;
                        float x    = this.m_info.m_subBuildings[i].m_position.x;
                        float num7 = -this.m_info.m_subBuildings[i].m_position.z;
                        num  = Mathf.Min(num, x - num5 * 4f);
                        num2 = Mathf.Max(num2, x + num5 * 4f);
                        num3 = Mathf.Min(num3, num7 - num6 * 4f);
                        num4 = Mathf.Max(num4, num7 + num6 * 4f);
                    }
                }
            }
            float   angle    = buildingData.m_angle;
            float   num8     = -(num + num2) * 0.5f;
            float   num9     = -(num3 + num4) * 0.5f;
            float   num10    = Mathf.Sin(angle);
            float   num11    = Mathf.Cos(angle);
            Vector3 position = buildingData.m_position - new Vector3(num11 * num8 + num10 * num9, 0f, num10 * num8 - num11 * num9);

            Notification.Problem problem = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem.NoResources | Notification.Problem.NoPlaceforGoods | Notification.Problem.NoInputProducts | Notification.Problem.NoFishingGoods);
            bool flag = this.m_info.m_class.m_service == ItemClass.Service.Fishing;

            DistrictPolicies.Park parkPolicies = instance.m_parks.m_buffer[(int)b].m_parkPolicies;
            DistrictPark[]        buffer       = instance.m_parks.m_buffer;
            byte b2 = b;

            buffer[(int)b2].m_parkPoliciesEffect = (buffer[(int)b2].m_parkPoliciesEffect | (parkPolicies & (DistrictPolicies.Park.ImprovedLogistics | DistrictPolicies.Park.WorkSafety | DistrictPolicies.Park.AdvancedAutomation)));
            if ((parkPolicies & DistrictPolicies.Park.ImprovedLogistics) != DistrictPolicies.Park.None)
            {
                int num12 = this.GetMaintenanceCost() / 100;
                num12 = finalProductionRate * num12 / 1000;
                if (num12 != 0)
                {
                    Singleton <EconomyManager> .instance.FetchResource(EconomyManager.Resource.Maintenance, num12, this.m_info.m_class);
                }
            }
            int num13 = this.m_outputRate;

            if ((parkPolicies & DistrictPolicies.Park.AdvancedAutomation) != DistrictPolicies.Park.None)
            {
                num13 = (num13 * 110 + 50) / 100;
                int num14 = this.GetMaintenanceCost() / 100;
                num14 = finalProductionRate * num14 / 1000;
                if (num14 != 0)
                {
                    Singleton <EconomyManager> .instance.FetchResource(EconomyManager.Resource.Maintenance, num14, this.m_info.m_class);
                }
            }
            if ((parkPolicies & DistrictPolicies.Park.WorkSafety) != DistrictPolicies.Park.None)
            {
                int num15 = (aliveWorkerCount + (int)(Singleton <SimulationManager> .instance.m_currentFrameIndex >> 8 & 15U)) / 16;
                if (num15 != 0)
                {
                    Singleton <EconomyManager> .instance.FetchResource(EconomyManager.Resource.PolicyCost, num15, this.m_info.m_class);
                }
            }
            if (finalProductionRate != 0)
            {
                int num16 = this.m_pollutionAccumulation;
                if (b != 0)
                {
                    int num17;
                    int num18;
                    instance.m_parks.m_buffer[(int)b].GetProductionFactors(out num17, out num18);
                    finalProductionRate = (finalProductionRate * num17 + 50) / 100;
                    num16 = (num16 * num18 + 50) / 100;
                }
                else if (this.m_industryType != DistrictPark.ParkType.Industry)
                {
                    finalProductionRate = 0;
                }
                int num19 = 0;
                int num20 = 0;
                if (this.m_inputResource1 != TransferManager.TransferReason.None)
                {
                    num19 = this.GetInputBufferSize1(parkPolicies, (int)instance.m_parks.m_buffer[(int)b].m_finalStorageDelta);
                    num20 = (int)buildingData.m_customBuffer2;
                    int num21 = (this.m_inputRate1 * finalProductionRate + 99) / 100;
                    if (num20 < num21)
                    {
                        finalProductionRate = (num20 * 100 + this.m_inputRate1 - 1) / this.m_inputRate1;
                        problem             = Notification.AddProblems(problem, (!flag) ? ((!this.IsRawMaterial(this.m_inputResource1)) ? Notification.Problem.NoInputProducts : Notification.Problem.NoResources) : Notification.Problem.NoFishingGoods);
                    }
                }
                int num22 = 0;
                int num23 = 0;
                if (this.m_inputResource2 != TransferManager.TransferReason.None)
                {
                    num22 = this.GetInputBufferSize2(parkPolicies, (int)instance.m_parks.m_buffer[(int)b].m_finalStorageDelta);
                    num23 = ((int)buildingData.m_teens << 8 | (int)buildingData.m_youngs);
                    int num24 = (this.m_inputRate2 * finalProductionRate + 99) / 100;
                    if (num23 < num24)
                    {
                        finalProductionRate = (num23 * 100 + this.m_inputRate2 - 1) / this.m_inputRate2;
                        problem             = Notification.AddProblems(problem, (!flag) ? ((!this.IsRawMaterial(this.m_inputResource2)) ? Notification.Problem.NoInputProducts : Notification.Problem.NoResources) : Notification.Problem.NoFishingGoods);
                    }
                }
                int num25 = 0;
                int num26 = 0;
                if (this.m_inputResource3 != TransferManager.TransferReason.None)
                {
                    num25 = this.GetInputBufferSize3(parkPolicies, (int)instance.m_parks.m_buffer[(int)b].m_finalStorageDelta);
                    num26 = ((int)buildingData.m_adults << 8 | (int)buildingData.m_seniors);
                    int num27 = (this.m_inputRate3 * finalProductionRate + 99) / 100;
                    if (num26 < num27)
                    {
                        finalProductionRate = (num26 * 100 + this.m_inputRate3 - 1) / this.m_inputRate3;
                        problem             = Notification.AddProblems(problem, (!flag) ? ((!this.IsRawMaterial(this.m_inputResource3)) ? Notification.Problem.NoInputProducts : Notification.Problem.NoResources) : Notification.Problem.NoFishingGoods);
                    }
                }
                int num28 = 0;
                int num29 = 0;
                if (this.m_inputResource4 != TransferManager.TransferReason.None)
                {
                    num28 = this.GetInputBufferSize4(parkPolicies, (int)instance.m_parks.m_buffer[(int)b].m_finalStorageDelta);
                    num29 = ((int)buildingData.m_education1 << 8 | (int)buildingData.m_education2);
                    int num30 = (this.m_inputRate4 * finalProductionRate + 99) / 100;
                    if (num29 < num30)
                    {
                        finalProductionRate = (num29 * 100 + this.m_inputRate4 - 1) / this.m_inputRate4;
                        problem             = Notification.AddProblems(problem, (!flag) ? ((!this.IsRawMaterial(this.m_inputResource4)) ? Notification.Problem.NoInputProducts : Notification.Problem.NoResources) : Notification.Problem.NoFishingGoods);
                    }
                }
                int num31 = 0;
                int num32 = 0;
                if (this.m_outputResource != TransferManager.TransferReason.None)
                {
                    num31 = this.GetOutputBufferSize(parkPolicies, (int)instance.m_parks.m_buffer[(int)b].m_finalStorageDelta);
                    num32 = (int)buildingData.m_customBuffer1;
                    int num33 = (num13 * finalProductionRate + 99) / 100;
                    if (num31 - num32 < num33)
                    {
                        num33 = Mathf.Max(0, num31 - num32);
                        finalProductionRate = (num33 * 100 + num13 - 1) / num13;
                        if (this.m_outputVehicleCount != 0)
                        {
                            problem = Notification.AddProblems(problem, Notification.Problem.NoPlaceforGoods);
                            if (this.m_info.m_class.m_service == ItemClass.Service.PlayerIndustry)
                            {
                                GuideController properties = Singleton <GuideManager> .instance.m_properties;
                                if (properties != null)
                                {
                                    Singleton <BuildingManager> .instance.m_warehouseNeeded.Activate(properties.m_warehouseNeeded, buildingID);
                                }
                            }
                        }
                    }
                }
                if (this.m_inputResource1 != TransferManager.TransferReason.None)
                {
                    int num34 = (this.m_inputRate1 * finalProductionRate + 99) / 100;
                    num20 = Mathf.Max(0, num20 - num34);
                    buildingData.m_customBuffer2 = (ushort)num20;
                    instance.m_parks.m_buffer[(int)b].AddConsumptionAmount(this.m_inputResource1, num34);
                }
                if (this.m_inputResource2 != TransferManager.TransferReason.None)
                {
                    int num35 = (this.m_inputRate2 * finalProductionRate + 99) / 100;
                    num23 = Mathf.Max(0, num23 - num35);
                    buildingData.m_youngs = (byte)(num23 & 255);
                    buildingData.m_teens  = (byte)(num23 >> 8);
                    instance.m_parks.m_buffer[(int)b].AddConsumptionAmount(this.m_inputResource2, num35);
                }
                if (this.m_inputResource3 != TransferManager.TransferReason.None)
                {
                    int num36 = (this.m_inputRate3 * finalProductionRate + 99) / 100;
                    num26 = Mathf.Max(0, num26 - num36);
                    buildingData.m_seniors = (byte)(num26 & 255);
                    buildingData.m_adults  = (byte)(num26 >> 8);
                    instance.m_parks.m_buffer[(int)b].AddConsumptionAmount(this.m_inputResource3, num36);
                }
                if (this.m_inputResource4 != TransferManager.TransferReason.None)
                {
                    int num37 = (this.m_inputRate4 * finalProductionRate + 99) / 100;
                    num29 = Mathf.Max(0, num29 - num37);
                    buildingData.m_education2 = (byte)(num29 & 255);
                    buildingData.m_education1 = (byte)(num29 >> 8);
                    instance.m_parks.m_buffer[(int)b].AddConsumptionAmount(this.m_inputResource4, num37);
                }
                if (this.m_outputResource != TransferManager.TransferReason.None)
                {
                    int num38 = (num13 * finalProductionRate + 99) / 100;
                    num32 = Mathf.Min(num31, num32 + num38);
                    buildingData.m_customBuffer1 = (ushort)num32;
                    instance.m_parks.m_buffer[(int)b].AddProductionAmountFish(this.m_outputResource, num38);
                }
                num16 = (finalProductionRate * num16 + 50) / 100;
                if (num16 != 0)
                {
                    num16 = UniqueFacultyAI.DecreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, num16);
                    Singleton <NaturalResourceManager> .instance.TryDumpResource(NaturalResourceManager.Resource.Pollution, num16, num16, position, this.m_pollutionRadius);
                }
                base.HandleDead2(buildingID, ref buildingData, ref behaviour, totalWorkerCount);
                if (b != 0 || this.m_industryType == DistrictPark.ParkType.Industry)
                {
                    int num39 = 0;
                    if (this.m_inputResource1 != TransferManager.TransferReason.None)
                    {
                        int num40 = 0;
                        int num41 = 0;
                        int num42 = 0;
                        int num43 = 0;
                        base.CalculateGuestVehicles(buildingID, ref buildingData, this.m_inputResource1, ref num40, ref num41, ref num42, ref num43);
                        if (num43 != 0)
                        {
                            num39 |= 1;
                        }
                        int num44 = num19 - num20 - num41;
                        if (num44 >= 8000)
                        {
                            TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
                            offer.Priority = Mathf.Max(1, num44 * 8 / num19);
                            offer.Building = buildingID;
                            offer.Position = buildingData.m_position;
                            offer.Amount   = 1;
                            offer.Active   = false;
                            Singleton <TransferManager> .instance.AddIncomingOffer(this.m_inputResource1, offer);
                        }
                        instance.m_parks.m_buffer[(int)b].AddBufferStatus(this.m_inputResource1, num20, num41, num19);
                    }
                    if (this.m_inputResource2 != TransferManager.TransferReason.None)
                    {
                        int num45 = 0;
                        int num46 = 0;
                        int num47 = 0;
                        int num48 = 0;
                        base.CalculateGuestVehicles(buildingID, ref buildingData, this.m_inputResource2, ref num45, ref num46, ref num47, ref num48);
                        if (num48 != 0)
                        {
                            num39 |= 2;
                        }
                        int num49 = num22 - num23 - num46;
                        if (num49 >= 8000)
                        {
                            TransferManager.TransferOffer offer2 = default(TransferManager.TransferOffer);
                            offer2.Priority = Mathf.Max(1, num49 * 8 / num22);
                            offer2.Building = buildingID;
                            offer2.Position = buildingData.m_position;
                            offer2.Amount   = 1;
                            offer2.Active   = false;
                            Singleton <TransferManager> .instance.AddIncomingOffer(this.m_inputResource2, offer2);
                        }
                        instance.m_parks.m_buffer[(int)b].AddBufferStatus(this.m_inputResource2, num23, num46, num22);
                    }
                    if (this.m_inputResource3 != TransferManager.TransferReason.None)
                    {
                        int num50 = 0;
                        int num51 = 0;
                        int num52 = 0;
                        int num53 = 0;
                        base.CalculateGuestVehicles(buildingID, ref buildingData, this.m_inputResource3, ref num50, ref num51, ref num52, ref num53);
                        if (num53 != 0)
                        {
                            num39 |= 4;
                        }
                        int num54 = num25 - num26 - num51;
                        if (num54 >= 8000)
                        {
                            TransferManager.TransferOffer offer3 = default(TransferManager.TransferOffer);
                            offer3.Priority = Mathf.Max(1, num54 * 8 / num25);
                            offer3.Building = buildingID;
                            offer3.Position = buildingData.m_position;
                            offer3.Amount   = 1;
                            offer3.Active   = false;
                            Singleton <TransferManager> .instance.AddIncomingOffer(this.m_inputResource3, offer3);
                        }
                        instance.m_parks.m_buffer[(int)b].AddBufferStatus(this.m_inputResource3, num26, num51, num25);
                    }
                    if (this.m_inputResource4 != TransferManager.TransferReason.None)
                    {
                        int num55 = 0;
                        int num56 = 0;
                        int num57 = 0;
                        int num58 = 0;
                        base.CalculateGuestVehicles(buildingID, ref buildingData, this.m_inputResource4, ref num55, ref num56, ref num57, ref num58);
                        if (num58 != 0)
                        {
                            num39 |= 8;
                        }
                        int num59 = num28 - num29 - num56;
                        if (num59 >= 8000)
                        {
                            TransferManager.TransferOffer offer4 = default(TransferManager.TransferOffer);
                            offer4.Priority = Mathf.Max(1, num59 * 8 / num28);
                            offer4.Building = buildingID;
                            offer4.Position = buildingData.m_position;
                            offer4.Amount   = 1;
                            offer4.Active   = false;
                            Singleton <TransferManager> .instance.AddIncomingOffer(this.m_inputResource4, offer4);
                        }
                        instance.m_parks.m_buffer[(int)b].AddBufferStatus(this.m_inputResource4, num29, num56, num28);
                    }
                    buildingData.m_tempImport |= (byte)num39;
                    if (this.m_outputResource != TransferManager.TransferReason.None)
                    {
                        if (this.m_outputVehicleCount == 0)
                        {
                            if (num32 == num31)
                            {
                                int num60 = (num32 * IndustryBuildingAI.GetResourcePrice(this.m_outputResource, ItemClass.Service.None) + 50) / 100;
                                if ((instance.m_districts.m_buffer[(int)district].m_cityPlanningPolicies & DistrictPolicies.CityPlanning.SustainableFishing) != DistrictPolicies.CityPlanning.None)
                                {
                                    num60 = (num60 * 105 + 99) / 100;
                                }
                                num60 = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, num60);
                                Singleton <EconomyManager> .instance.AddResource(EconomyManager.Resource.ResourcePrice, num60, this.m_info.m_class);

                                if (b != 0)
                                {
                                    instance.m_parks.m_buffer[(int)b].AddExportAmountFish(this.m_outputResource, num32);
                                }
                                num32 = 0;
                                buildingData.m_customBuffer1 = (ushort)num32;
                                buildingData.m_tempExport    = byte.MaxValue;
                            }
                        }
                        else
                        {
                            int num61 = 0;
                            int num62 = 0;
                            int num63 = 0;
                            int value = 0;
                            base.CalculateOwnVehicles(buildingID, ref buildingData, this.m_outputResource, ref num61, ref num62, ref num63, ref value);
                            buildingData.m_tempExport = (byte)Mathf.Clamp(value, (int)buildingData.m_tempExport, 255);
                            int budget = Singleton <EconomyManager> .instance.GetBudget(this.m_info.m_class);

                            int productionRate2 = PlayerBuildingAI.GetProductionRate(100, budget);
                            int num64           = (productionRate2 * this.m_outputVehicleCount + 99) / 100;
                            int num65           = num32;
                            if (num65 >= 8000 && num61 < num64)
                            {
                                TransferManager.TransferOffer offer5 = default(TransferManager.TransferOffer);
                                offer5.Priority = Mathf.Max(1, num65 * 8 / num31);
                                offer5.Building = buildingID;
                                offer5.Position = buildingData.m_position;
                                offer5.Amount   = 1;
                                offer5.Active   = true;
                                Singleton <TransferManager> .instance.AddOutgoingOffer(this.m_outputResource, offer5);
                            }
                        }
                        instance.m_parks.m_buffer[(int)b].AddBufferStatusFish(this.m_outputResource, num32, 0, num31);
                    }
                }
                if (buildingData.m_finalImport != 0)
                {
                    District[] buffer2 = instance.m_districts.m_buffer;
                    byte       b3      = district;
                    buffer2[(int)b3].m_playerConsumption.m_finalImportAmount = buffer2[(int)b3].m_playerConsumption.m_finalImportAmount + (uint)buildingData.m_finalImport;
                }
                if (buildingData.m_finalExport != 0)
                {
                    District[] buffer3 = instance.m_districts.m_buffer;
                    byte       b4      = district;
                    buffer3[(int)b4].m_playerConsumption.m_finalExportAmount = buffer3[(int)b4].m_playerConsumption.m_finalExportAmount + (uint)buildingData.m_finalExport;
                }
                int num66 = finalProductionRate * this.m_noiseAccumulation / 100;
                if (num66 != 0)
                {
                    Singleton <ImmaterialResourceManager> .instance.AddResource(ImmaterialResourceManager.Resource.NoisePollution, num66, position, this.m_noiseRadius);
                }
            }
            buildingData.m_problems   = problem;
            buildingData.m_education3 = (byte)Mathf.Clamp(finalProductionRate * num13 / Mathf.Max(1, this.m_outputRate), 0, 255);
            buildingData.m_health     = (byte)Mathf.Clamp(finalProductionRate, 0, 255);
            if (b != 0)
            {
                instance.m_parks.m_buffer[(int)b].AddWorkers(aliveWorkerCount);
            }
            else if (this.m_industryType != DistrictPark.ParkType.Industry)
            {
                GuideController properties2 = Singleton <GuideManager> .instance.m_properties;
                if (properties2 != null)
                {
                    Singleton <BuildingManager> .instance.m_industryBuildingOutsideIndustryArea.Activate(properties2.m_industryBuildingOutsideIndustryArea, buildingID);
                }
            }
            base.ProduceGoods(buildingID, ref buildingData, ref frameData, productionRate, finalProductionRate, ref behaviour, aliveWorkerCount, totalWorkerCount, workPlaceCount, aliveVisitorCount, totalVisitorCount, visitPlaceCount);
        }
        public static int ProcessCitizenSalary(uint citizenId, bool checkOnly)
        {
            int salary = 0;

            if (citizenId != 0u)
            {
                Citizen.Flags citizenFlag = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].m_flags;
                if ((citizenFlag & Citizen.Flags.Student) != Citizen.Flags.None)
                {
                    return(salary);
                }
                ushort workBuilding = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].m_workBuilding;
                if (workBuilding != 0u)
                {
                    Building buildingData = Singleton <BuildingManager> .instance.m_buildings.m_buffer[workBuilding];
                    if (!IsGoverment(workBuilding))
                    {
                        salary = BuildingData.buildingWorkCount[workBuilding];
                        if (!checkOnly)
                        {
                            if (buildingData.Info.m_class.m_service != ItemClass.Service.Office)
                            {
                                BuildingData.buildingMoney[workBuilding] -= salary;
                            }
                        }
                    }
                    else
                    {
                        //Goverment
                        int aliveWorkCount = 0;
                        int totalWorkCount = 0;
                        Citizen.BehaviourData behaviour = default;
                        RealCityCommonBuildingAI.InitDelegate();
                        RealCityCommonBuildingAI.GetWorkBehaviour((CommonBuildingAI)buildingData.Info.m_buildingAI, workBuilding, ref buildingData, ref behaviour, ref aliveWorkCount, ref totalWorkCount);
                        int salaryMax = 0;
                        switch (Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].EducationLevel)
                        {
                        case Citizen.Education.Uneducated:
                            salaryMax = (int)(MainDataStore.govermentSalary * 0.5);
                            salary    = MainDataStore.govermentEducation0SalaryFixed; break;

                        case Citizen.Education.OneSchool:
                            salaryMax = (int)(MainDataStore.govermentSalary * 0.55);
                            salary    = MainDataStore.govermentEducation1SalaryFixed; break;

                        case Citizen.Education.TwoSchools:
                            salaryMax = (int)(MainDataStore.govermentSalary * 0.65);
                            salary    = MainDataStore.govermentEducation2SalaryFixed; break;

                        case Citizen.Education.ThreeSchools:
                            salaryMax = (int)(MainDataStore.govermentSalary * 0.8);
                            salary    = MainDataStore.govermentEducation3SalaryFixed; break;
                        }
                        int allWorkCount = 0;
                        //Update to see if there is building workplace change.
                        //If a building have 10 workers and have 100 workplacecount, we assume that the other 90 vitual workers are from outside
                        //Which will give addition cost
                        allWorkCount = TotalWorkCount(workBuilding, buildingData, false, false);
                        if (totalWorkCount > allWorkCount)
                        {
                            Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].SetWorkplace(citizenId, 0, 0u);
                        }
                        float vitualWorkersRatio = (totalWorkCount != 0) ? (allWorkCount / (float)totalWorkCount) : 1f;

                        //Budget offset for Salary
                        int budget = Singleton <EconomyManager> .instance.GetBudget(buildingData.Info.m_class);

                        salary = (int)(salary * budget / 100f);
                        salary = Math.Max(salary, salaryMax);
#if Debug
                        DebugLog.LogToFileOnly("DebugInfo: LandPrice offset for Salary is " + landPriceOffset.ToString());
#endif
                        salary = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, salary);
                        if (!checkOnly)
                        {
                            var m_class = Singleton <BuildingManager> .instance.m_buildings.m_buffer[workBuilding].Info.m_class;
                            Singleton <EconomyManager> .instance.FetchResource((EconomyManager.Resource) 16, (int)(salary * vitualWorkersRatio), m_class);

                            MainDataStore.outsideTouristMoney += (salary * (vitualWorkersRatio - 1f) * MainDataStore.outsideTouristSalaryProfitRatio);
                        }
                    }
                }
            }

            return(salary);
        }        //public
        }        //public

        public static int TotalWorkCount(ushort buildingID, Building data, bool checkOnly, bool update)
        {
            int totalWorkCount = 0;

            //For performance
#if FASTRUN
            update = false;
#endif
            if (BuildingData.isBuildingWorkerUpdated[buildingID] && !update)
            {
                totalWorkCount = BuildingData.buildingWorkCount[buildingID];
            }
            else
            {
                if (data.Info.m_buildingAI is LandfillSiteAI)
                {
                    LandfillSiteAI buildingAI = data.Info.m_buildingAI as LandfillSiteAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is ExtractingFacilityAI)
                {
                    ExtractingFacilityAI buildingAI = data.Info.m_buildingAI as ExtractingFacilityAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is ProcessingFacilityAI)
                {
                    ProcessingFacilityAI buildingAI = data.Info.m_buildingAI as ProcessingFacilityAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is PoliceStationAI)
                {
                    PoliceStationAI buildingAI = data.Info.m_buildingAI as PoliceStationAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is FireStationAI)
                {
                    FireStationAI buildingAI = data.Info.m_buildingAI as FireStationAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is HospitalAI)
                {
                    HospitalAI buildingAI = data.Info.m_buildingAI as HospitalAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is CargoStationAI)
                {
                    CargoStationAI buildingAI = data.Info.m_buildingAI as CargoStationAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is TransportStationAI)
                {
                    TransportStationAI buildingAI = data.Info.m_buildingAI as TransportStationAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is CemeteryAI)
                {
                    CemeteryAI buildingAI = data.Info.m_buildingAI as CemeteryAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is MedicalCenterAI)
                {
                    MedicalCenterAI buildingAI = data.Info.m_buildingAI as MedicalCenterAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is MonumentAI)
                {
                    MonumentAI buildingAI = data.Info.m_buildingAI as MonumentAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is DepotAI)
                {
                    DepotAI buildingAI = data.Info.m_buildingAI as DepotAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is HelicopterDepotAI)
                {
                    HelicopterDepotAI buildingAI = data.Info.m_buildingAI as HelicopterDepotAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is MaintenanceDepotAI)
                {
                    MaintenanceDepotAI buildingAI = data.Info.m_buildingAI as MaintenanceDepotAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is FirewatchTowerAI)
                {
                    FirewatchTowerAI buildingAI = data.Info.m_buildingAI as FirewatchTowerAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is DoomsdayVaultAI)
                {
                    DoomsdayVaultAI buildingAI = data.Info.m_buildingAI as DoomsdayVaultAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is DisasterResponseBuildingAI)
                {
                    DisasterResponseBuildingAI buildingAI = data.Info.m_buildingAI as DisasterResponseBuildingAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is HadronColliderAI)
                {
                    HadronColliderAI buildingAI = data.Info.m_buildingAI as HadronColliderAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is SchoolAI)
                {
                    SchoolAI buildingAI = data.Info.m_buildingAI as SchoolAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is PowerPlantAI)
                {
                    PowerPlantAI buildingAI = data.Info.m_buildingAI as PowerPlantAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is SnowDumpAI)
                {
                    SnowDumpAI buildingAI = data.Info.m_buildingAI as SnowDumpAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is WarehouseAI)
                {
                    WarehouseAI buildingAI = data.Info.m_buildingAI as WarehouseAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is WaterFacilityAI)
                {
                    WaterFacilityAI buildingAI = data.Info.m_buildingAI as WaterFacilityAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is SaunaAI)
                {
                    SaunaAI buildingAI = data.Info.m_buildingAI as SaunaAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is PostOfficeAI)
                {
                    PostOfficeAI buildingAI = data.Info.m_buildingAI as PostOfficeAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is RadioMastAI)
                {
                    RadioMastAI buildingAI = data.Info.m_buildingAI as RadioMastAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is SpaceElevatorAI)
                {
                    SpaceElevatorAI buildingAI = data.Info.m_buildingAI as SpaceElevatorAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is SpaceRadarAI)
                {
                    SpaceRadarAI buildingAI = data.Info.m_buildingAI as SpaceRadarAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is MainIndustryBuildingAI)
                {
                    MainIndustryBuildingAI buildingAI = data.Info.m_buildingAI as MainIndustryBuildingAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is AuxiliaryBuildingAI)
                {
                    AuxiliaryBuildingAI buildingAI = data.Info.m_buildingAI as AuxiliaryBuildingAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is ShelterAI)
                {
                    ShelterAI buildingAI = data.Info.m_buildingAI as ShelterAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is HeatingPlantAI)
                {
                    HeatingPlantAI buildingAI = data.Info.m_buildingAI as HeatingPlantAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is MainCampusBuildingAI)
                {
                    MainCampusBuildingAI buildingAI = data.Info.m_buildingAI as MainCampusBuildingAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is MuseumAI)
                {
                    MuseumAI buildingAI = data.Info.m_buildingAI as MuseumAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is UniqueFactoryAI)
                {
                    UniqueFactoryAI buildingAI = data.Info.m_buildingAI as UniqueFactoryAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is UniqueFacultyAI)
                {
                    UniqueFacultyAI buildingAI = data.Info.m_buildingAI as UniqueFacultyAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is VarsitySportsArenaAI)
                {
                    VarsitySportsArenaAI buildingAI = data.Info.m_buildingAI as VarsitySportsArenaAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is LibraryAI)
                {
                    LibraryAI buildingAI = data.Info.m_buildingAI as LibraryAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is FishFarmAI)
                {
                    FishFarmAI buildingAI = data.Info.m_buildingAI as FishFarmAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is FishingHarborAI)
                {
                    FishingHarborAI buildingAI = data.Info.m_buildingAI as FishingHarborAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is EldercareAI)
                {
                    EldercareAI buildingAI = data.Info.m_buildingAI as EldercareAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is ChildcareAI)
                {
                    ChildcareAI buildingAI = data.Info.m_buildingAI as ChildcareAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else if (data.Info.m_buildingAI is MarketAI)
                {
                    MarketAI buildingAI = data.Info.m_buildingAI as MarketAI;
                    totalWorkCount = buildingAI.m_workPlaceCount0 + buildingAI.m_workPlaceCount1 + buildingAI.m_workPlaceCount2 + buildingAI.m_workPlaceCount3;
                }
                else
                {
                    if (!checkOnly)
                    {
                        DebugLog.LogToFileOnly("Error: find unknow building = " + data.Info.m_buildingAI.ToString());
                    }
                }

                BuildingData.isBuildingWorkerUpdated[buildingID] = true;
                BuildingData.buildingWorkCount[buildingID]       = totalWorkCount;
            }
            return(totalWorkCount);
        }
        public static void ProcessFamily(uint homeID, ref CitizenUnit data)
        {
            if (RealCityResidentAI.preCitizenId > homeID)
            {
                //DebugLog.LogToFileOnly("Another period started");
                MainDataStore.familyCount      = RealCityResidentAI.familyCount;
                MainDataStore.citizenCount     = RealCityResidentAI.citizenCount;
                MainDataStore.level2HighWealth = RealCityResidentAI.level2HighWealth;
                MainDataStore.level3HighWealth = RealCityResidentAI.level3HighWealth;
                MainDataStore.level1HighWealth = RealCityResidentAI.level1HighWealth;
                if (RealCityResidentAI.familyCount != 0)
                {
                    MainDataStore.citizenSalaryPerFamily  = ((RealCityResidentAI.citizenSalaryCount / RealCityResidentAI.familyCount));
                    MainDataStore.citizenExpensePerFamily = ((RealCityResidentAI.citizenExpenseCount / RealCityResidentAI.familyCount));
                }
                MainDataStore.citizenExpense        = RealCityResidentAI.citizenExpenseCount;
                MainDataStore.citizenSalaryTaxTotal = RealCityResidentAI.citizenSalaryTaxTotal;
                MainDataStore.citizenSalaryTotal    = RealCityResidentAI.citizenSalaryCount;
                if (MainDataStore.familyCount < MainDataStore.familyWeightStableHigh)
                {
                    MainDataStore.familyWeightStableHigh = (uint)MainDataStore.familyCount;
                }
                else
                {
                    MainDataStore.familyWeightStableHigh = RealCityResidentAI.familyWeightStableHigh;
                }
                if (MainDataStore.familyCount < MainDataStore.familyWeightStableLow)
                {
                    MainDataStore.familyWeightStableLow = (uint)MainDataStore.familyCount;
                }
                else
                {
                    MainDataStore.familyWeightStableLow = RealCityResidentAI.familyWeightStableLow;
                }

                RealCityPrivateBuildingAI.profitBuildingMoneyFinal = RealCityPrivateBuildingAI.profitBuildingMoney;

                RealCityResidentAI.level3HighWealth           = 0;
                RealCityResidentAI.level2HighWealth           = 0;
                RealCityResidentAI.level1HighWealth           = 0;
                RealCityResidentAI.familyCount                = 0;
                RealCityResidentAI.citizenCount               = 0;
                RealCityResidentAI.citizenSalaryCount         = 0;
                RealCityResidentAI.citizenExpenseCount        = 0;
                RealCityResidentAI.citizenSalaryTaxTotal      = 0;
                RealCityResidentAI.tempCitizenSalaryTaxTotal  = 0f;
                RealCityResidentAI.familyWeightStableHigh     = 0;
                RealCityResidentAI.familyWeightStableLow      = 0;
                RealCityPrivateBuildingAI.profitBuildingMoney = 0;
            }

            RealCityResidentAI.preCitizenId = homeID;
            RealCityResidentAI.familyCount++;

            if (homeID > 524288)
            {
                DebugLog.LogToFileOnly("Error: citizen ID greater than 524288");
            }

            //DebugLog.LogToFileOnly($"ProcessCitizen pre family {homeID} moneny {CitizenUnitData.familyMoney[homeID]}");
            //ProcessCitizen pre, gather all citizenMoney to familyMoney
            ProcessCitizen(homeID, ref data, true);
            //DebugLog.LogToFileOnly($"ProcessCitizen post family {homeID} moneny {CitizenUnitData.familyMoney[homeID]}");
            //1.We calculate citizen income
            int familySalaryCurrent = 0;

            familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen0, false);
            familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen1, false);
            familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen2, false);
            familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen3, false);
            familySalaryCurrent += RealCityResidentAI.ProcessCitizenSalary(data.m_citizen4, false);
            RealCityResidentAI.citizenSalaryCount = RealCityResidentAI.citizenSalaryCount + familySalaryCurrent;
            if (familySalaryCurrent < 0)
            {
                DebugLog.LogToFileOnly("familySalaryCurrent< 0 in ResidentAI");
                familySalaryCurrent = 0;
            }

            //2.We calculate salary tax
            float tax = (float)(Politics.residentTax << 1) * familySalaryCurrent / 100f;

            RealCityResidentAI.tempCitizenSalaryTaxTotal = RealCityResidentAI.tempCitizenSalaryTaxTotal + (int)tax;
            RealCityResidentAI.citizenSalaryTaxTotal     = (int)RealCityResidentAI.tempCitizenSalaryTaxTotal;
            ProcessCitizenIncomeTax(homeID, tax);

            //3. We calculate expense
            int            educationFee = 0;
            int            hospitalFee  = 0;
            int            expenseRate  = 0;
            CitizenManager instance     = Singleton <CitizenManager> .instance;
            int            tempEducationFee;
            int            tempHospitalFee;

            if (data.m_citizen4 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen4)].Dead)
            {
                GetExpenseRate(data.m_citizen4, out expenseRate, out tempEducationFee, out tempHospitalFee);
                educationFee += tempEducationFee;
                hospitalFee  += tempHospitalFee;
            }
            if (data.m_citizen3 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen3)].Dead)
            {
                GetExpenseRate(data.m_citizen3, out expenseRate, out tempEducationFee, out tempHospitalFee);
                educationFee += tempEducationFee;
                hospitalFee  += tempHospitalFee;
            }
            if (data.m_citizen2 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen2)].Dead)
            {
                GetExpenseRate(data.m_citizen2, out expenseRate, out tempEducationFee, out tempHospitalFee);
                educationFee += tempEducationFee;
                hospitalFee  += tempHospitalFee;
            }
            if (data.m_citizen1 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen1)].Dead)
            {
                GetExpenseRate(data.m_citizen1, out expenseRate, out tempEducationFee, out tempHospitalFee);
                educationFee += tempEducationFee;
                hospitalFee  += tempHospitalFee;
            }
            if (data.m_citizen0 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen0)].Dead)
            {
                GetExpenseRate(data.m_citizen0, out expenseRate, out tempEducationFee, out tempHospitalFee);
                educationFee += tempEducationFee;
                hospitalFee  += tempHospitalFee;
            }
            ProcessCitizenHouseRent(homeID, expenseRate);
            //campus DLC added.
            expenseRate = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Economics, expenseRate);
            RealCityResidentAI.citizenExpenseCount += (educationFee + expenseRate + hospitalFee);

            //4. income - expense
            float incomeMinusExpense = familySalaryCurrent - tax - educationFee - expenseRate;

            CitizenUnitData.familyMoney[homeID] += incomeMinusExpense;

            //5. Limit familyMoney
            if (CitizenUnitData.familyMoney[homeID] > 100000000f)
            {
                CitizenUnitData.familyMoney[homeID] = 100000000f;
            }

            if (CitizenUnitData.familyMoney[homeID] < -100000000f)
            {
                CitizenUnitData.familyMoney[homeID] = -100000000f;
            }

            //6. Caculate minimumLivingAllowance and benefitOffset
            if (CitizenUnitData.familyMoney[homeID] < (-(Politics.benefitOffset * MainDataStore.govermentSalary) / 100f))
            {
                int num = (int)(-CitizenUnitData.familyMoney[homeID]);
                CitizenUnitData.familyMoney[homeID]  += num;
                MainDataStore.minimumLivingAllowance += num;
                Singleton <EconomyManager> .instance.FetchResource((EconomyManager.Resource) 17, num, ItemClass.Service.Residential, ItemClass.SubService.None, ItemClass.Level.Level1);
            }
            else
            {
                if (Politics.benefitOffset > 0)
                {
                    CitizenUnitData.familyMoney[homeID]  += ((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f);
                    MainDataStore.minimumLivingAllowance += (int)((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f);
                    Singleton <EconomyManager> .instance.FetchResource((EconomyManager.Resource) 17, (int)((Politics.benefitOffset * MainDataStore.govermentSalary) / 100f), ItemClass.Service.Residential, ItemClass.SubService.None, ItemClass.Level.Level1);
                }
            }

            var canBuyGoodMoney        = MainDataStore.maxGoodPurchase * RealCityIndustryBuildingAI.GetResourcePrice(TransferManager.TransferReason.Shopping);
            var familySalaryCurrentTmp = (familySalaryCurrent > canBuyGoodMoney) ? canBuyGoodMoney : familySalaryCurrent;

            //7. Process citizen status
            if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 30)
            {
                RealCityResidentAI.level3HighWealth++;
            }
            else if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 20)
            {
                RealCityResidentAI.level2HighWealth++;
            }
            else if ((CitizenUnitData.familyMoney[homeID] / (canBuyGoodMoney + 1000f - familySalaryCurrentTmp)) >= 10)
            {
                RealCityResidentAI.level1HighWealth++;
            }

            //8 reduce goods
            float reducedGoods;

            if (CitizenUnitData.familyMoney[homeID] < canBuyGoodMoney)
            {
                reducedGoods = CitizenUnitData.familyGoods[homeID] / 100f;
            }
            else
            {
                reducedGoods = CitizenUnitData.familyGoods[homeID] / 50f;
            }

            CitizenUnitData.familyGoods[homeID] = (ushort)COMath.Clamp((int)(CitizenUnitData.familyGoods[homeID] - reducedGoods), 0, 60000);
            data.m_goods = (ushort)(CitizenUnitData.familyGoods[homeID] / 10f);

            //9 Buy good from outside and try move family
            if (data.m_goods == 0)
            {
                if ((CitizenUnitData.familyMoney[homeID] > canBuyGoodMoney) && (familySalaryCurrent > 1))
                {
                    uint citizenID  = 0u;
                    int  familySize = 0;
                    if (data.m_citizen4 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen4)].Dead)
                    {
                        familySize++;
                        citizenID = data.m_citizen4;
                        instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods;
                    }
                    if (data.m_citizen3 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen3)].Dead)
                    {
                        familySize++;
                        citizenID = data.m_citizen3;
                        instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods;
                    }
                    if (data.m_citizen2 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen2)].Dead)
                    {
                        familySize++;
                        citizenID = data.m_citizen2;
                        instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods;
                    }
                    if (data.m_citizen1 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen1)].Dead)
                    {
                        familySize++;
                        citizenID = data.m_citizen1;
                        instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods;
                    }
                    if (data.m_citizen0 != 0u && !instance.m_citizens.m_buffer[(int)((UIntPtr)data.m_citizen0)].Dead)
                    {
                        familySize++;
                        citizenID = data.m_citizen0;
                        instance.m_citizens.m_buffer[citizenID].m_flags &= ~Citizen.Flags.NeedGoods;
                    }

                    Singleton <ResidentAI> .instance.TryMoveFamily(citizenID, ref instance.m_citizens.m_buffer[citizenID], familySize);

                    CitizenUnitData.familyGoods[homeID] = 5000;
                    data.m_goods = (ushort)(CitizenUnitData.familyGoods[homeID] / 10f);
                    CitizenUnitData.familyMoney[homeID] -= canBuyGoodMoney;
                    MainDataStore.outsideGovermentMoney += (canBuyGoodMoney * MainDataStore.outsideGovermentProfitRatio);
                    MainDataStore.outsideTouristMoney   += (canBuyGoodMoney * MainDataStore.outsideCompanyProfitRatio * MainDataStore.outsideTouristSalaryProfitRatio);
                }
            }

            //ProcessCitizen post, split all familyMoney to CitizenMoney
            ProcessCitizen(homeID, ref data, false);
        }