Skip to content

Commit

Permalink
Merge branch 'feature-events'
Browse files Browse the repository at this point in the history
  • Loading branch information
dymanoid committed Aug 5, 2018
2 parents 1407aa0 + ddb442c commit 12c9aed
Show file tree
Hide file tree
Showing 23 changed files with 376 additions and 118 deletions.
15 changes: 13 additions & 2 deletions src/RealTime/Core/RealTimeCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,22 @@ internal sealed class RealTimeCore
private readonly CustomTimeBar timeBar;
private readonly RealTimeEventManager eventManager;
private readonly MethodPatcher patcher;
private readonly VanillaEvents vanillaEvents;

private bool isEnabled;

private RealTimeCore(TimeAdjustment timeAdjustment, CustomTimeBar timeBar, RealTimeEventManager eventManager, MethodPatcher patcher)
private RealTimeCore(
TimeAdjustment timeAdjustment,
CustomTimeBar timeBar,
RealTimeEventManager eventManager,
MethodPatcher patcher,
VanillaEvents vanillaEvents)
{
this.timeAdjustment = timeAdjustment;
this.timeBar = timeBar;
this.eventManager = eventManager;
this.patcher = patcher;
this.vanillaEvents = vanillaEvents;
isEnabled = true;
}

Expand Down Expand Up @@ -135,7 +142,9 @@ public static RealTimeCore Run(ConfigurationProvider<RealTimeConfig> configProvi
customTimeBar.Enable(gameDate);
customTimeBar.CityEventClick += CustomTimeBarCityEventClick;

var result = new RealTimeCore(timeAdjustment, customTimeBar, eventManager, patcher);
var vanillaEvents = VanillaEvents.Customize();

var result = new RealTimeCore(timeAdjustment, customTimeBar, eventManager, patcher, vanillaEvents);
eventManager.EventsChanged += result.CityEventsChanged;

var statistics = new Statistics(timeInfo, localizationProvider);
Expand Down Expand Up @@ -192,6 +201,8 @@ public void Stop()
Log.Info($"The 'Real Time' mod reverts method patches.");
patcher.Revert();

vanillaEvents.Revert();

timeAdjustment.Disable();
timeBar.CityEventClick -= CustomTimeBarCityEventClick;
timeBar.Disable();
Expand Down
16 changes: 11 additions & 5 deletions src/RealTime/CustomAI/RealTimeResidentAI.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,9 @@ private void DoScheduledEvacuation(ref CitizenSchedule schedule, TAI instance, u
private bool ProcessCitizenInShelter(ref CitizenSchedule schedule, ref TCitizen citizen)
{
ushort shelter = CitizenProxy.GetVisitBuilding(ref citizen);
if (BuildingMgr.BuildingHasFlags(shelter, Building.Flags.Downgrading))
if (BuildingMgr.BuildingHasFlags(shelter, Building.Flags.Downgrading) && schedule.ScheduledState == ResidentState.InShelter)
{
CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating);
schedule.Schedule(ResidentState.Unknown);
return true;
}
Expand Down Expand Up @@ -202,7 +203,7 @@ private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSched
return ScheduleAction.ProcessState;
}

if (CitizenProxy.GetVisitBuilding(ref citizen) == currentBuilding)
if (CitizenProxy.GetVisitBuilding(ref citizen) == currentBuilding && schedule.WorkStatus != WorkStatus.Working)
{
// A citizen may visit their own work building (e.g. shopping)
goto case Citizen.Location.Visit;
Expand All @@ -212,6 +213,11 @@ private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSched
return ScheduleAction.ProcessState;

case Citizen.Location.Visit:
if (CitizenProxy.GetWorkBuilding(ref citizen) == currentBuilding && schedule.WorkStatus == WorkStatus.Working)
{
goto case Citizen.Location.Work;
}

switch (buildingService)
{
case ItemClass.Service.Beautification:
Expand All @@ -228,7 +234,7 @@ when BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.
schedule.CurrentState = ResidentState.Shopping;
return ScheduleAction.ProcessState;

case ItemClass.Service.Disaster:
case ItemClass.Service.Disaster when CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating):
schedule.CurrentState = ResidentState.InShelter;
return ScheduleAction.ProcessState;
}
Expand All @@ -244,7 +250,7 @@ private bool UpdateCitizenSchedule(ref CitizenSchedule schedule, uint citizenId,
{
// If the game changed the work building, we have to update the work shifts first
ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen);
if (schedule.WorkBuilding != workBuilding)
if (schedule.WorkBuilding != workBuilding || (workBuilding == 0 && schedule.WorkShift != WorkShift.Unemployed))
{
schedule.WorkBuilding = workBuilding;
workBehavior.UpdateWorkShift(ref schedule, CitizenProxy.GetAge(ref citizen));
Expand Down Expand Up @@ -397,7 +403,7 @@ private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance,
return;
}

if (!executed && schedule.CurrentState == ResidentState.AtSchoolOrWork)
if (!executed && (schedule.CurrentState == ResidentState.AtSchoolOrWork || schedule.CurrentState == ResidentState.InShelter))
{
schedule.Schedule(ResidentState.Unknown);
DoScheduledHome(ref schedule, instance, citizenId, ref citizen);
Expand Down
25 changes: 18 additions & 7 deletions src/RealTime/CustomAI/RealTimeResidentAI.Moving.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,11 @@ private ushort MoveToCommercialBuilding(TAI instance, uint citizenId, ref TCitiz
{
CitizenMgr.ModifyUnitGoods(citizenUnit, ShoppingGoodsAmount);
}

return foundBuilding;
}

return foundBuilding;
return 0;
}

private ushort MoveToLeisureBuilding(TAI instance, uint citizenId, ref TCitizen citizen, ushort currentBuilding)
Expand All @@ -110,8 +112,9 @@ private ushort MoveToLeisureBuilding(TAI instance, uint citizenId, ref TCitizen
return 0;
}

StartMovingToVisitBuilding(instance, citizenId, ref citizen, leisureBuilding);
return leisureBuilding;
return StartMovingToVisitBuilding(instance, citizenId, ref citizen, leisureBuilding)
? leisureBuilding
: (ushort)0;
}

private bool StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitizen citizen, ushort visitBuilding)
Expand All @@ -129,13 +132,21 @@ private bool StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitiz
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);
if (CitizenProxy.GetVisitBuilding(ref citizen) == 0)
{
CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding);
return true;
// Building is full and doesn't accept visitors anymore
return false;
}

return false;
if (!residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, visitBuilding))
{
CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
return false;
}

return true;
}
}
}
30 changes: 17 additions & 13 deletions src/RealTime/CustomAI/RealTimeResidentAI.Visit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ private bool ScheduleRelaxing(ref CitizenSchedule schedule, uint citizenId, ref

private bool DoScheduledRelaxing(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
{
// Relaxing was already scheduled last time, but the citizen is still at school/work.
// Relaxing was already scheduled last time, but the citizen is still at school/work or in shelter.
// This can occur when the game's transfer manager can't find any activity for the citizen.
// In that case, move back home.
if (schedule.CurrentState == ResidentState.AtSchoolOrWork && schedule.LastScheduledState == ResidentState.Relaxing)
if ((schedule.CurrentState == ResidentState.AtSchoolOrWork || schedule.CurrentState == ResidentState.InShelter)
&& schedule.LastScheduledState == ResidentState.Relaxing)
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted relax but is still at work. No relaxing activity found. Now going home.");
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted relax but is still at work or in shelter. No relaxing activity found. Now going home.");
return false;
}

Expand All @@ -68,21 +69,23 @@ private bool DoScheduledRelaxing(ref CitizenSchedule schedule, TAI instance, uin
return true;

case ScheduleHint.AttendingEvent:
DateTime returnTime = default;
ICityEvent cityEvent = EventMgr.GetCityEvent(schedule.EventBuilding);
ushort eventBuilding = schedule.EventBuilding;
schedule.EventBuilding = 0;

ICityEvent cityEvent = EventMgr.GetCityEvent(eventBuilding);
if (cityEvent == null)
{
Log.Debug(LogCategory.Events, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted attend an event at '{schedule.EventBuilding}', but there was no event there");
Log.Debug(LogCategory.Events, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted attend an event at '{eventBuilding}', but there was no event there");
}
else if (StartMovingToVisitBuilding(instance, citizenId, ref citizen, schedule.EventBuilding))
else if (StartMovingToVisitBuilding(instance, citizenId, ref citizen, eventBuilding))
{
returnTime = cityEvent.EndTime;
Log.Debug(LogCategory.Events, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna attend an event at '{schedule.EventBuilding}', will return at {returnTime}");
schedule.Schedule(ResidentState.Unknown, cityEvent.EndTime);
Log.Debug(LogCategory.Events, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna attend an event at '{eventBuilding}', will return at {cityEvent.EndTime}");
return true;
}

return returnTime != default;
schedule.Schedule(ResidentState.Unknown);
return false;
}

uint relaxChance = spareTimeBehavior.GetRelaxingChance(
Expand Down Expand Up @@ -157,12 +160,13 @@ private bool ScheduleShopping(ref CitizenSchedule schedule, ref TCitizen citizen

private bool DoScheduledShopping(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
{
// Shopping was already scheduled last time, but the citizen is still at school/work.
// Shopping was already scheduled last time, but the citizen is still at school/work or in shelter.
// This can occur when the game's transfer manager can't find any activity for the citizen.
// In that case, move back home.
if (schedule.CurrentState == ResidentState.AtSchoolOrWork && schedule.LastScheduledState == ResidentState.Shopping)
if ((schedule.CurrentState == ResidentState.AtSchoolOrWork || schedule.CurrentState == ResidentState.InShelter)
&& schedule.LastScheduledState == ResidentState.Shopping)
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted go shopping but is still at work. No shopping activity found. Now going home.");
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted go shopping but is still at work or in shelter. No shopping activity found. Now going home.");
return false;
}

Expand Down
57 changes: 29 additions & 28 deletions src/RealTime/CustomAI/RealTimeTouristAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ private void ProcessMoving(TAI instance, uint citizenId, ref TCitizen citizen)

if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
{
Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Leaving the city.");
touristAI.FindVisitPlace(instance, citizenId, CitizenProxy.GetCurrentBuilding(ref citizen), touristAI.GetLeavingReason(instance, citizenId, ref citizen));
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));
return;
}

Expand Down Expand Up @@ -215,38 +215,29 @@ when BuildingMgr.GetBuildingSubService(visitBuilding) == ItemClass.SubService.Co
return;
}

if (Random.ShouldOccur(TouristEventChance) && !IsBadWeather())
ICityEvent currentEvent = EventMgr.GetCityEvent(visitBuilding);
if (currentEvent != null && currentEvent.StartTime < TimeInfo.Now)
{
ICityEvent cityEvent = GetUpcomingEventToAttend(citizenId, ref citizen);
if (cityEvent != null)
if (Random.ShouldOccur(TouristShoppingChance))
{
StartMovingToVisitBuilding(instance, citizenId, ref citizen, CitizenProxy.GetCurrentBuilding(ref citizen), cityEvent.BuildingId);
Log.Debug(LogCategory.Events, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} attending an event at {cityEvent.BuildingId}");
return;
BuildingMgr.ModifyMaterialBuffer(visitBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
}

return;
}

int doNothingChance;
switch (EventMgr.GetEventState(visitBuilding, DateTime.MaxValue))
if (Random.ShouldOccur(TouristEventChance) && !IsBadWeather())
{
case CityEventState.Ongoing:
if (Random.ShouldOccur(TouristShoppingChance))
{
BuildingMgr.ModifyMaterialBuffer(visitBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
}

ICityEvent cityEvent = GetUpcomingEventToAttend(citizenId, ref citizen);
if (cityEvent != null
&& StartMovingToVisitBuilding(instance, citizenId, ref citizen, CitizenProxy.GetCurrentBuilding(ref citizen), cityEvent.BuildingId))
{
Log.Debug(LogCategory.Events, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} attending an event at {cityEvent.BuildingId}");
return;

case CityEventState.Finished:
doNothingChance = 0;
break;

default:
doNothingChance = TouristDoNothingProbability;
break;
}
}

FindRandomVisitPlace(instance, citizenId, ref citizen, doNothingChance, visitBuilding);
FindRandomVisitPlace(instance, citizenId, ref citizen, 0, visitBuilding);
}

private void FindRandomVisitPlace(TAI instance, uint citizenId, ref TCitizen citizen, int doNothingProbability, ushort currentBuilding)
Expand Down Expand Up @@ -358,12 +349,22 @@ private ushort FindHotel(ushort currentBuilding)
ItemClass.SubService.CommercialTourist);
}

private void StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitizen citizen, ushort currentBuilding, ushort visitBuilding)
private bool StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitizen citizen, ushort currentBuilding, ushort visitBuilding)
{
if (touristAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, visitBuilding))
CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding);
if (CitizenProxy.GetVisitBuilding(ref citizen) == 0)
{
CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding);
// Building is full and doesn't accept visitors anymore
return false;
}

if (!touristAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, visitBuilding))
{
CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
return false;
}

return true;
}

private uint GetHotelLeaveChance()
Expand Down
Loading

0 comments on commit 12c9aed

Please sign in to comment.