diff --git a/src/RealTime/CustomAI/IRealTimeBuildingAI.cs b/src/RealTime/CustomAI/IRealTimeBuildingAI.cs
new file mode 100644
index 0000000000000000000000000000000000000000..335a7f43a55e4e6d32f02ab9119b236dfb19600b
--- /dev/null
+++ b/src/RealTime/CustomAI/IRealTimeBuildingAI.cs
@@ -0,0 +1,25 @@
+//
+// Copyright (c) dymanoid. All rights reserved.
+//
+
+namespace RealTime.CustomAI
+{
+ ///
+ /// An interface for the custom logic for the private buildings.
+ ///
+ internal interface IRealTimeBuildingAI
+ {
+ ///
+ /// Determines whether the building with the specified is noise restricted
+ /// (has NIMBY policy that is active on current time).
+ ///
+ /// The building ID to check.
+ /// The ID of a building where the citizen starts their journey.
+ /// Specify 0 if there is no journey in schedule.
+ ///
+ /// true if the building with the specified has NIMBY policy
+ /// that is active on current time; otherwise, false.
+ ///
+ bool IsNoiseRestricted(ushort buildingId, ushort currentBuildingId = 0);
+ }
+}
\ No newline at end of file
diff --git a/src/RealTime/CustomAI/ISpareTimeBehavior.cs b/src/RealTime/CustomAI/ISpareTimeBehavior.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eea4872cc4acd0bd05dd26a447d9b17d9430d1a5
--- /dev/null
+++ b/src/RealTime/CustomAI/ISpareTimeBehavior.cs
@@ -0,0 +1,33 @@
+//
+// Copyright (c) dymanoid. All rights reserved.
+//
+
+namespace RealTime.CustomAI
+{
+ ///
+ /// An interface for custom logic for the spare time simulation.
+ ///
+ internal interface ISpareTimeBehavior
+ {
+ ///
+ /// Gets the probability whether a citizen with specified age would go relaxing on current time.
+ ///
+ ///
+ /// The age of the citizen to check.
+ /// The citizen's assigned work shift (default is ).
+ ///
+ /// A percentage value in range of 0..100 that describes the probability whether
+ /// a citizen with specified age would go relaxing on current time.
+ uint GetRelaxingChance(Citizen.AgeGroup citizenAge, WorkShift workShift = WorkShift.Unemployed);
+
+ ///
+ /// Gets the probability whether a citizen with specified age would go shopping on current time.
+ ///
+ ///
+ /// The age of the citizen to check.
+ ///
+ /// A percentage value in range of 0..100 that describes the probability whether
+ /// a citizen with specified age would go shopping on current time.
+ uint GetShoppingChance(Citizen.AgeGroup citizenAge);
+ }
+}
\ No newline at end of file
diff --git a/src/RealTime/CustomAI/ITravelBehavior.cs b/src/RealTime/CustomAI/ITravelBehavior.cs
new file mode 100644
index 0000000000000000000000000000000000000000..74f64e8c2350b79112bf85c63ae905a37315dd32
--- /dev/null
+++ b/src/RealTime/CustomAI/ITravelBehavior.cs
@@ -0,0 +1,18 @@
+//
+// Copyright (c) dymanoid. All rights reserved.
+//
+
+namespace RealTime.CustomAI
+{
+ ///
+ /// An interface for citizens traveling behavior.
+ ///
+ internal interface ITravelBehavior
+ {
+ /// Gets an estimated travel time (in hours) between two specified buildings.
+ /// The ID of the first building.
+ /// The ID of the second building.
+ /// An estimated travel time in hours.
+ float GetEstimatedTravelTime(ushort building1, ushort building2);
+ }
+}
\ No newline at end of file
diff --git a/src/RealTime/CustomAI/IWorkBehavior.cs b/src/RealTime/CustomAI/IWorkBehavior.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6150e5a4cf31b87004fd5d1275a4b88c0a1c8b8d
--- /dev/null
+++ b/src/RealTime/CustomAI/IWorkBehavior.cs
@@ -0,0 +1,54 @@
+//
+// Copyright (c) dymanoid. All rights reserved.
+//
+
+namespace RealTime.CustomAI
+{
+ ///
+ /// An interface for the citizens work behavior.
+ ///
+ internal interface IWorkBehavior
+ {
+ /// Notifies this object that a new game day starts.
+ void BeginNewDay();
+
+ ///
+ /// Determines whether a building of specified and
+ /// currently has working hours. Note that this method always returns true for residential buildings.
+ ///
+ /// The building service.
+ /// The building sub-service.
+ ///
+ /// true if a building of specified and
+ /// currently has working hours; otherwise, false.
+ ///
+ bool IsBuildingWorking(ItemClass.Service service, ItemClass.SubService subService);
+
+ /// Updates the citizen's work schedule by determining the time for going to work.
+ /// The citizen's schedule to update.
+ /// The ID of the building where the citizen is currently located.
+ /// The duration (in hours) of a full citizens simulation cycle.
+ /// true if work was scheduled; otherwise, false.
+ bool ScheduleGoToWork(ref CitizenSchedule schedule, ushort currentBuilding, float simulationCycle);
+
+ /// Updates the citizen's work schedule by determining the lunch time.
+ /// The citizen's schedule to update.
+ /// The citizen's age.
+ /// true if a lunch time was scheduled; otherwise, false.
+ bool ScheduleLunch(ref CitizenSchedule schedule, Citizen.AgeGroup citizenAge);
+
+ /// Updates the citizen's work schedule by determining the returning from lunch time.
+ /// The citizen's schedule to update.
+ void ScheduleReturnFromLunch(ref CitizenSchedule schedule);
+
+ /// Updates the citizen's work schedule by determining the time for returning from work.
+ /// The citizen's schedule to update.
+ /// The age of the citizen.
+ void ScheduleReturnFromWork(ref CitizenSchedule schedule, Citizen.AgeGroup citizenAge);
+
+ /// Updates the citizen's work shift parameters in the specified citizen's .
+ /// The citizen's schedule to update the work shift in.
+ /// The age of the citizen.
+ void UpdateWorkShift(ref CitizenSchedule schedule, Citizen.AgeGroup citizenAge);
+ }
+}
\ No newline at end of file
diff --git a/src/RealTime/CustomAI/RealTimeBuildingAI.cs b/src/RealTime/CustomAI/RealTimeBuildingAI.cs
index 295127ccf21c7e950671aa2e8572b06e0b9300e8..490f3fbacbaf2435cdfe7f4f787aef43d11c1592 100644
--- a/src/RealTime/CustomAI/RealTimeBuildingAI.cs
+++ b/src/RealTime/CustomAI/RealTimeBuildingAI.cs
@@ -13,7 +13,7 @@ namespace RealTime.CustomAI
///
/// A class that incorporates the custom logic for the private buildings.
///
- internal sealed class RealTimeBuildingAI
+ internal sealed class RealTimeBuildingAI : IRealTimeBuildingAI
{
private const int ConstructionSpeedPaused = 10880;
private const int ConstructionSpeedMinimum = 1088;
@@ -27,8 +27,8 @@ namespace RealTime.CustomAI
private readonly ITimeInfo timeInfo;
private readonly IBuildingManagerConnection buildingManager;
private readonly IToolManagerConnection toolManager;
- private readonly WorkBehavior workBehavior;
- private readonly TravelBehavior travelBehavior;
+ private readonly IWorkBehavior workBehavior;
+ private readonly ITravelBehavior travelBehavior;
private readonly bool[] lightStates;
@@ -58,8 +58,8 @@ namespace RealTime.CustomAI
ITimeInfo timeInfo,
IBuildingManagerConnection buildingManager,
IToolManagerConnection toolManager,
- WorkBehavior workBehavior,
- TravelBehavior travelBehavior)
+ IWorkBehavior workBehavior,
+ ITravelBehavior travelBehavior)
{
this.config = config ?? throw new ArgumentNullException(nameof(config));
this.timeInfo = timeInfo ?? throw new ArgumentNullException(nameof(timeInfo));
diff --git a/src/RealTime/CustomAI/RealTimeHumanAIBase.cs b/src/RealTime/CustomAI/RealTimeHumanAIBase.cs
index d7e4d872f5f50d79cf12c5133f1f9ede2d0b04ae..563e8eaccec473e2cb31425eb2aa7a1e5b22c3c6 100644
--- a/src/RealTime/CustomAI/RealTimeHumanAIBase.cs
+++ b/src/RealTime/CustomAI/RealTimeHumanAIBase.cs
@@ -28,8 +28,8 @@ namespace RealTime.CustomAI
///
/// A configuration to use with this custom logic.
/// An object providing the proxies that connect the method calls to the game methods.
- /// A reference an instance.
- protected RealTimeHumanAIBase(RealTimeConfig config, GameConnections connections, RealTimeEventManager eventManager)
+ /// A reference to an instance.
+ protected RealTimeHumanAIBase(RealTimeConfig config, GameConnections connections, IRealTimeEventManager eventManager)
{
Config = config ?? throw new ArgumentNullException(nameof(config));
EventMgr = eventManager ?? throw new ArgumentNullException(nameof(eventManager));
@@ -68,7 +68,7 @@ namespace RealTime.CustomAI
///
/// Gets a reference to the event manager.
///
- protected RealTimeEventManager EventMgr { get; }
+ protected IRealTimeEventManager EventMgr { get; }
///
/// Gets a reference to the proxy class that provides access to citizen's methods and fields.
diff --git a/src/RealTime/CustomAI/RealTimeResidentAI.cs b/src/RealTime/CustomAI/RealTimeResidentAI.cs
index 3f0ff0395b9c7ec8ab70895d85e6217ebf6cbb5a..f83167e8db760d06cdaa12c3af127ee42ab0f469 100644
--- a/src/RealTime/CustomAI/RealTimeResidentAI.cs
+++ b/src/RealTime/CustomAI/RealTimeResidentAI.cs
@@ -18,11 +18,13 @@ namespace RealTime.CustomAI
where TCitizen : struct
{
private readonly ResidentAIConnection residentAI;
- private readonly RealTimeBuildingAI buildingAI;
- private readonly WorkBehavior workBehavior;
- private readonly SpareTimeBehavior spareTimeBehavior;
- private readonly TravelBehavior travelBehavior;
+ private readonly IRealTimeBuildingAI buildingAI;
+ private readonly IWorkBehavior workBehavior;
+ private readonly ISpareTimeBehavior spareTimeBehavior;
+ private readonly ITravelBehavior travelBehavior;
+
private readonly CitizenSchedule[] residentSchedules;
+
private float simulationCycle;
/// Initializes a new instance of the class.
@@ -30,7 +32,7 @@ namespace RealTime.CustomAI
/// A instance containing the mod's configuration.
/// A instance that provides the game connection implementation.
/// A connection to the game's resident AI.
- /// A instance.
+ /// An instance.
/// The custom building AI.
/// A behavior that provides simulation info for the citizens work time.
/// A behavior that provides simulation info for the citizens spare time.
@@ -39,11 +41,11 @@ namespace RealTime.CustomAI
RealTimeConfig config,
GameConnections connections,
ResidentAIConnection residentAI,
- RealTimeEventManager eventManager,
- RealTimeBuildingAI buildingAI,
- WorkBehavior workBehavior,
- SpareTimeBehavior spareTimeBehavior,
- TravelBehavior travelBehavior)
+ IRealTimeEventManager eventManager,
+ IRealTimeBuildingAI buildingAI,
+ IWorkBehavior workBehavior,
+ ISpareTimeBehavior spareTimeBehavior,
+ ITravelBehavior travelBehavior)
: base(config, connections, eventManager)
{
this.residentAI = residentAI ?? throw new ArgumentNullException(nameof(residentAI));
@@ -135,7 +137,7 @@ namespace RealTime.CustomAI
/// Performs simulation for starting a new day for all citizens.
public void BeginNewDay()
{
- workBehavior.UpdateLunchTime();
+ workBehavior.BeginNewDay();
todayWakeup = TimeInfo.Now.Date.AddHours(Config.WakeUpHour);
}
diff --git a/src/RealTime/CustomAI/RealTimeTouristAI.cs b/src/RealTime/CustomAI/RealTimeTouristAI.cs
index a6e55af18ecb8fe9293925fceb315259201ec25c..fe3bfbc1c7978990cdaeabc4ac15e152ba6b2ac1 100644
--- a/src/RealTime/CustomAI/RealTimeTouristAI.cs
+++ b/src/RealTime/CustomAI/RealTimeTouristAI.cs
@@ -22,7 +22,7 @@ namespace RealTime.CustomAI
where TCitizen : struct
{
private readonly TouristAIConnection touristAI;
- private readonly SpareTimeBehavior spareTimeBehavior;
+ private readonly ISpareTimeBehavior spareTimeBehavior;
///
/// Initializes a new instance of the class.
@@ -39,8 +39,8 @@ namespace RealTime.CustomAI
RealTimeConfig config,
GameConnections connections,
TouristAIConnection touristAI,
- RealTimeEventManager eventManager,
- SpareTimeBehavior spareTimeBehavior)
+ IRealTimeEventManager eventManager,
+ ISpareTimeBehavior spareTimeBehavior)
: base(config, connections, eventManager)
{
this.touristAI = touristAI ?? throw new ArgumentNullException(nameof(touristAI));
diff --git a/src/RealTime/CustomAI/SpareTimeBehavior.cs b/src/RealTime/CustomAI/SpareTimeBehavior.cs
index 5367f12629ea3856d32f351fcc7db1412d917e12..af9b3eb9dd4dc3bc2b902262b6f835eb39bbcea3 100644
--- a/src/RealTime/CustomAI/SpareTimeBehavior.cs
+++ b/src/RealTime/CustomAI/SpareTimeBehavior.cs
@@ -13,7 +13,7 @@ namespace RealTime.CustomAI
///
/// A class that provides custom logic for the spare time simulation.
///
- internal sealed class SpareTimeBehavior
+ internal sealed class SpareTimeBehavior : ISpareTimeBehavior
{
private readonly RealTimeConfig config;
private readonly ITimeInfo timeInfo;
diff --git a/src/RealTime/CustomAI/TravelBehavior.cs b/src/RealTime/CustomAI/TravelBehavior.cs
index 4ca776ced564b0cb9221bde5847628262650069e..779f6e247055a1561969dde9a71556a5f13c074a 100644
--- a/src/RealTime/CustomAI/TravelBehavior.cs
+++ b/src/RealTime/CustomAI/TravelBehavior.cs
@@ -8,7 +8,10 @@ namespace RealTime.CustomAI
using RealTime.Tools;
using static Constants;
- internal sealed class TravelBehavior
+ ///
+ /// A behavior for citizens traveling.
+ ///
+ internal sealed class TravelBehavior : ITravelBehavior
{
private readonly IBuildingManagerConnection buildingManager;
diff --git a/src/RealTime/CustomAI/WorkBehavior.cs b/src/RealTime/CustomAI/WorkBehavior.cs
index 5779607bfb0b0aea3c65f7bbf15a660fd1f5f12a..ee28e3b18523b752ef2128b6d8805f393608c647 100644
--- a/src/RealTime/CustomAI/WorkBehavior.cs
+++ b/src/RealTime/CustomAI/WorkBehavior.cs
@@ -14,13 +14,13 @@ namespace RealTime.CustomAI
///
/// A class containing methods for managing the citizens' work behavior.
///
- internal sealed class WorkBehavior
+ internal sealed class WorkBehavior : IWorkBehavior
{
private readonly RealTimeConfig config;
private readonly IRandomizer randomizer;
private readonly IBuildingManagerConnection buildingManager;
private readonly ITimeInfo timeInfo;
- private readonly TravelBehavior travelBehavior;
+ private readonly ITravelBehavior travelBehavior;
private DateTime lunchBegin;
private DateTime lunchEnd;
@@ -37,7 +37,7 @@ namespace RealTime.CustomAI
IRandomizer randomizer,
IBuildingManagerConnection buildingManager,
ITimeInfo timeInfo,
- TravelBehavior travelBehavior)
+ ITravelBehavior travelBehavior)
{
this.config = config ?? throw new ArgumentNullException(nameof(config));
this.randomizer = randomizer ?? throw new ArgumentNullException(nameof(randomizer));
@@ -90,8 +90,8 @@ namespace RealTime.CustomAI
HasExtendedFirstWorkShift(service, subService));
}
- /// Updates the lunch time according to current date and configuration.
- public void UpdateLunchTime()
+ /// Notifies this object that a new game day starts.
+ public void BeginNewDay()
{
DateTime today = timeInfo.Now.Date;
lunchBegin = today.AddHours(config.LunchBegin);
diff --git a/src/RealTime/Events/IRealTimeEventManager.cs b/src/RealTime/Events/IRealTimeEventManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..21506a8c61ee90ed8ade1670f4e17896950d915b
--- /dev/null
+++ b/src/RealTime/Events/IRealTimeEventManager.cs
@@ -0,0 +1,36 @@
+//
+// Copyright (c) dymanoid. All rights reserved.
+//
+
+namespace RealTime.Events
+{
+ using System;
+
+ /// An interface for the customized city events manager.
+ internal interface IRealTimeEventManager
+ {
+ ///
+ /// Gets the instance of an ongoing or upcoming city event that takes place in a building
+ /// with specified ID.
+ ///
+ /// The ID of a building to search events for.
+ /// An instance of the first matching city event, or null if none found.
+ ICityEvent GetCityEvent(ushort buildingId);
+
+ ///
+ /// Gets the instance of an upcoming city event whose start time is between the specified values.
+ ///
+ /// The earliest city event start time to consider.
+ /// The latest city event start time to consider.
+ /// An instance of the first matching city event, or null if none found.
+ ICityEvent GetUpcomingCityEvent(DateTime earliestStartTime, DateTime latestStartTime);
+
+ /// Gets the state of a city event in the specified building.
+ /// The building ID to check events in.
+ /// The latest start time of events to consider.
+ ///
+ /// The state of an event that meets the specified criteria, or if none found.
+ ///
+ CityEventState GetEventState(ushort buildingId, DateTime latestStart);
+ }
+}
\ No newline at end of file
diff --git a/src/RealTime/Events/RealTimeEventManager.cs b/src/RealTime/Events/RealTimeEventManager.cs
index 525c8286a44da9995dfd378433f6ab5563b8e3ff..ea8008518b92bbe96b0443e4ffe92838773a9b6e 100644
--- a/src/RealTime/Events/RealTimeEventManager.cs
+++ b/src/RealTime/Events/RealTimeEventManager.cs
@@ -16,7 +16,7 @@ namespace RealTime.Events
/// The central class for the custom city events logic.
///
- internal sealed class RealTimeEventManager : IStorageData
+ internal sealed class RealTimeEventManager : IStorageData, IRealTimeEventManager
{
private const int MaximumEventsCount = 5;
private const string StorageDataId = "RealTimeEvents";
diff --git a/src/RealTime/RealTime.csproj b/src/RealTime/RealTime.csproj
index 27346c64f9ff082e9b844f0d608a6246ea9dfaf4..cb96a925bcf54b26fe2e23792ebedc3a0e43940d 100644
--- a/src/RealTime/RealTime.csproj
+++ b/src/RealTime/RealTime.csproj
@@ -60,6 +60,10 @@
+
+
+
+
@@ -77,6 +81,7 @@
+