Skip to content

Commit

Permalink
Merge branch 'feature-targeting'
Browse files Browse the repository at this point in the history
  • Loading branch information
dymanoid committed Jul 28, 2018
2 parents ac37fe7 + 8d68ebd commit 1c132a9
Show file tree
Hide file tree
Showing 27 changed files with 268 additions and 152 deletions.
5 changes: 4 additions & 1 deletion src/RealTime/CustomAI/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ internal static class Constants
public const float FullSearchDistance = BuildingManager.BUILDINGGRID_RESOLUTION * BuildingManager.BUILDINGGRID_CELL_SIZE / 2f;

/// <summary>A chance in percent for a citizen to stay home until next scheduled action.</summary>
public const uint StayHomeAllDayChance = 15;
public const uint StayHomeAllDayChance = 2;

/// <summary>A chance in percent for a citizen to go shopping in the night.</summary>
public const uint NightShoppingChance = 20u;

/// <summary>A chance in percent for a citizen to go shopping just for fun.</summary>
public const uint FunShoppingChance = 35u;

/// <summary>A chance in percent for a tourist to find a hotel for sleepover.</summary>
public const uint FindHotelChance = 80;

Expand Down
14 changes: 5 additions & 9 deletions src/RealTime/CustomAI/RealTimeBuildingAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,16 @@ public int GetConstructionTime()
/// Performs the custom processing of the outgoing problem timer.
/// </summary>
/// <param name="buildingId">The ID of the building to process.</param>
/// <param name="oldValue">The old value of the outgoing problem timer.</param>
/// <param name="newValue">The new value of the outgoing problem timer.</param>
public void ProcessOutgoingProblems(ushort buildingId, byte oldValue, byte newValue)
/// <param name="outgoingProblemTimer">The previous value of the outgoing problem timer.</param>
public void ProcessBuildingProblems(ushort buildingId, byte outgoingProblemTimer)
{
// We have only few customers at night - that's an intended behavior.
// To avoid commercial buildings from collapsing due to lack of customers,
// we force the problem timer to pause at night time.
// In the daytime, the timer is running slower.
if (timeInfo.IsNightTime || timeInfo.Now.Minute % ProblemTimersInterval != 0 || freezeProblemTimers)
{
buildingManager.SetOutgoingProblemTimer(buildingId, oldValue);
buildingManager.SetOutgoingProblemTimer(buildingId, outgoingProblemTimer);
}
}

Expand All @@ -113,8 +112,7 @@ public void ProcessOutgoingProblems(ushort buildingId, byte oldValue, byte newVa
/// </summary>
/// <param name="buildingId">The ID of the building to process.</param>
/// <param name="oldValue">The old value of the worker problem timer.</param>
/// <param name="newValue">The new value of the worker problem timer.</param>
public void ProcessWorkerProblems(ushort buildingId, byte oldValue, byte newValue)
public void ProcessWorkerProblems(ushort buildingId, byte oldValue)
{
// We force the problem timer to pause at night time.
// In the daytime, the timer is running slower.
Expand Down Expand Up @@ -176,9 +174,7 @@ public void ProcessFrame(uint frameIndex)
/// </returns>
public bool ShouldSwitchBuildingLightsOff(ushort buildingId)
{
return config.SwitchOffLightsAtNight
? !lightStates[buildingId]
: false;
return config.SwitchOffLightsAtNight && !lightStates[buildingId];
}

private void UpdateLightState(uint frameIndex)
Expand Down
49 changes: 34 additions & 15 deletions src/RealTime/CustomAI/RealTimeResidentAI.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ when BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.
return ScheduleAction.Ignore;
}

private void UpdateCitizenSchedule(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
private bool UpdateCitizenSchedule(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
{
// If the game changed the work building, we have to update the work shifts first
ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen);
Expand All @@ -264,7 +264,7 @@ private void UpdateCitizenSchedule(ref CitizenSchedule schedule, uint citizenId,

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

Log.Debug(TimeInfo.Now, $"Scheduling for {GetCitizenDesc(citizenId, ref citizen)}...");
Expand All @@ -279,7 +279,7 @@ private void UpdateCitizenSchedule(ref CitizenSchedule schedule, uint citizenId,
{
if (ScheduleWork(ref schedule, ref citizen))
{
return;
return true;
}

if (schedule.ScheduledStateTime > nextActivityTime)
Expand All @@ -291,37 +291,56 @@ private void UpdateCitizenSchedule(ref CitizenSchedule schedule, uint citizenId,
if (ScheduleShopping(ref schedule, ref citizen, false))
{
Log.Debug($" - Schedule shopping");
return;
return true;
}

if (ScheduleRelaxing(ref schedule, citizenId, ref citizen))
{
Log.Debug($" - Schedule relaxing");
return;
return true;
}

if (schedule.CurrentState == ResidentState.AtHome)
{
if (Random.ShouldOccur(StayHomeAllDayChance))
{
nextActivityTime = todayWakeup.FutureHour(Config.WakeupHour);
if (nextActivityTime < TimeInfo.Now)
{
nextActivityTime = todayWakeup.FutureHour(Config.WakeupHour);
}
}
else
{
nextActivityTime = default;
}

Log.Debug($" - Schedule sleeping at home until {nextActivityTime}");
#if DEBUG
if (nextActivityTime <= TimeInfo.Now)
{
Log.Debug($" - Schedule idle until next scheduling run");
}
else
{
Log.Debug($" - Schedule idle until {nextActivityTime}");
}
#endif
schedule.Schedule(ResidentState.Unknown, nextActivityTime);
}
else
{
Log.Debug($" - Schedule moving home");
schedule.Schedule(ResidentState.AtHome, default);
}

return true;
}

private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen, bool noReschedule)
{
if (ProcessCurrentState(ref schedule, ref citizen) && schedule.ScheduledState == ResidentState.Unknown)
if (ProcessCurrentState(ref schedule, citizenId, ref citizen)
&& schedule.ScheduledState == ResidentState.Unknown && !noReschedule)
{
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} will be re-scheduled now");
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} will re-schedule now");

// If the state processing changed the schedule, we need to update it
UpdateCitizenSchedule(ref schedule, citizenId, ref citizen);
Expand Down Expand Up @@ -367,21 +386,21 @@ private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance,
}
}

private bool ProcessCurrentState(ref CitizenSchedule schedule, ref TCitizen citizen)
private bool ProcessCurrentState(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
{
switch (schedule.CurrentState)
{
case ResidentState.AtHome:
return RescheduleAtHome(ref schedule, ref citizen);
return RescheduleAtHome(ref schedule, citizenId, ref citizen);

case ResidentState.Shopping:
return ProcessCitizenShopping(ref schedule, ref citizen);
return ProcessCitizenShopping(ref schedule, citizenId, ref citizen);

case ResidentState.Relaxing:
return ProcessCitizenRelaxing(ref schedule, ref citizen);
return ProcessCitizenRelaxing(ref schedule, citizenId, ref citizen);

case ResidentState.Visiting:
return ProcessCitizenVisit(ref schedule, ref citizen);
return ProcessCitizenVisit(ref schedule, citizenId, ref citizen);

case ResidentState.InShelter:
return ProcessCitizenInShelter(ref schedule, ref citizen);
Expand Down
33 changes: 20 additions & 13 deletions src/RealTime/CustomAI/RealTimeResidentAI.Home.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,20 @@ private void DoScheduledHome(ref CitizenSchedule schedule, TAI instance, uint ci

ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);
CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating);
CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, homeBuilding);
schedule.Schedule(ResidentState.Unknown, default);
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} back home");

if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, homeBuilding))
{
CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
schedule.Schedule(ResidentState.Unknown, default);
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} back home");
}
else
{
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted to go home from {currentBuilding} but can't, waiting for the next opportunity");
}
}

private bool RescheduleAtHome(ref CitizenSchedule schedule, ref TCitizen citizen)
private bool RescheduleAtHome(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
{
if (schedule.CurrentState != ResidentState.AtHome || TimeInfo.Now < schedule.ScheduledStateTime)
{
Expand All @@ -39,24 +46,24 @@ private bool RescheduleAtHome(ref CitizenSchedule schedule, ref TCitizen citizen
return false;
}

if (IsBadWeather())
if (schedule.ScheduledState != ResidentState.Shopping && IsBadWeather())
{
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(0, ref citizen)} re-schedules an activity because of bad weather (see next line for citizen ID)");
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} re-schedules an activity because of bad weather");
schedule.Schedule(ResidentState.Unknown, default);
return true;
}

uint goOutChance = spareTimeBehavior.GetGoOutChance(
CitizenProxy.GetAge(ref citizen),
schedule.WorkShift,
schedule.ScheduledState == ResidentState.Shopping);
var age = CitizenProxy.GetAge(ref citizen);
uint goOutChance = schedule.ScheduledState == ResidentState.Shopping
? spareTimeBehavior.GetShoppingChance(age)
: spareTimeBehavior.GetRelaxingChance(age, schedule.WorkShift);

if (Random.ShouldOccur(goOutChance))
if (goOutChance > 0)
{
return false;
}

Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(0, ref citizen)} re-schedules an activity because of time (see next line for citizen ID)");
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} re-schedules an activity because of time");
schedule.Schedule(ResidentState.Unknown, default);
return true;
}
Expand Down
8 changes: 6 additions & 2 deletions src/RealTime/CustomAI/RealTimeResidentAI.Moving.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ private ushort MoveToCommercialBuilding(TAI instance, uint citizenId, ref TCitiz
}

ushort foundBuilding = BuildingMgr.FindActiveBuilding(currentBuilding, distance, ItemClass.Service.Commercial);
if (foundBuilding == 0)
{
Log.Debug($"Citizen {citizenId} didn't find any visitable commercial buildings nearby");
return 0;
}

if (IsBuildingNoiseRestricted(foundBuilding, currentBuilding))
{
Log.Debug($"Citizen {citizenId} won't go to the commercial building {foundBuilding}, it has a NIMBY policy");
Expand Down Expand Up @@ -120,14 +126,12 @@ private bool StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitiz
if (currentBuilding == visitBuilding)
{
CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding);
CitizenProxy.SetVisitBuilding(ref citizen, visitBuilding);
CitizenProxy.SetLocation(ref citizen, Citizen.Location.Visit);
return true;
}
else if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, visitBuilding))
{
CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding);
CitizenProxy.SetVisitBuilding(ref citizen, visitBuilding);
return true;
}

Expand Down
37 changes: 23 additions & 14 deletions src/RealTime/CustomAI/RealTimeResidentAI.SchoolWork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,27 @@ private bool ScheduleWork(ref CitizenSchedule schedule, ref TCitizen citizen)
if (timeLeft <= PrepareToWorkHours)
{
// Just sit at home if the work time will come soon
Log.Debug($" - Worktime in {timeLeft} hours, preparing for departure");
Log.Debug($" - Work time in {timeLeft} hours, preparing for departure");
return true;
}

if (timeLeft <= MaxTravelTime)
{
if (schedule.CurrentState != ResidentState.AtHome)
{
Log.Debug($" - Worktime in {timeLeft} hours, returning home");
Log.Debug($" - Work time in {timeLeft} hours, returning home");
schedule.Schedule(ResidentState.AtHome, default);
return true;
}

// If we have some time, try to shop locally.
if (ScheduleShopping(ref schedule, ref citizen, true))
{
Log.Debug($" - Worktime in {timeLeft} hours, trying local shop");
Log.Debug($" - Work time in {timeLeft} hours, trying local shop");
}
else
{
Log.Debug($" - Worktime in {timeLeft} hours, doing nothing");
Log.Debug($" - Work time in {timeLeft} hours, doing nothing");
}

return true;
Expand All @@ -62,22 +62,31 @@ private void DoScheduledWork(ref CitizenSchedule schedule, TAI instance, uint ci
{
CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
CitizenProxy.SetLocation(ref citizen, Citizen.Location.Work);
}
else if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, schedule.WorkBuilding)
&& schedule.CurrentState == ResidentState.AtHome)
{
schedule.DepartureToWorkTime = TimeInfo.Now;
return;
}

Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen);
if (workBehavior.ScheduleLunch(ref schedule, citizenAge))
if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, schedule.WorkBuilding))
{
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will go to lunch at {schedule.ScheduledStateTime}");
if (schedule.CurrentState == ResidentState.AtHome)
{
schedule.DepartureToWorkTime = TimeInfo.Now;
}

Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen);
if (workBehavior.ScheduleLunch(ref schedule, citizenAge))
{
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will go to lunch at {schedule.ScheduledStateTime}");
}
else
{
workBehavior.ScheduleReturnFromWork(ref schedule, citizenAge);
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will leave work at {schedule.ScheduledStateTime}");
}
}
else
{
workBehavior.ScheduleReturnFromWork(ref schedule, citizenAge);
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will leave work at {schedule.ScheduledStateTime}");
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted to go to work from {currentBuilding} but can't, will try once again next time");
schedule.Schedule(ResidentState.Unknown, default);
}
}

Expand Down
Loading

0 comments on commit 1c132a9

Please sign in to comment.