Skip to content

Commit

Permalink
Fix for commercial building problems that build up over time.
Browse files Browse the repository at this point in the history
New preview image
Clean up
  • Loading branch information
PropaneDragon committed Jan 22, 2016
1 parent 6b96bbb commit 22608ef
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 42 deletions.
Binary file modified PreviewImage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
84 changes: 47 additions & 37 deletions RushHour/BuildingHandlers/NewCommercialBuildingAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,53 +12,51 @@ public class NewCommercialBuildingAI
[RedirectMethod]
public static void SimulationStepActive(CommercialBuildingAI thisAI, ushort buildingID, ref Building buildingData, ref Building.Frame frameData)
{
//This is a mess because I pulled it directly from the decompiled code and patched it up slightly.
//It works though, and that's all I'm bothered about for now.

DistrictManager instance1 = Singleton<DistrictManager>.instance;
byte district = instance1.GetDistrict(buildingData.m_position);
DistrictPolicies.Services policies = instance1.m_districts.m_buffer[(int)district].m_servicePolicies;
DistrictPolicies.Taxation taxationPolicies = instance1.m_districts.m_buffer[(int)district].m_taxationPolicies;
DistrictPolicies.CityPlanning cityPlanningPolicies = instance1.m_districts.m_buffer[(int)district].m_cityPlanningPolicies;
instance1.m_districts.m_buffer[(int)district].m_servicePoliciesEffect |= policies & (DistrictPolicies.Services.PowerSaving | DistrictPolicies.Services.WaterSaving | DistrictPolicies.Services.SmokeDetectors | DistrictPolicies.Services.Recycling | DistrictPolicies.Services.RecreationalUse);
DistrictManager _districtManager = Singleton<DistrictManager>.instance;
byte districtId = _districtManager.GetDistrict(buildingData.m_position);
District _district = _districtManager.m_districts.m_buffer[districtId];

DistrictPolicies.Services policies = _district.m_servicePolicies;
DistrictPolicies.Taxation taxationPolicies = _district.m_taxationPolicies;
DistrictPolicies.CityPlanning cityPlanningPolicies = _district.m_cityPlanningPolicies;

_district.m_servicePoliciesEffect |= policies & (DistrictPolicies.Services.PowerSaving | DistrictPolicies.Services.WaterSaving | DistrictPolicies.Services.SmokeDetectors | DistrictPolicies.Services.Recycling | DistrictPolicies.Services.RecreationalUse);

switch (thisAI.m_info.m_class.m_subService)
{
case ItemClass.SubService.CommercialLow:
if ((taxationPolicies & (DistrictPolicies.Taxation.TaxRaiseComLow | DistrictPolicies.Taxation.TaxLowerComLow)) != (DistrictPolicies.Taxation.TaxRaiseComLow | DistrictPolicies.Taxation.TaxLowerComLow))
instance1.m_districts.m_buffer[(int)district].m_taxationPoliciesEffect |= taxationPolicies & (DistrictPolicies.Taxation.TaxRaiseComLow | DistrictPolicies.Taxation.TaxLowerComLow);
instance1.m_districts.m_buffer[(int)district].m_cityPlanningPoliciesEffect |= cityPlanningPolicies & DistrictPolicies.CityPlanning.SmallBusiness;
_district.m_taxationPoliciesEffect |= taxationPolicies & (DistrictPolicies.Taxation.TaxRaiseComLow | DistrictPolicies.Taxation.TaxLowerComLow);
_district.m_cityPlanningPoliciesEffect |= cityPlanningPolicies & DistrictPolicies.CityPlanning.SmallBusiness;
break;
case ItemClass.SubService.CommercialHigh:
if ((taxationPolicies & (DistrictPolicies.Taxation.TaxRaiseComHigh | DistrictPolicies.Taxation.TaxLowerComHigh)) != (DistrictPolicies.Taxation.TaxRaiseComHigh | DistrictPolicies.Taxation.TaxLowerComHigh))
instance1.m_districts.m_buffer[(int)district].m_taxationPoliciesEffect |= taxationPolicies & (DistrictPolicies.Taxation.TaxRaiseComHigh | DistrictPolicies.Taxation.TaxLowerComHigh);
instance1.m_districts.m_buffer[(int)district].m_cityPlanningPoliciesEffect |= cityPlanningPolicies & DistrictPolicies.CityPlanning.BigBusiness;
_district.m_taxationPoliciesEffect |= taxationPolicies & (DistrictPolicies.Taxation.TaxRaiseComHigh | DistrictPolicies.Taxation.TaxLowerComHigh);
_district.m_cityPlanningPoliciesEffect |= cityPlanningPolicies & DistrictPolicies.CityPlanning.BigBusiness;
break;
case ItemClass.SubService.CommercialLeisure:
instance1.m_districts.m_buffer[(int)district].m_taxationPoliciesEffect |= taxationPolicies & DistrictPolicies.Taxation.DontTaxLeisure;
instance1.m_districts.m_buffer[(int)district].m_cityPlanningPoliciesEffect |= cityPlanningPolicies & DistrictPolicies.CityPlanning.NoLoudNoises;
_district.m_taxationPoliciesEffect |= taxationPolicies & DistrictPolicies.Taxation.DontTaxLeisure;
_district.m_cityPlanningPoliciesEffect |= cityPlanningPolicies & DistrictPolicies.CityPlanning.NoLoudNoises;
break;
}

Citizen.BehaviourData behaviour = new Citizen.BehaviourData();
int aliveWorkerCount = 0;
int totalWorkerCount = 0;
int workPlaceCount = 0;

int aliveWorkerCount = 0, totalWorkerCount = 0, workPlaceCount = 0, aliveCount = 0, totalCount = 0;
int workers = HandleWorkers(thisAI, buildingID, ref buildingData, ref behaviour, ref aliveWorkerCount, ref totalWorkerCount, ref workPlaceCount);

int width = buildingData.Width;
int length = buildingData.Length;
int maxIncomingLoadSize = MaxIncomingLoadSize(thisAI);
int aliveCount = 0;
int totalCount = 0;

GetVisitBehaviour(thisAI, buildingID, ref buildingData, ref behaviour, ref aliveCount, ref totalCount);

int visitCount = thisAI.CalculateVisitplaceCount(new Randomizer((int)buildingID), width, length);
int num3 = Mathf.Max(0, visitCount - totalCount);
int a1 = visitCount * 500;
int num4 = Mathf.Max(a1, maxIncomingLoadSize * 4);
int visitCount = thisAI.CalculateVisitplaceCount(new Randomizer(buildingID), width, length);
int remainingCount = Mathf.Max(0, visitCount - totalCount);
int multipliedVisitCount = visitCount * 500;
int num4 = Mathf.Max(multipliedVisitCount, maxIncomingLoadSize * 4);

TransferManager.TransferReason incomingTransferReason = GetIncomingTransferReason(thisAI);
TransferManager.TransferReason outgoingTransferReason = GetOutgoingTransferReason(thisAI, buildingID);

if (workers != 0)
{
int num5 = num4;
Expand All @@ -77,24 +75,24 @@ public static void SimulationStepActive(CommercialBuildingAI thisAI, ushort buil
buildingData.m_customBuffer2 += (ushort)num7;
workers = (num7 + 9) / 10;
}
int electricityConsumption;
int waterConsumption;
int sewageAccumulation;
int garbageAccumulation;
int incomeAccumulation;

int electricityConsumption, waterConsumption, sewageAccumulation, garbageAccumulation, incomeAccumulation, taxRate;

thisAI.GetConsumptionRates(new Randomizer((int)buildingID), workers, out electricityConsumption, out waterConsumption, out sewageAccumulation, out garbageAccumulation, out incomeAccumulation);

if (garbageAccumulation != 0 && (policies & DistrictPolicies.Services.Recycling) != DistrictPolicies.Services.None)
{
garbageAccumulation = Mathf.Max(1, garbageAccumulation * 85 / 100);
incomeAccumulation = incomeAccumulation * 95 / 100;
}
int taxRate;

switch (thisAI.m_info.m_class.m_subService)
{
case ItemClass.SubService.CommercialLeisure:
taxRate = (buildingData.m_flags & Building.Flags.HighDensity) == Building.Flags.None ? Singleton<EconomyManager>.instance.GetTaxRate(ItemClass.Service.Commercial, ItemClass.SubService.CommercialLow, thisAI.m_info.m_class.m_level, taxationPolicies) : Singleton<EconomyManager>.instance.GetTaxRate(ItemClass.Service.Commercial, ItemClass.SubService.CommercialHigh, thisAI.m_info.m_class.m_level, taxationPolicies);
if ((taxationPolicies & DistrictPolicies.Taxation.DontTaxLeisure) != DistrictPolicies.Taxation.None)
taxRate = 0;

if ((cityPlanningPolicies & DistrictPolicies.CityPlanning.NoLoudNoises) != DistrictPolicies.CityPlanning.None && Singleton<SimulationManager>.instance.m_isNightTime)
{
electricityConsumption = electricityConsumption + 1 >> 1;
Expand All @@ -105,13 +103,16 @@ public static void SimulationStepActive(CommercialBuildingAI thisAI, ushort buil
break;
}
break;

case ItemClass.SubService.CommercialTourist:
taxRate = (buildingData.m_flags & Building.Flags.HighDensity) == Building.Flags.None ? Singleton<EconomyManager>.instance.GetTaxRate(ItemClass.Service.Commercial, ItemClass.SubService.CommercialLow, thisAI.m_info.m_class.m_level, taxationPolicies) : Singleton<EconomyManager>.instance.GetTaxRate(ItemClass.Service.Commercial, ItemClass.SubService.CommercialHigh, thisAI.m_info.m_class.m_level, taxationPolicies);
break;

default:
taxRate = Singleton<EconomyManager>.instance.GetTaxRate(thisAI.m_info.m_class, taxationPolicies);
break;
}

if (workers != 0)
{
int num5 = HandleCommonConsumption(thisAI, buildingID, ref buildingData, ref electricityConsumption, ref waterConsumption, ref sewageAccumulation, ref garbageAccumulation, policies);
Expand Down Expand Up @@ -272,9 +273,11 @@ public static void SimulationStepActive(CommercialBuildingAI thisAI, ushort buil

Notification.Problem problems1 = Notification.RemoveProblems(buildingData.m_problems, Notification.Problem.NoCustomers | Notification.Problem.NoGoods);

if ((int)buildingData.m_customBuffer2 > num4 - (a1 >> 1) && aliveCount <= visitCount >> 1)
//Start of modification

if ((int)buildingData.m_customBuffer2 > num4 - (multipliedVisitCount >> 1) && aliveCount <= visitCount >> 1)
{
if (_simulationManager.m_currentDayTimeHour > 17 && _simulationManager.m_currentDayTimeHour < 20)
if (_simulationManager.m_currentDayTimeHour > 18 && _simulationManager.m_currentDayTimeHour < 20)
{
buildingData.m_outgoingProblemTimer = (byte)Mathf.Min(byte.MaxValue, buildingData.m_outgoingProblemTimer + 1);

Expand All @@ -287,9 +290,16 @@ public static void SimulationStepActive(CommercialBuildingAI thisAI, ushort buil
problems1 = Notification.AddProblems(problems1, Notification.Problem.NoCustomers);
}
}
else if(buildingData.m_outgoingProblemTimer > 0)
{
--buildingData.m_outgoingProblemTimer;
}
}
else
buildingData.m_outgoingProblemTimer = (byte)0;

//End of modification

if ((int)buildingData.m_customBuffer1 == 0)
{
buildingData.m_incomingProblemTimer = (byte)Mathf.Min((int)byte.MaxValue, (int)buildingData.m_incomingProblemTimer + 1);
Expand All @@ -298,7 +308,7 @@ public static void SimulationStepActive(CommercialBuildingAI thisAI, ushort buil
else
buildingData.m_incomingProblemTimer = (byte)0;
buildingData.m_problems = problems1;
instance1.m_districts.m_buffer[(int)district].AddCommercialData(ref behaviour, health, happiness, crimeRate, workPlaceCount, aliveWorkerCount, Mathf.Max(0, workPlaceCount - totalWorkerCount), visitCount, aliveCount, num3, (int)thisAI.m_info.m_class.m_level, electricityConsumption, waterConsumption, sewageAccumulation, garbageAccumulation, incomeAccumulation, Mathf.Min(100, (int)buildingData.m_garbageBuffer / 50), (int)buildingData.m_waterPollution * 100 / (int)byte.MaxValue, (int)buildingData.m_finalImport, (int)buildingData.m_finalExport, thisAI.m_info.m_class.m_subService);
_district.AddCommercialData(ref behaviour, health, happiness, crimeRate, workPlaceCount, aliveWorkerCount, Mathf.Max(0, workPlaceCount - totalWorkerCount), visitCount, aliveCount, remainingCount, (int)thisAI.m_info.m_class.m_level, electricityConsumption, waterConsumption, sewageAccumulation, garbageAccumulation, incomeAccumulation, Mathf.Min(100, (int)buildingData.m_garbageBuffer / 50), (int)buildingData.m_waterPollution * 100 / (int)byte.MaxValue, (int)buildingData.m_finalImport, (int)buildingData.m_finalExport, thisAI.m_info.m_class.m_subService);
if ((int)buildingData.m_fireIntensity == 0 && incomingTransferReason != TransferManager.TransferReason.None)
{
int num5 = num4 - (int)buildingData.m_customBuffer1 - capacity - (maxIncomingLoadSize >> 1);
Expand All @@ -315,13 +325,13 @@ public static void SimulationStepActive(CommercialBuildingAI thisAI, ushort buil
if ((int)buildingData.m_fireIntensity == 0 && outgoingTransferReason != TransferManager.TransferReason.None)
{
int num5 = (int)buildingData.m_customBuffer2 - aliveCount * 100;
if (num5 >= 100 && num3 > 0)
if (num5 >= 100 && remainingCount > 0)
Singleton<TransferManager>.instance.AddOutgoingOffer(outgoingTransferReason, new TransferManager.TransferOffer()
{
Priority = Mathf.Max(1, num5 * 8 / num4),
Building = buildingID,
Position = buildingData.m_position,
Amount = Mathf.Min(num5 / 100, num3),
Amount = Mathf.Min(num5 / 100, remainingCount),
Active = false
});
}
Expand Down
4 changes: 4 additions & 0 deletions RushHour/BuildingHandlers/NewPrivateBuildingAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public static int HandleWorkers(PrivateBuildingAI thisAI, ushort buildingID, ref
int num1 = (level3 * 300 + level2 * 200 + level1 * 100) / (workPlaceCount + 1);
int num2 = (behaviour.m_educated3Count * 300 + behaviour.m_educated2Count * 200 + behaviour.m_educated1Count * 100) / (aliveWorkerCount + 1);

//Start of modification

if (Chances.WorkHour())
{
if (aliveWorkerCount < workPlaceCount >> 1)
Expand All @@ -57,6 +59,8 @@ public static int HandleWorkers(PrivateBuildingAI thisAI, ushort buildingID, ref
buildingData.m_workerProblemTimer = (byte)0;
}

//End of modification

buildingData.m_problems = problems1;
return Mathf.Max(1, b);
}
Expand Down
2 changes: 1 addition & 1 deletion RushHour/ResidentHandlers/NewResidentAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static void UpdateLocation(ResidentAI resident, uint citizenID, ref Citiz
{
CitizenManager _citizenManager = Singleton<CitizenManager>.instance;

if (data.m_homeBuilding == 00 && data.m_workBuilding == 0 && data.m_visitBuilding == 0 && data.m_instance == 0 && data.m_vehicle == 0)
if (data.m_homeBuilding == 0 && data.m_workBuilding == 0 && data.m_visitBuilding == 0 && data.m_instance == 0 && data.m_vehicle == 0)
{
_citizenManager.ReleaseCitizen(citizenID);
}
Expand Down
6 changes: 2 additions & 4 deletions RushHour/RushHour.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="CimTools, Version=0.1.5821.35742, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Libraries\CimTools.dll</HintPath>
</Reference>
<Reference Include="ColossalManaged">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed\ColossalManaged.dll</HintPath>
<Private>False</Private>
Expand All @@ -52,6 +48,7 @@
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed\ICities.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="UnityEngine">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed\UnityEngine.dll</HintPath>
<Private>False</Private>
Expand All @@ -63,6 +60,7 @@
<Compile Include="Experiments\ExperimentsToggle.cs" />
<Compile Include="LoadingExtension.cs" />
<Compile Include="Places\Chances.cs" />
<Compile Include="Places\CityEventManager.cs" />

This comment has been minimized.

Copy link
@bloodypenguin

bloodypenguin Jan 23, 2016

Collaborator

Please take a look at EventInfo, EventData, EventManager, EventCollection and EventProperties classes in game's decompiled code. It looks like CO already made a basic implementation of events a while ago but for some reason haven't released that feature yet. I think you better use (& mod of course) existing events framework. First, because if CO eventually brings events into the game your mod will be already ready for the feature. Second, it's always nice to reuse code instead of duplicating ;)

This comment has been minimized.

Copy link
@bloodypenguin

bloodypenguin Jan 23, 2016

Collaborator

BTW, CityEventManager.cs is missing from repo

This comment has been minimized.

Copy link
@PropaneDragon

PropaneDragon Jan 23, 2016

Author Owner

Ah yeah, I'll look into that and see what it can do. It'd be nice to use it unless CO decide to do something with it and change a lot of how it works.

Turns out I pushed the wrong bit of the project to the wrong branch. It's available in the experimental branch, so I guess I'll just cherry pick that out.

<Compile Include="Redirection\RedirectionHelper.cs" />
<Compile Include="Redirection\RedirectionUtil.cs" />
<Compile Include="Redirection\RedirectMethodAttribute.cs" />
Expand Down

0 comments on commit 22608ef

Please sign in to comment.