Skip to content

Commit

Permalink
Merge branch 'feature-infrastructure'
Browse files Browse the repository at this point in the history
  • Loading branch information
dymanoid committed Jun 30, 2018
2 parents 02fe8a5 + 875b9ef commit d458459
Show file tree
Hide file tree
Showing 19 changed files with 126 additions and 123 deletions.
6 changes: 3 additions & 3 deletions src/RealTime/Core/RealTimeCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,22 @@ public static RealTimeCore Run(RealTimeConfig config, string rootPath, Localizat

var timeInfo = new TimeInfo();
var buildingManager = new BuildingManagerConnection();
var simulationManager = new SimulationManagerConnection();
var randomizer = new GameRandomizer();

var gameConnections = new GameConnections<Citizen>(
timeInfo,
new CitizenConnection(),
new CitizenManagerConnection(),
buildingManager,
simulationManager,
randomizer,
new TransferManagerConnection());

var eventManager = new RealTimeEventManager(
config,
CityEventsLoader.Instance,
new EventManagerConnection(),
buildingManager,
simulationManager,
randomizer,
timeInfo);

SetupCustomAI(timeInfo, config, gameConnections, eventManager);
Expand Down
3 changes: 3 additions & 0 deletions src/RealTime/CustomAI/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ internal static class Constants
/// <summary>A minimum work shift duration in hours.</summary>
public const float MinimumWorkShiftDuration = 2f;

/// <summary>An earliest hour when citizens wake up at home.</summary>
public const float EarliestWakeUp = 5.5f;

/// <summary>An assumed average speed of a citizen when moving to target
/// (this is not just a walking speed, but also takes into account moving by car or public transport).</summary>
public const float OnTheWayDistancePerHour = 500f;
Expand Down
24 changes: 4 additions & 20 deletions src/RealTime/CustomAI/RealTimeHumanAIBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace RealTime.CustomAI
{
using System;
using ColossalFramework.Math;
using RealTime.Config;
using RealTime.Events;
using RealTime.GameConnection;
Expand All @@ -21,8 +20,6 @@ namespace RealTime.CustomAI
internal abstract class RealTimeHumanAIBase<TCitizen>
where TCitizen : struct
{
private Randomizer randomizer;

/// <summary>
/// Initializes a new instance of the <see cref="RealTimeHumanAIBase{TCitizen}"/> class.
/// </summary>
Expand All @@ -47,7 +44,7 @@ protected RealTimeHumanAIBase(RealTimeConfig config, GameConnections<TCitizen> c
TransferMgr = connections.TransferManager;
CitizenProxy = connections.CitizenConnection;
TimeInfo = connections.TimeInfo;
randomizer = connections.SimulationManager.GetRandomizer();
Random = connections.Random;
}

/// <summary>
Expand Down Expand Up @@ -98,20 +95,7 @@ protected RealTimeHumanAIBase(RealTimeConfig config, GameConnections<TCitizen> c
/// <summary>
/// Gets a reference to the game's randomizer.
/// </summary>
protected ref Randomizer Randomizer => ref randomizer;

/// <summary>
/// Determines whether a randomly generated value meets the specified probability.
/// </summary>
///
/// <param name="chance">The probability value to check. Valid values are 0..100</param>
/// <returns>
/// <c>true</c> if the randomly generated value meets the specified probability; otherwise, <c>false</c>.
/// </returns>
protected bool IsChance(uint chance)
{
return Randomizer.UInt32(100u) < chance;
}
protected IRandomizer Random { get; }

/// <summary>
/// Determines whether the current date and time represent the specified time interval on a work day.
Expand Down Expand Up @@ -373,7 +357,7 @@ protected bool IsCitizenVirtual<TAI>(TAI humanAI, ref TCitizen citizen, Func<TAI
return false;
}

return !IsChance(virtualChance);
return !Random.ShouldOccur(virtualChance);
}

private bool CanAttendEvent(uint citizenId, ref TCitizen citizen, ICityEvent cityEvent)
Expand All @@ -385,7 +369,7 @@ private bool CanAttendEvent(uint citizenId, ref TCitizen citizen, ICityEvent cit
Citizen.Wellbeing wellbeing = CitizenProxy.GetWellbeingLevel(ref citizen);
Citizen.Happiness happiness = CitizenProxy.GetHappinessLevel(ref citizen);

return cityEvent.TryAcceptAttendee(age, gender, education, wealth, wellbeing, happiness, ref randomizer);
return cityEvent.TryAcceptAttendee(age, gender, education, wealth, wellbeing, happiness, Random);
}
}
}
35 changes: 18 additions & 17 deletions src/RealTime/CustomAI/RealTimeResidentAI.Home.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace RealTime.CustomAI
{
using RealTime.Tools;
using static Constants;

internal sealed partial class RealTimeResidentAI<TAI, TCitizen>
{
Expand Down Expand Up @@ -44,42 +45,42 @@ private void ProcessCitizenAtHome(TAI instance, uint citizenId, ref TCitizen cit

private bool IsBusyAtHomeInTheMorning(Citizen.AgeGroup citizenAge)
{
float currentHour = TimeInfo.CurrentHour;
float offset = IsWeekend ? 2 : 0;
switch (citizenAge)
{
case Citizen.AgeGroup.Child:
return IsBusyAtHomeInTheMorning(8 + offset);
return IsBusyAtHomeInTheMorning(currentHour, 8 + offset);

case Citizen.AgeGroup.Teen:
case Citizen.AgeGroup.Young:
return IsBusyAtHomeInTheMorning(9 + offset);
return IsBusyAtHomeInTheMorning(currentHour, 9 + offset);

case Citizen.AgeGroup.Adult:
return IsBusyAtHomeInTheMorning(8 + (offset / 2f));
return IsBusyAtHomeInTheMorning(currentHour, 8 + (offset / 2f));

case Citizen.AgeGroup.Senior:
return IsBusyAtHomeInTheMorning(7);
return IsBusyAtHomeInTheMorning(currentHour, 7);

default:
return true;
}
}

bool IsBusyAtHomeInTheMorning(float latestHour)
private bool IsBusyAtHomeInTheMorning(float currentHour, float latestHour)
{
if (currentHour >= latestHour || currentHour < EarliestWakeUp)
{
float currentHour = TimeInfo.CurrentHour;
if (currentHour >= latestHour || currentHour < TimeInfo.SunriseHour)
{
return false;
}
return false;
}

float sunriseHour = TimeInfo.SunriseHour;
float dx = latestHour - sunriseHour;
float x = currentHour - sunriseHour;
float sunriseHour = EarliestWakeUp;
float dx = latestHour - sunriseHour;
float x = currentHour - sunriseHour;

// A cubic probability curve from sunrise (0%) to latestHour (100%)
uint chance = (uint)((100f / dx * x) - ((dx - x) * (dx - x) * x));
return !IsChance(chance);
}
// A cubic probability curve from the earliest wake up hour (0%) to latest hour (100%)
uint chance = (uint)((100f / dx * x) - ((dx - x) * (dx - x) * x));
return !Random.ShouldOccur(chance);
}
}
}
2 changes: 1 addition & 1 deletion src/RealTime/CustomAI/RealTimeResidentAI.Moving.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private void ProcessCitizenMoving(TAI instance, uint citizenId, ref TCitizen cit

if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.WaitingTransport | CitizenInstance.Flags.WaitingTaxi))
{
if (mayCancel && CitizenMgr.GetInstanceWaitCounter(instanceId) == 255 && IsChance(AbandonTransportWaitChance))
if (mayCancel && CitizenMgr.GetInstanceWaitCounter(instanceId) == 255 && Random.ShouldOccur(AbandonTransportWaitChance))
{
ushort home = CitizenProxy.GetHomeBuilding(ref citizen);
if (home == 0)
Expand Down
10 changes: 5 additions & 5 deletions src/RealTime/CustomAI/RealTimeResidentAI.SchoolWork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ private bool ShouldMoveToSchoolOrWork(uint citizenId, ushort workBuilding, ushor
return false;
}

float overtime = IsChance(Config.OnTimeQuota) ? 0 : Config.MaxOvertime * Randomizer.Int32(100u) / 200f;
float overtime = Random.ShouldOccur(Config.OnTimeQuota) ? 0 : Config.MaxOvertime * Random.GetRandomValue(100u) / 200f;

return ShouldMoveToSchoolOrWork(currentBuilding, workBuilding, workBeginHour, workEndHour, overtime);
}
Expand Down Expand Up @@ -300,7 +300,7 @@ private bool ShouldReturnFromSchoolOrWork(uint citizenId, ushort buildingId, Cit
}
else if (currentHour >= workEndHour)
{
return IsChance(Config.OnTimeQuota);
return Random.ShouldOccur(Config.OnTimeQuota);
}
}
else
Expand All @@ -311,7 +311,7 @@ private bool ShouldReturnFromSchoolOrWork(uint citizenId, ushort buildingId, Cit
}
else if (currentHour >= workEndHour && currentHour < earliestGotoHour)
{
return IsChance(Config.OnTimeQuota);
return Random.ShouldOccur(Config.OnTimeQuota);
}
}

Expand All @@ -336,7 +336,7 @@ private bool ShouldGoToLunch(Citizen.AgeGroup citizenAge)
float currentHour = TimeInfo.CurrentHour;
if (currentHour >= Config.LunchBegin && currentHour <= Config.LunchEnd)
{
return IsChance(Config.LunchQuota);
return Random.ShouldOccur(Config.LunchQuota);
}

return false;
Expand Down Expand Up @@ -391,7 +391,7 @@ private void GetWorkShiftTimes(uint citizenId, ItemClass.Service sevice, ItemCla

if (ShouldWorkAtDawn(sevice, subService))
{
begin = TimeInfo.SunriseHour;
begin = Mathf.Min(TimeInfo.SunriseHour, EarliestWakeUp);
}
else
{
Expand Down
14 changes: 7 additions & 7 deletions src/RealTime/CustomAI/RealTimeResidentAI.Visit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ private void ProcessCitizenVisit(TAI instance, ResidentState citizenState, uint
return;
}

if (IsChance(ReturnFromShoppingChance) || IsWorkDayMorning(CitizenProxy.GetAge(ref citizen)))
if (Random.ShouldOccur(ReturnFromShoppingChance) || IsWorkDayMorning(CitizenProxy.GetAge(ref citizen)))
{
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} returning from shopping at {currentBuilding} back home");
ReturnFromVisit(instance, citizenId, ref citizen, CitizenProxy.GetHomeBuilding(ref citizen), Citizen.Location.Home, isVirtual);
Expand Down Expand Up @@ -130,7 +130,7 @@ private bool CitizenReturnsHomeFromVisit(TAI instance, uint citizenId, ref TCiti
return true;
}

if (IsChance(ReturnFromVisitChance))
if (Random.ShouldOccur(ReturnFromVisitChance))
{
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} returning from visit back home");
ReturnFromVisit(instance, citizenId, ref citizen, homeBuilding, Citizen.Location.Home, isVirtual);
Expand Down Expand Up @@ -177,7 +177,7 @@ private bool CitizenGoesShopping(TAI instance, uint citizenId, ref TCitizen citi

if (TimeInfo.IsNightTime)
{
if (IsChance(GetGoOutChance(CitizenProxy.GetAge(ref citizen))))
if (Random.ShouldOccur(GetGoOutChance(CitizenProxy.GetAge(ref citizen))))
{
ushort localVisitPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance, isVirtual);
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna go shopping at night, trying local shop '{localVisitPlace}'");
Expand All @@ -187,12 +187,12 @@ private bool CitizenGoesShopping(TAI instance, uint citizenId, ref TCitizen citi
return false;
}

if (IsChance(GoShoppingChance))
if (Random.ShouldOccur(GoShoppingChance))
{
bool localOnly = CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDayMorning(CitizenProxy.GetAge(ref citizen));
ushort localVisitPlace = 0;

if (IsChance(Config.LocalBuildingSearchQuota))
if (Random.ShouldOccur(Config.LocalBuildingSearchQuota))
{
localVisitPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance, isVirtual);
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna go shopping, tries a local shop '{localVisitPlace}'");
Expand All @@ -218,7 +218,7 @@ private bool CitizenGoesShopping(TAI instance, uint citizenId, ref TCitizen citi

private bool CitizenGoesToEvent(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual)
{
if (!IsChance(GetGoOutChance(CitizenProxy.GetAge(ref citizen))))
if (!Random.ShouldOccur(GetGoOutChance(CitizenProxy.GetAge(ref citizen))))
{
return false;
}
Expand All @@ -235,7 +235,7 @@ private bool CitizenGoesToEvent(TAI instance, uint citizenId, ref TCitizen citiz
private bool CitizenGoesRelaxing(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual)
{
Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen);
if (!IsChance(GetGoOutChance(citizenAge)))
if (!Random.ShouldOccur(GetGoOutChance(citizenAge)))
{
return false;
}
Expand Down
10 changes: 5 additions & 5 deletions src/RealTime/CustomAI/RealTimeTouristAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ private void ProcessVisit(TAI instance, uint citizenId, ref TCitizen citizen, bo
return;
}

if (IsChance(TouristEventChance) && AttendUpcomingEvent(citizenId, ref citizen, out ushort eventBuilding))
if (Random.ShouldOccur(TouristEventChance) && AttendUpcomingEvent(citizenId, ref citizen, out ushort eventBuilding))
{
StartMovingToVisitBuilding(instance, citizenId, ref citizen, CitizenProxy.GetCurrentBuilding(ref citizen), eventBuilding, isVirtual);
Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen, isVirtual)} attending an event at {eventBuilding}");
Expand All @@ -151,7 +151,7 @@ private void ProcessVisit(TAI instance, uint citizenId, ref TCitizen citizen, bo
switch (EventMgr.GetEventState(visitBuilding, DateTime.MaxValue))
{
case CityEventState.Ongoing:
if (IsChance(TouristShoppingChance))
if (Random.ShouldOccur(TouristShoppingChance))
{
BuildingMgr.ModifyMaterialBuffer(visitBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
}
Expand Down Expand Up @@ -180,15 +180,15 @@ private void FindRandomVisitPlace(TAI instance, uint citizenId, ref TCitizen cit
return;
}

if (!IsChance(GetGoOutChance(CitizenProxy.GetAge(ref citizen))))
if (!Random.ShouldOccur(GetGoOutChance(CitizenProxy.GetAge(ref citizen))))
{
FindHotel(instance, citizenId, ref citizen, isVirtual);
return;
}

if (isVirtual)
{
if (IsChance(TouristShoppingChance) && BuildingMgr.GetBuildingService(currentBuilding) == ItemClass.Service.Commercial)
if (Random.ShouldOccur(TouristShoppingChance) && BuildingMgr.GetBuildingService(currentBuilding) == ItemClass.Service.Commercial)
{
BuildingMgr.ModifyMaterialBuffer(currentBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
}
Expand All @@ -215,7 +215,7 @@ private void FindRandomVisitPlace(TAI instance, uint citizenId, ref TCitizen cit
private void FindHotel(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual)
{
ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);
if (!IsChance(FindHotelChance))
if (!Random.ShouldOccur(FindHotelChance))
{
Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen, isVirtual)} didn't want to stay in a hotel, leaving the city");
touristAI.FindVisitPlace(instance, citizenId, currentBuilding, touristAI.GetLeavingReason(instance, citizenId, ref citizen));
Expand Down
12 changes: 6 additions & 6 deletions src/RealTime/Events/CityEventBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace RealTime.Events
{
using System;
using ColossalFramework.Math;
using RealTime.Simulation;

/// <summary>A base class for a city event.</summary>
/// <seealso cref="ICityEvent"/>
Expand Down Expand Up @@ -42,7 +42,7 @@ public virtual bool TryAcceptAttendee(
Citizen.Wealth wealth,
Citizen.Wellbeing wellbeing,
Citizen.Happiness happiness,
ref Randomizer randomizer)
IRandomizer randomizer)
{
return true;
}
Expand Down Expand Up @@ -70,18 +70,18 @@ public void Configure(ushort buildingId, string buildingName, DateTime startTime
/// <param name="wealth">The citizen's wealth.</param>
/// <param name="randomizer">A reference to the game's randomizer.</param>
/// <returns>The citizen's budget for attending an event.</returns>
protected static float GetCitizenBudgetForEvent(Citizen.Wealth wealth, ref Randomizer randomizer)
protected static float GetCitizenBudgetForEvent(Citizen.Wealth wealth, IRandomizer randomizer)
{
switch (wealth)
{
case Citizen.Wealth.Low:
return 30f + randomizer.Int32(60);
return 30f + randomizer.GetRandomValue(60);

case Citizen.Wealth.Medium:
return 80f + randomizer.Int32(80);
return 80f + randomizer.GetRandomValue(80);

case Citizen.Wealth.High:
return 120f + randomizer.Int32(320);
return 120f + randomizer.GetRandomValue(320);

default:
return 0;
Expand Down
4 changes: 2 additions & 2 deletions src/RealTime/Events/ICityEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace RealTime.Events
{
using System;
using ColossalFramework.Math;
using RealTime.Simulation;

/// <summary>An interface for a city event that is taking pace or being prepared.</summary>
internal interface ICityEvent
Expand Down Expand Up @@ -52,6 +52,6 @@ bool TryAcceptAttendee(
Citizen.Wealth wealth,
Citizen.Wellbeing wellbeing,
Citizen.Happiness happiness,
ref Randomizer randomizer);
IRandomizer randomizer);
}
}
Loading

0 comments on commit d458459

Please sign in to comment.