private void ReturnFromVisit( TAI instance, uint citizenId, ref TCitizen citizen, ushort targetBuilding, Citizen.Location targetLocation, bool isVirtual) { if (targetBuilding == 0 || targetLocation == Citizen.Location.Visit || CitizenProxy.GetVehicle(ref citizen) != 0) { return; } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating); CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); if (isVirtual || targetBuilding == currentBuilding) { CitizenProxy.SetLocation(ref citizen, targetLocation); } else { residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, targetBuilding); } }
private bool ProcessCitizenSick(TAI instance, uint citizenId, ref TCitizen citizen) { Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen); if (currentLocation == Citizen.Location.Moving) { return(false); } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (currentLocation != Citizen.Location.Home && currentBuilding == 0) { Log.Debug(LogCategory.State, $"Teleporting {GetCitizenDesc(citizenId, ref citizen)} back home because they are sick but no building is specified"); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); return(true); } if (currentLocation != Citizen.Location.Home && CitizenProxy.GetVehicle(ref citizen) != 0) { return(true); } if (currentLocation == Citizen.Location.Visit) { ItemClass.Service service = BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen)); if (service == ItemClass.Service.HealthCare || service == ItemClass.Service.Disaster) { return(true); } } Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is sick, trying to get to a hospital"); residentAI.FindHospital(instance, citizenId, currentBuilding, TransferManager.TransferReason.Sick); return(true); }
public ExtCitizen(uint citizenId) { this.citizenId = citizenId; transportMode = ExtTransportMode.None; lastTransportMode = ExtTransportMode.None; lastLocation = Citizen.Location.Moving; }
internal ExtCitizen(uint citizenId) { this.citizenId = citizenId; transportMode = ExtTransportMode.None; lastTransportMode = ExtTransportMode.None; lastLocation = Citizen.Location.Moving; ResetLastLocation(); }
private void ResetLastLocation() { Citizen.Location loc = Citizen.Location.Moving; Constants.ServiceFactory.CitizenService.ProcessCitizen(citizenId, delegate(uint citId, ref Citizen citizen) { loc = citizen.CurrentLocation; return(true); }); lastLocation = loc; }
/// <summary> /// Gets a string that describes the specified citizen. /// </summary> /// /// <param name="citizenId">The citizen ID.</param> /// <param name="citizen">The citizen data reference.</param> /// /// <returns>A short string describing the specified citizen.</returns> protected string GetCitizenDesc(uint citizenId, ref TCitizen citizen) { ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); string home = homeBuilding == 0 ? "homeless" : "lives at " + homeBuilding; ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen); string employment = workBuilding == 0 ? "unemployed" : "works at " + workBuilding; Citizen.Location location = CitizenProxy.GetLocation(ref citizen); return($"Citizen {citizenId} ({CitizenProxy.GetAge(ref citizen)}, {home}, {employment}, currently {location} at {CitizenProxy.GetCurrentBuilding(ref citizen)}) / instance {CitizenProxy.GetInstance(ref citizen)}"); }
/// <summary> /// Gets a string that describes the provided citizen. /// </summary> /// /// <param name="citizenId">The citizen ID.</param> /// <param name="citizen">The citizen data reference.</param> /// <param name="isVirtual"><c>true</c> if the citizen is in a virtual mode; otherwise, <c>false</c>.</param> /// /// <returns>A short string describing the provided citizen.</returns> protected string GetCitizenDesc(uint citizenId, ref TCitizen citizen, bool?isVirtual) { ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); string home = homeBuilding == 0 ? "homeless" : "lives at " + homeBuilding; ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen); string employment = workBuilding == 0 ? "unemployed" : "works at " + workBuilding; Citizen.Location location = CitizenProxy.GetLocation(ref citizen); string virt = isVirtual.HasValue ? (isVirtual.Value ? " (virtual)" : " (real)") : null; return($"Citizen {citizenId} ({CitizenProxy.GetAge(ref citizen)}, {home}, {employment}, currently {location} at {CitizenProxy.GetCurrentBuilding(ref citizen)}) / instance {CitizenProxy.GetInstance(ref citizen)}{virt}"); }
private void ProcessCitizenAtSchoolOrWork(TAI instance, uint citizenId, ref TCitizen citizen) { ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen); if (workBuilding == 0) { Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is in corrupt state: at school/work with no work building. Teleporting home."); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); return; } if (ShouldGoToLunch(CitizenProxy.GetAge(ref citizen))) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen); ushort lunchPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance); if (lunchPlace != 0) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going for lunch from {currentBuilding} ({currentLocation}) to {lunchPlace}"); } else { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted to go for lunch from {currentBuilding} ({currentLocation}), but there were no buildings close enough"); } return; } if (!ShouldReturnFromSchoolOrWork(CitizenProxy.GetAge(ref citizen))) { return; } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} leaves their workplace {workBuilding}"); if (CitizenGoesToEvent(instance, citizenId, ref citizen)) { return; } if (!CitizenGoesShopping(instance, citizenId, ref citizen) && !CitizenGoesRelaxing(instance, citizenId, ref citizen)) { residentAI.StartMoving(instance, citizenId, ref citizen, workBuilding, CitizenProxy.GetHomeBuilding(ref citizen)); } }
private void ProcessCitizenDead(TAI instance, uint citizenId, ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen); switch (currentLocation) { case Citizen.Location.Home when currentBuilding != 0: CitizenProxy.SetWorkplace(ref citizen, citizenId, 0); CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); break; case Citizen.Location.Work when currentBuilding != 0: CitizenProxy.SetHome(ref citizen, citizenId, 0); CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); break; case Citizen.Location.Visit when currentBuilding != 0: CitizenProxy.SetHome(ref citizen, citizenId, 0); CitizenProxy.SetWorkplace(ref citizen, citizenId, 0); if (BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen)) == ItemClass.Service.HealthCare) { return; } break; case Citizen.Location.Moving when CitizenProxy.GetVehicle(ref citizen) != 0: CitizenProxy.SetHome(ref citizen, citizenId, 0); CitizenProxy.SetWorkplace(ref citizen, citizenId, 0); CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); return; default: Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is released because of death"); residentSchedules[citizenId] = default; CitizenMgr.ReleaseCitizen(citizenId); return; } residentAI.FindHospital(instance, citizenId, currentBuilding, TransferManager.TransferReason.Dead); Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is dead, body should get serviced"); }
/// <summary> /// Check if resident is confused. /// </summary> /// <param name="data">The citizen.</param> /// <returns>True if resident is confused.</returns> public static bool IsConfused(ref Citizen data) { // From ResidentAI.GetLocalizedStatus from original game code at version 1.7.0-f5. CitizenManager instance1 = Singleton <CitizenManager> .instance; ushort instance2 = data.m_instance; if ((int)instance2 != 0) { return(IsConfused(ref instance1.m_instances.m_buffer[(int)instance2])); } Citizen.Location currentLocation = data.CurrentLocation; ushort homeBuilding = data.m_homeBuilding; ushort workBuilding = data.m_workBuilding; ushort visitBuilding = data.m_visitBuilding; //bool flag = (data.m_flags & Citizen.Flags.Student) != Citizen.Flags.None; if (currentLocation != Citizen.Location.Home) { if (currentLocation != Citizen.Location.Work) { if (currentLocation == Citizen.Location.Visit && (int)visitBuilding != 0) { //target = InstanceID.Empty; //target.Building = visitBuilding; //return ColossalFramework.Globalization.Locale.Get("CITIZEN_STATUS_VISITING"); return(false); } } else if ((int)workBuilding != 0) { //target = InstanceID.Empty; //return ColossalFramework.Globalization.Locale.Get(!flag ? "CITIZEN_STATUS_AT_WORK" : "CITIZEN_STATUS_AT_SCHOOL"); return(false); } } else if ((int)homeBuilding != 0) { //target = InstanceID.Empty; //return ColossalFramework.Globalization.Locale.Get("CITIZEN_STATUS_AT_HOME"); return(false); } //target = InstanceID.Empty; //return ColossalFramework.Globalization.Locale.Get("CITIZEN_STATUS_CONFUSED"); return(true); }
private void ProcessCitizenDead(TAI instance, uint citizenId, ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen); if (currentBuilding == 0 || (currentLocation == Citizen.Location.Moving && CitizenProxy.GetVehicle(ref citizen) == 0)) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is released"); residentSchedules[citizenId] = default; CitizenMgr.ReleaseCitizen(citizenId); return; } if (currentLocation != Citizen.Location.Home && CitizenProxy.GetHomeBuilding(ref citizen) != 0) { CitizenProxy.SetHome(ref citizen, citizenId, 0); } if (currentLocation != Citizen.Location.Work && CitizenProxy.GetWorkBuilding(ref citizen) != 0) { CitizenProxy.SetWorkplace(ref citizen, citizenId, 0); } if (currentLocation != Citizen.Location.Visit && CitizenProxy.GetVisitBuilding(ref citizen) != 0) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); } if (currentLocation == Citizen.Location.Moving || CitizenProxy.GetVehicle(ref citizen) != 0) { return; } if (currentLocation == Citizen.Location.Visit && BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen)) == ItemClass.Service.HealthCare) { return; } residentAI.FindHospital(instance, citizenId, currentBuilding, TransferManager.TransferReason.Dead); Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is dead, body should get serviced"); }
/// <summary> /// Check if tourist is confused. /// </summary> /// <param name="data">The citizen.</param> /// <returns>True if tourist is confused.</returns> public static bool IsConfused(ref Citizen data) { // From TouristAI.GetLocalizedStatus from original game code at version 1.4.1-f2. CitizenManager instance = Singleton <CitizenManager> .instance; ushort instanceID = data.m_instance; if ((int)instanceID != 0) { return(IsConfused(ref instance.m_instances.m_buffer[(int)instanceID])); } Citizen.Location currentLocation = data.CurrentLocation; ushort num = data.m_visitBuilding; if (currentLocation == Citizen.Location.Visit && (int)num != 0) { ////target = InstanceID.Empty; ////target.Building = num; ////return Locale.Get("CITIZEN_STATUS_VISITING"); return(false); } ////target = InstanceID.Empty; ////return Locale.Get("CITIZEN_STATUS_CONFUSED"); return(true); }
public void SetLocation(ref Citizen citizen, Citizen.Location location) { citizen.CurrentLocation = location; }
private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSchedule schedule) { if (schedule.CurrentState == ResidentState.Ignored) { return(ScheduleAction.Ignore); } if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.DummyTraffic)) { schedule.CurrentState = ResidentState.Ignored; return(ScheduleAction.Ignore); } Citizen.Location location = CitizenProxy.GetLocation(ref citizen); if (location == Citizen.Location.Moving) { if (CitizenMgr.InstanceHasFlags( CitizenProxy.GetInstance(ref citizen), CitizenInstance.Flags.OnTour | CitizenInstance.Flags.TargetIsNode, true)) { // Guided tours are treated as visits schedule.CurrentState = ResidentState.Visiting; schedule.Hint = ScheduleHint.OnTour; return(ScheduleAction.ProcessState); } return(ScheduleAction.ProcessTransition); } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (currentBuilding == 0) { schedule.CurrentState = ResidentState.Unknown; return(ScheduleAction.ProcessState); } ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding); if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating) && buildingService != ItemClass.Service.Disaster) { schedule.CurrentState = ResidentState.Evacuation; schedule.Schedule(ResidentState.InShelter); return(ScheduleAction.ProcessState); } switch (location) { case Citizen.Location.Home: schedule.CurrentState = ResidentState.AtHome; return(ScheduleAction.ProcessState); case Citizen.Location.Work: if (buildingService == ItemClass.Service.Disaster && CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating)) { schedule.CurrentState = ResidentState.InShelter; return(ScheduleAction.ProcessState); } if (CitizenProxy.GetVisitBuilding(ref citizen) == currentBuilding && schedule.WorkStatus != WorkStatus.Working) { // A citizen may visit their own work building (e.g. shopping), // but the game sets the location to 'work' even if the citizen visits the building. goto case Citizen.Location.Visit; } schedule.CurrentState = ResidentState.AtSchoolOrWork; return(ScheduleAction.ProcessState); case Citizen.Location.Visit: switch (buildingService) { case ItemClass.Service.Beautification: case ItemClass.Service.Monument: case ItemClass.Service.Tourism: case ItemClass.Service.Commercial when BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure && schedule.WorkStatus != WorkStatus.Working: schedule.CurrentState = ResidentState.Relaxing; return(ScheduleAction.ProcessState); case ItemClass.Service.Commercial: schedule.CurrentState = ResidentState.Shopping; return(ScheduleAction.ProcessState); case ItemClass.Service.Disaster when CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating): schedule.CurrentState = ResidentState.InShelter; return(ScheduleAction.ProcessState); } schedule.CurrentState = ResidentState.Visiting; return(ScheduleAction.ProcessState); } return(ScheduleAction.Ignore); }
/// <summary> /// Generic stuff that can be taken care of as a group. /// </summary> /// <param name="thisAI"></param> /// <param name="citizenID"></param> /// <param name="person"></param> /// <returns>Whether to continue or whether this has taken care of the resident.</returns> private static bool ProcessGenerics(ref ResidentAI thisAI, uint citizenID, ref Citizen person) { bool everythingOk = false; ushort residingBuilding = 0; CitizenManager _citizenManager = Singleton <CitizenManager> .instance; Citizen.Location _currentLocation = person.CurrentLocation; switch (_currentLocation) { case Citizen.Location.Home: residingBuilding = person.m_homeBuilding; break; case Citizen.Location.Work: residingBuilding = person.m_workBuilding; break; case Citizen.Location.Visit: residingBuilding = person.m_visitBuilding; break; } Building visitBuilding = Singleton <BuildingManager> .instance.m_buildings.m_buffer[person.m_visitBuilding]; bool inHealthcare = _currentLocation == Citizen.Location.Visit && residingBuilding != 0 && (visitBuilding.Info.m_class.m_service == ItemClass.Service.HealthCare || visitBuilding.Info.m_class.m_service == ItemClass.Service.Disaster); if (person.Dead) { if (residingBuilding == 0) { _citizenManager.ReleaseCitizen(citizenID); } else { if ((_currentLocation == Citizen.Location.Work || _currentLocation == Citizen.Location.Visit) && person.m_homeBuilding != 0) { person.SetWorkplace(citizenID, 0, 0U); } if ((_currentLocation == Citizen.Location.Home || _currentLocation == Citizen.Location.Visit) && person.m_workBuilding != 0) { person.SetWorkplace(citizenID, 0, 0U); } if ((_currentLocation == Citizen.Location.Home || _currentLocation == Citizen.Location.Work) && person.m_visitBuilding != 0) { person.SetVisitplace(citizenID, 0, 0U); } if (ExperimentsToggle.ImprovedDeathcare) { if (person.m_vehicle == 0 && !inHealthcare) { NewResidentAI.FindHospital(thisAI, citizenID, residingBuilding, TransferManager.TransferReason.Sick); } } else { if (person.m_vehicle == 0 && !inHealthcare) { NewResidentAI.FindHospital(thisAI, citizenID, residingBuilding, TransferManager.TransferReason.Dead); } } } } else if (person.Arrested) { if (_currentLocation == Citizen.Location.Visit && residingBuilding == 0) { person.Arrested = false; } else { person.Arrested = false; } } else if (person.Sick) { if (residingBuilding != 0) { if (person.m_vehicle == 0 && !inHealthcare) { NewResidentAI.FindHospital(thisAI, citizenID, residingBuilding, TransferManager.TransferReason.Sick); } } else { person.CurrentLocation = Citizen.Location.Home; } } else if (residingBuilding == 0) { person.CurrentLocation = Citizen.Location.Home; } else if (ShouldEvacuate(residingBuilding)) { NewResidentAI.FindEvacuationPlace(thisAI, citizenID, residingBuilding, NewResidentAI.GetEvacuationReason(thisAI, residingBuilding)); } else if (!person.Collapsed) { everythingOk = true; } return(everythingOk); }
public bool IsAtOutsideConnection(ushort instanceId, ref CitizenInstance instanceData, ref Citizen citizenData) { #if DEBUG bool citDebug = GlobalConfig.Instance.Debug.CitizenId == 0 || GlobalConfig.Instance.Debug.CitizenId == instanceData.m_citizen; bool debug = GlobalConfig.Instance.Debug.Switches[2] && citDebug; bool fineDebug = GlobalConfig.Instance.Debug.Switches[4] && citDebug; if (debug) { Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): called for citizen instance {instanceId}. Path: {instanceData.m_path} vehicle={citizenData.m_vehicle}"); } #endif Citizen.Location location = citizenData.CurrentLocation; switch (location) { case Citizen.Location.Home: case Citizen.Location.Visit: case Citizen.Location.Work: #if DEBUG if (fineDebug) { Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): Citizen is currently at location {location}. This is not an outside connection."); } #endif return(false); } bool spawned = (instanceData.m_flags & CitizenInstance.Flags.Character) != CitizenInstance.Flags.None; if (!spawned && (citizenData.m_vehicle == 0 || (Singleton <VehicleManager> .instance.m_vehicles.m_buffer[citizenData.m_vehicle].m_flags & Vehicle.Flags.Spawned) == 0)) { #if DEBUG if (fineDebug) { Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): Citizen instance is not spawned ({instanceData.m_flags}) and does not have a spawned car. Not at an outside connection."); } #endif return(false); } if (instanceData.m_sourceBuilding == 0) { #if DEBUG if (fineDebug) { Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): Citizen instance does not have a source building. Not at an outside connection."); } #endif return(false); } if ((Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_sourceBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None) { #if DEBUG if (fineDebug) { Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): Source building {instanceData.m_sourceBuilding} is not an outside connection."); } #endif return(false); } Vector3 pos; if (spawned) { pos = instanceData.GetLastFramePosition(); } else { pos = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[citizenData.m_vehicle].GetLastFramePosition(); } bool ret = (pos - Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_sourceBuilding].m_position).magnitude <= GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance; #if DEBUG if (fineDebug) { Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): pos={pos}, spawned={spawned}, ret={ret}"); } #endif return(ret); }