Skip to content

Commit

Permalink
Merge branch 'feature-1.16'
Browse files Browse the repository at this point in the history
  • Loading branch information
dymanoid committed Aug 26, 2018
2 parents 461a395 + bfd897e commit 0f4988d
Show file tree
Hide file tree
Showing 22 changed files with 160 additions and 84 deletions.
7 changes: 7 additions & 0 deletions src/RealTime/Config/RealTimeConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,13 @@ public RealTimeConfig(bool latestVersion)
[ConfigItemCheckBox]
public bool ShowIncompatibilityNotifications { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the mod should use the English-US time and date formats, if the English language is selected.
/// </summary>
[ConfigItem("Tools", 1)]
[ConfigItemCheckBox]
public bool UseEnglishUSFormats { get; set; }

/// <summary>Checks the version of the deserialized object and migrates it to the latest version when necessary.</summary>
public void MigrateWhenNecessary()
{
Expand Down
35 changes: 19 additions & 16 deletions src/RealTime/Core/RealTimeCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace RealTime.Core
/// The core component of the Real Time mod. Activates and deactivates
/// the different parts of the mod's logic.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "This is the entry point and needs to instantiate all parts")]
internal sealed class RealTimeCore
{
private const string HarmonyId = "com.cities_skylines.dymanoid.realtime";
Expand Down Expand Up @@ -117,6 +118,8 @@ public static RealTimeCore Run(
LoadStorageData(new[] { configProvider }, StorageBase.CurrentLevelStorage);
}

localizationProvider.SetEnglishUSFormatsState(configProvider.Configuration.UseEnglishUSFormats);

var timeInfo = new TimeInfo(configProvider.Configuration);
var buildingManager = new BuildingManagerConnection();
var randomizer = new GameRandomizer();
Expand Down Expand Up @@ -224,6 +227,22 @@ public void Stop()
return;
}

ResidentAIPatch.RealTimeAI = null;
TouristAIPatch.RealTimeAI = null;
BuildingAIPatches.RealTimeAI = null;
BuildingAIPatches.WeatherInfo = null;
TransferManagerPatch.RealTimeAI = null;
SimulationHandler.EventManager = null;
SimulationHandler.DayTimeSimulation = null;
SimulationHandler.TimeAdjustment = null;
SimulationHandler.WeatherInfo = null;
SimulationHandler.Buildings = null;
SimulationHandler.CitizenProcessor = null;
SimulationHandler.Statistics?.Close();
SimulationHandler.Statistics = null;
ParkPatches.SpareTimeBehavior = null;
OutsideConnectionAIPatch.SpareTimeBehavior = null;

Log.Info($"The 'Real Time' mod reverts method patches.");
patcher.Revert();

Expand All @@ -241,22 +260,6 @@ public void Stop()

StorageBase.CurrentLevelStorage.GameSaving -= GameSaving;

ResidentAIPatch.RealTimeAI = null;
TouristAIPatch.RealTimeAI = null;
BuildingAIPatches.RealTimeAI = null;
BuildingAIPatches.WeatherInfo = null;
TransferManagerPatch.RealTimeAI = null;
SimulationHandler.EventManager = null;
SimulationHandler.DayTimeSimulation = null;
SimulationHandler.TimeAdjustment = null;
SimulationHandler.WeatherInfo = null;
SimulationHandler.Buildings = null;
SimulationHandler.CitizenProcessor = null;
SimulationHandler.Statistics?.Close();
SimulationHandler.Statistics = null;
ParkPatches.SpareTimeBehavior = null;
OutsideConnectionAIPatch.SpareTimeBehavior = null;

WorldInfoPanelPatches.CitizenInfoPanel?.Disable();
WorldInfoPanelPatches.CitizenInfoPanel = null;

Expand Down
1 change: 1 addition & 0 deletions src/RealTime/Core/RealTimeMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ private void ApplyLanguage()

if (localizationProvider.LoadTranslation(LocaleManager.instance.language))
{
localizationProvider.SetEnglishUSFormatsState(configProvider.Configuration.UseEnglishUSFormats);
core?.Translate(localizationProvider);
}

Expand Down
79 changes: 45 additions & 34 deletions src/RealTime/CustomAI/RealTimeResidentAI.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,12 @@ private bool ProcessCitizenSick(TAI instance, uint citizenId, ref TCitizen citiz

if (currentLocation == Citizen.Location.Visit)
{
ItemClass.Service service = BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen));
if (service == ItemClass.Service.HealthCare || service == ItemClass.Service.Disaster)
ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen);
switch (BuildingMgr.GetBuildingService(visitBuilding))
{
return true;
case ItemClass.Service.HealthCare:
case ItemClass.Service.Disaster when !BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading):
return true;
}
}

Expand All @@ -115,31 +117,34 @@ private bool ProcessCitizenSick(TAI instance, uint citizenId, ref TCitizen citiz

private void DoScheduledEvacuation(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
{
schedule.Schedule(ResidentState.Unknown);
ushort building = CitizenProxy.GetCurrentBuilding(ref citizen);
if (building == 0)
{
schedule.Schedule(ResidentState.AtHome);
return;
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is trying to find a shelter from current position");
TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0));
}

schedule.Schedule(ResidentState.InShelter);
if (schedule.CurrentState != ResidentState.InShelter)
else
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is trying to find an evacuation place");
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is trying to find a shelter from {building}");
residentAI.FindEvacuationPlace(instance, citizenId, building, residentAI.GetEvacuationReason(instance, building));
}
}

private bool ProcessCitizenInShelter(ref CitizenSchedule schedule, ref TCitizen citizen)
{
ushort shelter = CitizenProxy.GetVisitBuilding(ref citizen);
if (BuildingMgr.BuildingHasFlags(shelter, Building.Flags.Downgrading) && schedule.ScheduledState == ResidentState.InShelter)
if (BuildingMgr.BuildingHasFlags(shelter, Building.Flags.Downgrading))
{
CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating);
schedule.Schedule(ResidentState.Unknown);
return true;
}

if (schedule.ScheduledState != ResidentState.Unknown)
{
schedule.Schedule(ResidentState.Unknown);
}

return false;
}

Expand All @@ -165,11 +170,10 @@ private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSched
true))
{
// Guided tours are treated as visits
schedule.CurrentState = ResidentState.Visiting;
schedule.Hint = ScheduleHint.OnTour;
return ScheduleAction.ProcessState;
}

schedule.CurrentState = ResidentState.InTransition;
return ScheduleAction.ProcessTransition;
}

Expand All @@ -180,35 +184,44 @@ private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSched
return ScheduleAction.ProcessState;
}

ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding);
if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating)
&& buildingService != ItemClass.Service.Disaster)
if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating))
{
schedule.CurrentState = ResidentState.Evacuation;
schedule.Schedule(ResidentState.InShelter);
return ScheduleAction.ProcessState;
}

ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding);
switch (location)
{
case Citizen.Location.Home:
schedule.CurrentState = ResidentState.AtHome;
return ScheduleAction.ProcessState;

case Citizen.Location.Work:
if (buildingService == ItemClass.Service.Disaster && CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
{
schedule.CurrentState = ResidentState.InShelter;
return ScheduleAction.ProcessState;
}

if (CitizenProxy.GetVisitBuilding(ref citizen) == currentBuilding && schedule.WorkStatus != WorkStatus.Working)
{
// A citizen may visit their own work building (e.g. shopping),
// but the game sets the location to 'work' even if the citizen visits the building.
goto case Citizen.Location.Visit;
}

switch (buildingService)
{
case ItemClass.Service.Electricity:
case ItemClass.Service.Water:
case ItemClass.Service.HealthCare:
case ItemClass.Service.PoliceDepartment:
case ItemClass.Service.FireDepartment:
case ItemClass.Service.Disaster:
if (BuildingMgr.IsAreaEvacuating(currentBuilding))
{
schedule.CurrentState = ResidentState.InShelter;
return ScheduleAction.ProcessState;
}

break;
}

schedule.CurrentState = ResidentState.AtSchoolOrWork;
return ScheduleAction.ProcessState;

Expand All @@ -229,7 +242,7 @@ when BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.
schedule.CurrentState = ResidentState.Shopping;
return ScheduleAction.ProcessState;

case ItemClass.Service.Disaster when CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating):
case ItemClass.Service.Disaster:
schedule.CurrentState = ResidentState.InShelter;
return ScheduleAction.ProcessState;
}
Expand Down Expand Up @@ -356,7 +369,9 @@ private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance,
return;
}

if (schedule.CurrentState == ResidentState.AtHome && IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen))
if (schedule.CurrentState == ResidentState.AtHome
&& schedule.ScheduledState != ResidentState.InShelter
&& IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen))
{
Log.Debug(LogCategory.Simulation, $" *** Citizen {citizenId} is virtual this time");
schedule.Schedule(ResidentState.Unknown);
Expand All @@ -368,18 +383,15 @@ private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance,
{
case ResidentState.AtHome:
DoScheduledHome(ref schedule, instance, citizenId, ref citizen);
executed = true;
break;
return;

case ResidentState.AtSchoolOrWork:
DoScheduledWork(ref schedule, instance, citizenId, ref citizen);
executed = true;
break;
return;

case ResidentState.Shopping when schedule.WorkStatus == WorkStatus.Working:
DoScheduledLunch(ref schedule, instance, citizenId, ref citizen);
executed = true;
break;
return;

case ResidentState.Shopping:
executed = DoScheduledShopping(ref schedule, instance, citizenId, ref citizen);
Expand All @@ -389,10 +401,9 @@ private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance,
executed = DoScheduledRelaxing(ref schedule, instance, citizenId, ref citizen);
break;

case ResidentState.InShelter:
case ResidentState.InShelter when schedule.CurrentState != ResidentState.InShelter:
DoScheduledEvacuation(ref schedule, instance, citizenId, ref citizen);
executed = true;
break;
return;

default:
return;
Expand Down
24 changes: 17 additions & 7 deletions src/RealTime/CustomAI/RealTimeResidentAI.Moving.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace RealTime.CustomAI

internal sealed partial class RealTimeResidentAI<TAI, TCitizen>
{
private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
private bool ProcessCitizenMoving(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
{
ushort instanceId = CitizenProxy.GetInstance(ref citizen);
ushort vehicleId = CitizenProxy.GetVehicle(ref citizen);
Expand Down Expand Up @@ -39,15 +39,27 @@ private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, ui
return true;
}

if (vehicleId == 0 && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating) && CitizenMgr.IsAreaEvacuating(instanceId))
bool isEvacuating = CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating);
if (vehicleId == 0 && !isEvacuating && CitizenMgr.IsAreaEvacuating(instanceId))
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Finding an evacuation place.");
schedule.Schedule(ResidentState.Unknown);
schedule.DepartureTime = default;
TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0));
schedule.CurrentState = ResidentState.Evacuation;
return false;
}

if (isEvacuating)
{
return true;
}

if (schedule.Hint == ScheduleHint.OnTour)
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} quits a tour");
schedule.Schedule(ResidentState.Unknown);
schedule.Hint = ScheduleHint.None;
return false;
}

ushort targetBuilding = CitizenMgr.GetTargetBuilding(instanceId);
bool headingToWork = targetBuilding == CitizenProxy.GetWorkBuilding(ref citizen);
if (vehicleId != 0 && schedule.DepartureTime != default)
Expand All @@ -67,7 +79,6 @@ private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, ui
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} cancels the trip because of traffic jam");
schedule.Schedule(ResidentState.Relaxing);
schedule.Hint = ScheduleHint.RelaxNearbyOnly;
schedule.CurrentState = ResidentState.InTransition;
return false;
}
}
Expand All @@ -82,7 +93,6 @@ private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, ui
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} cancels the trip to a park due to bad weather");
schedule.Schedule(ResidentState.AtHome);
schedule.CurrentState = ResidentState.InTransition;
return false;
}

Expand Down
7 changes: 0 additions & 7 deletions src/RealTime/CustomAI/RealTimeResidentAI.Visit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,6 @@ private bool ProcessCitizenShopping(ref CitizenSchedule schedule, uint citizenId

private bool ProcessCitizenVisit(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
{
if (schedule.Hint == ScheduleHint.OnTour)
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} quits a tour");
schedule.Schedule(ResidentState.Unknown);
return true;
}

return RescheduleVisit(ref schedule, citizenId, ref citizen, CitizenProxy.GetVisitBuilding(ref citizen));
}

Expand Down
18 changes: 12 additions & 6 deletions src/RealTime/CustomAI/RealTimeResidentAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,29 @@ public void UpdateLocation(TAI instance, uint citizenId, ref TCitizen citizen)
case ScheduleAction.Ignore:
return;

case ScheduleAction.ProcessTransition when ProcessCitizenMoving(ref schedule, instance, citizenId, ref citizen):
case ScheduleAction.ProcessTransition when ProcessCitizenMoving(ref schedule, citizenId, ref citizen):
return;
}

if (schedule.CurrentState == ResidentState.Unknown)
switch (schedule.CurrentState)
{
Log.Debug(LogCategory.State, TimeInfo.Now, $"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is in an UNKNOWN state! Changing to 'moving'");
CitizenProxy.SetLocation(ref citizen, Citizen.Location.Moving);
return;
case ResidentState.Unknown:
Log.Debug(LogCategory.State, TimeInfo.Now, $"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is in an UNKNOWN state! Changing to 'moving'");
CitizenProxy.SetLocation(ref citizen, Citizen.Location.Moving);
return;

case ResidentState.Evacuation:
schedule.Schedule(ResidentState.InShelter);
break;
}

if (TimeInfo.Now < schedule.ScheduledStateTime)
{
return;
}

bool updated = UpdateCitizenSchedule(ref schedule, citizenId, ref citizen);
Log.Debug(LogCategory.State, TimeInfo.Now, $"Citizen {citizenId} is in state {schedule.CurrentState}");
bool updated = schedule.CurrentState != ResidentState.InShelter && UpdateCitizenSchedule(ref schedule, citizenId, ref citizen);
ExecuteCitizenSchedule(ref schedule, instance, citizenId, ref citizen, updated);
}

Expand Down
10 changes: 8 additions & 2 deletions src/RealTime/CustomAI/RealTimeTouristAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,16 @@ private void ProcessMoving(TAI instance, uint citizenId, ref TCitizen citizen)
return;
}

if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
bool isEvacuating = CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating);
if (vehicleId == 0 && !isEvacuating && CitizenMgr.IsAreaEvacuating(instanceId))
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Searching for a shelter.");
touristAI.FindVisitPlace(instance, citizenId, CitizenProxy.GetCurrentBuilding(ref citizen), touristAI.GetEvacuationReason(instance, 0));
TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, touristAI.GetEvacuationReason(instance, 0));
return;
}

if (isEvacuating)
{
return;
}

Expand Down
Loading

0 comments on commit 0f4988d

Please sign in to comment.