Skip to content

Commit

Permalink
Merge branch 'feature-commercial'
Browse files Browse the repository at this point in the history
  • Loading branch information
dymanoid committed Jun 26, 2018
2 parents efa4ae3 + bdc33fb commit b17950d
Show file tree
Hide file tree
Showing 22 changed files with 228 additions and 169 deletions.
38 changes: 38 additions & 0 deletions src/RealTime/BuildingAI/CommercialAI.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// <copyright file="CommercialAI.cs" company="dymanoid">
// Copyright (c) dymanoid. All rights reserved.
// </copyright>

namespace RealTime.BuildingAI
{
using RealTime.GameConnection;
using RealTime.Simulation;

internal sealed class CommercialAI
{
private readonly ITimeInfo timeInfo;

public CommercialAI(ITimeInfo timeInfo, IBuildingManagerConnection buildingManager)
{
this.timeInfo = timeInfo ?? throw new System.ArgumentNullException(nameof(timeInfo));
BuildingMgr = buildingManager ?? throw new System.ArgumentNullException(nameof(buildingManager));
}

public IBuildingManagerConnection BuildingMgr { get; }

public void Process(uint frameId)
{
frameId &= 0xFF;

uint buildingFrom = frameId * 192u;
uint buildingTo = ((frameId + 1u) * 192u) - 1u;

// We have only few customers at night - that's an inteded behavior.
// To avoid commercial building from collapsing due to lack of customers,
// we force the problem timer to pause at night time.
if (timeInfo.IsNightTime)
{
BuildingMgr.DecrementOutgoingProblemTimer((ushort)buildingFrom, (ushort)buildingTo, ItemClass.Service.Commercial);
}
}
}
}
14 changes: 10 additions & 4 deletions src/RealTime/Core/RealTimeCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace RealTime.Core
using System;
using System.Collections.Generic;
using System.Security.Permissions;
using RealTime.BuildingAI;
using RealTime.Config;
using RealTime.CustomAI;
using RealTime.Events;
Expand Down Expand Up @@ -104,7 +105,6 @@ public static RealTimeCore Run(RealTimeConfig config, string rootPath, Localizat

SetupCustomAI(timeInfo, config, gameConnections, eventManager);

RealTimeEventSimulation.EventManager = eventManager;
CityEventsLoader.Istance.ReloadEvents(rootPath);

var customTimeBar = new CustomTimeBar();
Expand All @@ -113,7 +113,11 @@ public static RealTimeCore Run(RealTimeConfig config, string rootPath, Localizat

var result = new RealTimeCore(timeAdjustment, customTimeBar, eventManager);
eventManager.EventsChanged += result.CityEventsChanged;
DaylightTimeSimulation.NewDay += result.CityEventsChanged;
SimulationHandler.NewDay += result.CityEventsChanged;

SimulationHandler.DayTimeSimulation = new DayTimeSimulation();
SimulationHandler.EventManager = eventManager;
SimulationHandler.CommercialAI = new CommercialAI(timeInfo, buildingManager);

RealTimeStorage.Instance.GameSaving += result.GameSaving;
result.storageData.Add(eventManager);
Expand All @@ -139,7 +143,7 @@ public void Stop()
timeBar.CityEventClick -= CustomTimeBarCityEventClick;
timeBar.Disable();
eventManager.EventsChanged -= CityEventsChanged;
DaylightTimeSimulation.NewDay -= CityEventsChanged;
SimulationHandler.NewDay -= CityEventsChanged;

CityEventsLoader.Istance.Clear();

Expand All @@ -148,7 +152,9 @@ public void Stop()
ResidentAIHook.RealTimeAI = null;
TouristAIHook.RealTimeAI = null;
PrivateBuildingAIHook.RealTimeAI = null;
RealTimeEventSimulation.EventManager = null;
SimulationHandler.EventManager = null;
SimulationHandler.DayTimeSimulation = null;
SimulationHandler.CommercialAI = null;

try
{
Expand Down
3 changes: 2 additions & 1 deletion src/RealTime/CustomAI/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ internal static class Constants
{
public const int ShoppingGoodsAmount = 100;

public const float LocalSearchDistance = 500f;
public const float LocalSearchDistance = 270f * 2;
public const float LeisureSearchDistance = 270f * 3;
public const float FullSearchDistance = 270f * 64f / 2f;

public const uint AbandonTourChance = 25;
Expand Down
2 changes: 1 addition & 1 deletion src/RealTime/CustomAI/RealTimeHumanAIBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ protected bool AttendUpcomingEvent(uint citizenId, ref TCitizen citizen, out ush
eventBuildingId = default;

ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);
if (EventMgr.GetEventState(currentBuilding, DateTime.MaxValue) == CityEventState.OnGoing)
if (EventMgr.GetEventState(currentBuilding, DateTime.MaxValue) == CityEventState.Ongoing)
{
return false;
}
Expand Down
6 changes: 3 additions & 3 deletions src/RealTime/CustomResidentAI/RealTimeResidentAI.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ private ResidentState GetResidentState(ref TCitizen citizen)
ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);
ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding);

if ((BuildingMgr.GetBuildingFlags(currentBuilding) & Building.Flags.Evacuating) != 0
if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating)
&& buildingService != ItemClass.Service.Disaster)
{
return ResidentState.Evacuating;
Expand All @@ -141,7 +141,7 @@ private ResidentState GetResidentState(ref TCitizen citizen)
switch (CitizenProxy.GetLocation(ref citizen))
{
case Citizen.Location.Home:
if ((CitizenProxy.GetFlags(ref citizen) & Citizen.Flags.MovingIn) != 0)
if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn))
{
return ResidentState.LeftCity;
}
Expand All @@ -154,7 +154,7 @@ private ResidentState GetResidentState(ref TCitizen citizen)
return ResidentState.Unknown;

case Citizen.Location.Work:
if (buildingService == ItemClass.Service.Disaster && CitizenProxy.GetFlags(ref citizen) == Citizen.Flags.Evacuating)
if (buildingService == ItemClass.Service.Disaster && CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
{
return ResidentState.InShelter;
}
Expand Down
9 changes: 3 additions & 6 deletions src/RealTime/CustomResidentAI/RealTimeResidentAI.Moving.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,14 @@ private void ProcessCitizenMoving(TAI instance, uint citizenId, ref TCitizen cit
return;
}

if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && (CitizenProxy.GetFlags(ref citizen) & Citizen.Flags.Evacuating) == 0)
if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
{
Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Finding an evacuation place.");
TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0));
return;
}

CitizenInstance.Flags instanceFlags = CitizenMgr.GetInstanceFlags(instanceId);
CitizenInstance.Flags onTourFlags = CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour;

if ((instanceFlags & onTourFlags) == onTourFlags)
if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, true))
{
ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);
if (IsChance(AbandonTourChance) && homeBuilding != 0)
Expand All @@ -48,7 +45,7 @@ private void ProcessCitizenMoving(TAI instance, uint citizenId, ref TCitizen cit
residentAI.StartMoving(instance, citizenId, ref citizen, 0, homeBuilding);
}
}
else if ((instanceFlags & (CitizenInstance.Flags.WaitingTransport | CitizenInstance.Flags.WaitingTaxi)) != 0)
else if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.WaitingTransport | CitizenInstance.Flags.WaitingTaxi))
{
if (mayCancel && CitizenMgr.GetInstanceWaitCounter(instanceId) == 255 && IsChance(AbandonTransportWaitChance))
{
Expand Down
22 changes: 16 additions & 6 deletions src/RealTime/CustomResidentAI/RealTimeResidentAI.Visit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ internal sealed partial class RealTimeResidentAI<TAI, TCitizen>
{
private void ProcessCitizenVisit(TAI instance, ResidentState citizenState, uint citizenId, ref TCitizen citizen)
{
if (CitizenProxy.GetVisitBuilding(ref citizen) == 0)
ushort currentBuilding = CitizenProxy.GetVisitBuilding(ref citizen);
if (currentBuilding == 0)
{
Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is in corrupt state: visiting with no visit building. Teleporting home.");
CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
Expand All @@ -28,6 +29,15 @@ private void ProcessCitizenVisit(TAI instance, ResidentState citizenState, uint
return;

case ResidentState.AtLeisureArea:
if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods)
&& BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure)
{
// No Citizen.Flags.NeedGoods flag reset here, because we only bought 'beer' or 'champagne' in a leisure building.
BuildingMgr.ModifyMaterialBuffer(CitizenProxy.GetVisitBuilding(ref citizen), TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
}

goto case ResidentState.Visiting;

case ResidentState.Visiting:
if (!CitizenGoesWorking(instance, citizenId, ref citizen))
{
Expand All @@ -37,7 +47,7 @@ private void ProcessCitizenVisit(TAI instance, ResidentState citizenState, uint
return;

case ResidentState.Shopping:
if ((CitizenProxy.GetFlags(ref citizen) & Citizen.Flags.NeedGoods) != 0)
if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods))
{
BuildingMgr.ModifyMaterialBuffer(CitizenProxy.GetVisitBuilding(ref citizen), TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.NeedGoods);
Expand Down Expand Up @@ -66,7 +76,7 @@ private bool CitzenReturnsFromShelter(TAI instance, uint citizenId, ref TCitizen
return true;
}

if ((BuildingMgr.GetBuildingFlags(visitBuilding) & Building.Flags.Downgrading) == 0)
if (!BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading))
{
return false;
}
Expand Down Expand Up @@ -96,7 +106,7 @@ private bool CitizenReturnsHomeFromVisit(TAI instance, uint citizenId, ref TCiti
switch (EventMgr.GetEventState(visitBuilding, TimeInfo.Now.AddHours(MaxHoursOnTheWay)))
{
case CityEventState.Upcoming:
case CityEventState.OnGoing:
case CityEventState.Ongoing:
return false;

case CityEventState.Finished:
Expand Down Expand Up @@ -127,7 +137,7 @@ private void ReturnFromVisit(TAI instance, uint citizenId, ref TCitizen citizen,

private bool CitizenGoesShopping(TAI instance, uint citizenId, ref TCitizen citizen)
{
if ((CitizenProxy.GetFlags(ref citizen) & Citizen.Flags.NeedGoods) == 0)
if (!CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods))
{
return false;
}
Expand Down Expand Up @@ -242,7 +252,7 @@ private ushort MoveToLeisure(TAI instance, uint citizenId, ref TCitizen citizen,
{
ushort leisureBuilding = BuildingMgr.FindActiveBuilding(
buildingId,
FullSearchDistance,
LeisureSearchDistance,
ItemClass.Service.Commercial,
ItemClass.SubService.CommercialLeisure);

Expand Down
12 changes: 5 additions & 7 deletions src/RealTime/CustomTouristAI/RealTimeTouristAI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,14 @@ private void ProcessMoving(TAI instance, uint citizenId, ref TCitizen citizen)
return;
}

if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && (CitizenProxy.GetFlags(ref citizen) & Citizen.Flags.Evacuating) == 0)
if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
{
Log.Debug(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));
return;
}

CitizenInstance.Flags flags = CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour;
if ((CitizenMgr.GetInstanceFlags(instanceId) & flags) == flags)
if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, true))
{
FindRandomVisitPlace(instance, citizenId, ref citizen, TouristDoNothingProbability, 0);
}
Expand All @@ -95,8 +94,7 @@ private void ProcessVisit(TAI instance, uint citizenId, ref TCitizen citizen)
return;
}

Building.Flags buildingFlags = BuildingMgr.GetBuildingFlags(visitBuilding);
if ((buildingFlags & Building.Flags.Evacuating) != 0)
if (BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Evacuating))
{
touristAI.FindEvacuationPlace(instance, citizenId, visitBuilding, touristAI.GetEvacuationReason(instance, visitBuilding));
return;
Expand All @@ -105,7 +103,7 @@ private void ProcessVisit(TAI instance, uint citizenId, ref TCitizen citizen)
switch (BuildingMgr.GetBuildingService(visitBuilding))
{
case ItemClass.Service.Disaster:
if ((buildingFlags & Building.Flags.Downgrading) != 0)
if (BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading))
{
FindRandomVisitPlace(instance, citizenId, ref citizen, 0, visitBuilding);
}
Expand All @@ -129,7 +127,7 @@ private void ProcessVisit(TAI instance, uint citizenId, ref TCitizen citizen)
bool doShopping;
switch (EventMgr.GetEventState(visitBuilding, DateTime.MaxValue))
{
case CityEventState.OnGoing:
case CityEventState.Ongoing:
doShopping = IsChance(TouristShoppingChance);
break;

Expand Down
2 changes: 1 addition & 1 deletion src/RealTime/Events/CityEventState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ internal enum CityEventState
{
None,
Upcoming,
OnGoing,
Ongoing,
Finished
}
}
6 changes: 3 additions & 3 deletions src/RealTime/Events/RealTimeEventManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public CityEventState GetEventState(ushort buildingId, DateTime latestStart)
}
else if ((vanillaEventState & EventData.Flags.Active) != 0)
{
return CityEventState.OnGoing;
return CityEventState.Ongoing;
}
else if (vanillaEventState != EventData.Flags.None)
{
Expand All @@ -115,7 +115,7 @@ public CityEventState GetEventState(ushort buildingId, DateTime latestStart)

if (activeEvent != null && activeEvent.BuildingId == buildingId)
{
return CityEventState.OnGoing;
return CityEventState.Ongoing;
}
else if (lastActiveEvent != null && lastActiveEvent.BuildingId == buildingId)
{
Expand Down Expand Up @@ -159,7 +159,7 @@ public void ProcessEvents()
}

ushort building = buildingManager.GetRandomBuilding(EventBuildingServices);
if ((buildingManager.GetBuildingFlags(building) & Building.Flags.Active) == 0)
if (!buildingManager.BuildingHasFlags(building, Building.Flags.Active))
{
return;
}
Expand Down
18 changes: 0 additions & 18 deletions src/RealTime/Events/RealTimeEventSimulation.cs

This file was deleted.

29 changes: 25 additions & 4 deletions src/RealTime/GameConnection/BuildingManagerConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace RealTime.GameConnection
{
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
Expand All @@ -25,11 +24,11 @@ public ItemClass.SubService GetBuildingSubService(ushort buildingId)
: BuildingManager.instance.m_buildings.m_buffer[buildingId].Info.m_class.m_subService;
}

public Building.Flags GetBuildingFlags(ushort buildingId)
public bool BuildingHasFlags(ushort buildingId, Building.Flags flags)
{
return buildingId == 0
? Building.Flags.None
: BuildingManager.instance.m_buildings.m_buffer[buildingId].m_flags;
? false
: (BuildingManager.instance.m_buildings.m_buffer[buildingId].m_flags & flags) != 0;
}

public float GetDistanceBetweenBuildings(ushort building1, ushort building2)
Expand Down Expand Up @@ -134,6 +133,28 @@ public ushort GetRandomBuilding(IEnumerable<ItemClass.Service> services)
return 0;
}

public void DecrementOutgoingProblemTimer(ushort buildingIdFrom, ushort buildingIdTo, ItemClass.Service service)
{
if (service == ItemClass.Service.None)
{
return;
}

for (ushort buildingId = buildingIdFrom; buildingId <= buildingIdTo; buildingId++)
{
ref Building building = ref BuildingManager.instance.m_buildings.m_buffer[buildingId];
if ((building.m_flags & Building.Flags.Created) == 0 || building.Info.m_class.m_service != service)
{
continue;
}

if (building.m_outgoingProblemTimer > 0)
{
building.m_outgoingProblemTimer -= 1;
}
}
}

public string GetBuildingClassName(ushort buildingId)
{
return buildingId == 0
Expand Down
4 changes: 2 additions & 2 deletions src/RealTime/GameConnection/CitizenConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ public ushort GetCurrentBuilding(ref Citizen citizen)
return citizen.GetBuildingByLocation();
}

public Citizen.Flags GetFlags(ref Citizen citizen)
public bool HasFlags(ref Citizen citizen, Citizen.Flags flags)
{
return citizen.m_flags;
return (citizen.m_flags & flags) != 0;
}

public ushort GetHomeBuilding(ref Citizen citizen)
Expand Down
Loading

0 comments on commit b17950d

Please sign in to comment.