/// <summary>removes the specified flags from a citizen.</summary> /// <param name="citizen">The citizen to remove flags from.</param> /// <param name="flags">The flags to remove.</param> /// <returns> /// The current citizen's flags after removing the specified flags. /// </returns> public Citizen.Flags RemoveFlags(ref Citizen citizen, Citizen.Flags flags) { var currentFlags = citizen.m_flags; currentFlags &= ~flags; return(citizen.m_flags = currentFlags); }
/// <summary>Adds the specified flags to a citizen.</summary> /// <param name="citizen">The citizen to add flags to.</param> /// <param name="flags">The flags to add.</param> /// <returns>The current citizen's flags after adding the specified flags.</returns> public Citizen.Flags AddFlags(ref Citizen citizen, Citizen.Flags flags) { var currentFlags = citizen.m_flags; currentFlags |= flags; return(citizen.m_flags = currentFlags); }
public bool CheckCitizenFlags(uint citizenId, Citizen.Flags flagMask, Citizen.Flags?expectedResult = default(Citizen.Flags?)) { bool ret = false; ProcessCitizen(citizenId, delegate(uint cId, ref Citizen citizen) { ret = LogicUtil.CheckFlags((uint)citizen.m_flags, (uint)flagMask, (uint?)expectedResult); return(true); }); return(ret); }
/// <summary> /// Check citizen flags contain at least one of the flags in <paramref name="flagMask"/>. /// </summary> /// /// <param name="citizenId">The id of the citizen to inspect.</param> /// <param name="flagMask">The flags to test.</param> /// <param name="expectedResult">If specified, ensure only the expected flags are found.</param> /// /// <returns>Returns <c>true</c> if the test passes, otherwise <c>false</c>.</returns> public bool CheckCitizenFlags(uint citizenId, Citizen.Flags flagMask, Citizen.Flags?expectedResult = null) { Citizen.Flags result = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].m_flags & flagMask; return(expectedResult == null ? result != 0 : result == expectedResult); }
/// <summary>Reads the data set to the specified <see cref="Stream" />.</summary> /// <param name="target">A <see cref="Stream" /> to write the data set to.</param> void IStorageData.StoreData(Stream target) { byte[] buffer = new byte[CitizenSchedule.DataRecordSize]; long referenceTime = timeInfo.Now.Date.Ticks; for (int i = 0; i < citizens.Length; ++i) { Citizen.Flags flags = citizens[i].m_flags; if ((flags & Citizen.Flags.Created) == 0 || (flags & Citizen.Flags.DummyTraffic) != 0) { continue; } residentSchedules[i].Write(buffer, referenceTime); target.Write(buffer, 0, buffer.Length); } }
public static void Citizens( QueryHandler <Citizen, uint> h, Citizen.Flags flags = Citizen.Flags.Created ) { var mgr = Singleton <Cities::CitizenManager> .instance; for (int i = 0; i < mgr.m_citizens.m_size; ++i) { if ((mgr.m_citizens.m_buffer[i].m_flags & flags) == Citizen.Flags.None) { continue; } if (!h.Invoke(ref mgr.m_citizens.m_buffer[i], (uint)i)) { return; } } }
/// <summary>Reads the data set from the specified <see cref="Stream" />.</summary> /// <param name="source">A <see cref="Stream" /> to read the data set from.</param> void IStorageData.ReadData(Stream source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } byte[] buffer = new byte[CitizenSchedule.DataRecordSize]; long referenceTime = timeInfo.Now.Date.Ticks; for (int i = 0; i < citizens.Length; ++i) { Citizen.Flags flags = citizens[i].m_flags; if ((flags & Citizen.Flags.Created) == 0 || (flags & Citizen.Flags.DummyTraffic) != 0) { continue; } source.Read(buffer, 0, buffer.Length); residentSchedules[i].Read(buffer, referenceTime); } }
public bool HasFlags(ref Citizen citizen, Citizen.Flags flags) { return((citizen.m_flags & flags) != 0); }
/// <summary> /// Determines whether the specified citizen has particular flags. /// </summary> /// <param name="citizen">The citizen to check flags of.</param> /// <param name="flags">The flags to check.</param> /// <returns> /// <c>true</c> if the citizen has any of the specified flags; otherwise, <c>false</c>. /// </returns> public bool HasFlags(ref Citizen citizen, Citizen.Flags flags) => (citizen.m_flags & flags) != 0;
internal static bool IsFlagSet(this Citizen.Flags value, Citizen.Flags flag) => (value & flag) != 0;
public void CustomSimulationStep(ushort instanceId, ref CitizenInstance instanceData, Vector3 physicsLodRefPos) { #if DEBUG bool citizenDebug = (DebugSettings.CitizenInstanceId == 0 || DebugSettings.CitizenInstanceId == instanceId) && (DebugSettings.CitizenId == 0 || DebugSettings.CitizenId == instanceData.m_citizen) && (DebugSettings.SourceBuildingId == 0 || DebugSettings.SourceBuildingId == instanceData.m_sourceBuilding) && (DebugSettings.TargetBuildingId == 0 || DebugSettings.TargetBuildingId == instanceData.m_targetBuilding); bool logParkingAi = DebugSwitch.BasicParkingAILog.Get() && citizenDebug; #else var logParkingAi = false; #endif CitizenManager citizenManager = Singleton <CitizenManager> .instance; uint citizenId = instanceData.m_citizen; if ((instanceData.m_flags & (CitizenInstance.Flags.Blown | CitizenInstance.Flags.Floating)) != CitizenInstance.Flags.None && (instanceData.m_flags & CitizenInstance.Flags.Character) == CitizenInstance.Flags.None) { citizenManager.ReleaseCitizenInstance(instanceId); if (citizenId != 0u) { citizenManager.ReleaseCitizen(citizenId); } return; } Citizen[] citizensBuffer = citizenManager.m_citizens.m_buffer; if ((instanceData.m_flags & CitizenInstance.Flags.WaitingPath) != CitizenInstance.Flags.None) { PathManager pathManager = Singleton <PathManager> .instance; byte pathFindFlags = pathManager.m_pathUnits.m_buffer[instanceData.m_path].m_pathFindFlags; // NON-STOCK CODE START ExtPathState mainPathState = ExtPathState.Calculating; if ((pathFindFlags & PathUnit.FLAG_FAILED) != 0 || instanceData.m_path == 0) { mainPathState = ExtPathState.Failed; } else if ((pathFindFlags & PathUnit.FLAG_READY) != 0) { mainPathState = ExtPathState.Ready; } if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + $"Path: {instanceData.m_path}, mainPathState={mainPathState}"); } ExtSoftPathState finalPathState; using (var bm = Benchmark.MaybeCreateBenchmark( null, "ConvertPathStateToSoftPathState+UpdateCitizenPathState")) { finalPathState = ExtCitizenInstance.ConvertPathStateToSoftPathState(mainPathState); if (Options.parkingAI) { finalPathState = AdvancedParkingManager.Instance.UpdateCitizenPathState( instanceId, ref instanceData, ref ExtCitizenInstanceManager .Instance.ExtInstances[ instanceId], ref ExtCitizenManager .Instance.ExtCitizens[ citizenId], ref citizensBuffer[ instanceData.m_citizen], mainPathState); if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + $"Applied Parking AI logic. Path: {instanceData.m_path}, " + $"mainPathState={mainPathState}, finalPathState={finalPathState}, " + $"extCitizenInstance={ExtCitizenInstanceManager.Instance.ExtInstances[instanceId]}"); } } // if Options.parkingAi } switch (finalPathState) { case ExtSoftPathState.Ready: { if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): Path-finding " + $"succeeded for citizen instance {instanceId} " + $"(finalPathState={finalPathState}). Path: {instanceData.m_path} " + "-- calling HumanAI.PathfindSuccess"); } if (citizenId == 0 || citizensBuffer[instanceData.m_citizen].m_vehicle == 0) { Spawn(instanceId, ref instanceData); } instanceData.m_pathPositionIndex = 255; instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath; instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering); // NON-STOCK CODE START (transferred from ResidentAI.PathfindSuccess) const Citizen.Flags CTZ_MASK = Citizen.Flags.Tourist | Citizen.Flags.MovingIn | Citizen.Flags.DummyTraffic; if (citizenId != 0 && (citizensBuffer[citizenId].m_flags & CTZ_MASK) == Citizen.Flags.MovingIn) { StatisticBase statisticBase = Singleton <StatisticsManager> .instance.Acquire <StatisticInt32>(StatisticType.MoveRate); statisticBase.Add(1); } // NON-STOCK CODE END PathfindSuccess(instanceId, ref instanceData); break; } case ExtSoftPathState.Ignore: { if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + "Path-finding result shall be ignored for citizen instance " + $"{instanceId} (finalPathState={finalPathState}). " + $"Path: {instanceData.m_path} -- ignoring"); } return; } case ExtSoftPathState.Calculating: default: { if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + $"Path-finding result undetermined for citizen instance {instanceId} " + $"(finalPathState={finalPathState}). " + $"Path: {instanceData.m_path} -- continue"); } break; } case ExtSoftPathState.FailedHard: { if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + $"HARD path-finding failure for citizen instance {instanceId} " + $"(finalPathState={finalPathState}). Path: {instanceData.m_path} " + "-- calling HumanAI.PathfindFailure"); } instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath; instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering); Singleton <PathManager> .instance.ReleasePath(instanceData.m_path); instanceData.m_path = 0u; PathfindFailure(instanceId, ref instanceData); return; } case ExtSoftPathState.FailedSoft: { if (logParkingAi) { Log._Debug( $"CustomHumanAI.CustomSimulationStep({instanceId}): " + $"SOFT path-finding failure for citizen instance {instanceId} " + $"(finalPathState={finalPathState}). Path: {instanceData.m_path} " + "-- calling HumanAI.InvalidPath"); } // path mode has been updated, repeat path-finding instanceData.m_flags &= ~CitizenInstance.Flags.WaitingPath; instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown | CitizenInstance.Flags.Cheering); InvalidPath(instanceId, ref instanceData); break; } } // NON-STOCK CODE END } // NON-STOCK CODE START using (var bm = Benchmark.MaybeCreateBenchmark(null, "ExtSimulationStep")) { if (Options.parkingAI) { if (ExtSimulationStep( instanceId, ref instanceData, ref ExtCitizenInstanceManager.Instance.ExtInstances[instanceId], physicsLodRefPos)) { return; } } } // NON-STOCK CODE END base.SimulationStep(instanceId, ref instanceData, physicsLodRefPos); VehicleManager vehicleManager = Singleton <VehicleManager> .instance; ushort vehicleId = 0; if (instanceData.m_citizen != 0u) { vehicleId = citizensBuffer[instanceData.m_citizen].m_vehicle; } if (vehicleId != 0) { Vehicle[] vehiclesBuffer = vehicleManager.m_vehicles.m_buffer; VehicleInfo vehicleInfo = vehiclesBuffer[vehicleId].Info; if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle) { vehicleInfo.m_vehicleAI.SimulationStep( vehicleId, ref vehiclesBuffer[vehicleId], vehicleId, ref vehiclesBuffer[vehicleId], 0); vehicleId = 0; } } if (vehicleId != 0 || (instanceData.m_flags & (CitizenInstance.Flags.Character | CitizenInstance.Flags.WaitingPath | CitizenInstance.Flags.Blown | CitizenInstance.Flags.Floating)) != CitizenInstance.Flags.None) { return; } instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown); ArriveAtDestination(instanceId, ref instanceData, false); citizenManager.ReleaseCitizenInstance(instanceId); }
public static int ProcessCitizenSalary(uint citizenId, bool checkOnly) { int salary = 0; if (citizenId != 0u) { Citizen.Flags citizenFlag = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].m_flags; if ((citizenFlag & Citizen.Flags.Student) != Citizen.Flags.None) { return(salary); } ushort workBuilding = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].m_workBuilding; if (workBuilding != 0u) { Building buildingData = Singleton <BuildingManager> .instance.m_buildings.m_buffer[workBuilding]; if (!IsGoverment(workBuilding)) { salary = BuildingData.buildingWorkCount[workBuilding]; if (!checkOnly) { if (buildingData.Info.m_class.m_service != ItemClass.Service.Office) { BuildingData.buildingMoney[workBuilding] -= salary; } } } else { //Goverment int aliveWorkCount = 0; int totalWorkCount = 0; Citizen.BehaviourData behaviour = default; RealCityCommonBuildingAI.InitDelegate(); RealCityCommonBuildingAI.GetWorkBehaviour((CommonBuildingAI)buildingData.Info.m_buildingAI, workBuilding, ref buildingData, ref behaviour, ref aliveWorkCount, ref totalWorkCount); int salaryMax = 0; switch (Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].EducationLevel) { case Citizen.Education.Uneducated: salaryMax = (int)(MainDataStore.govermentSalary * 0.5); salary = MainDataStore.govermentEducation0SalaryFixed; break; case Citizen.Education.OneSchool: salaryMax = (int)(MainDataStore.govermentSalary * 0.55); salary = MainDataStore.govermentEducation1SalaryFixed; break; case Citizen.Education.TwoSchools: salaryMax = (int)(MainDataStore.govermentSalary * 0.65); salary = MainDataStore.govermentEducation2SalaryFixed; break; case Citizen.Education.ThreeSchools: salaryMax = (int)(MainDataStore.govermentSalary * 0.8); salary = MainDataStore.govermentEducation3SalaryFixed; break; } int allWorkCount = 0; //Update to see if there is building workplace change. //If a building have 10 workers and have 100 workplacecount, we assume that the other 90 vitual workers are from outside //Which will give addition cost allWorkCount = TotalWorkCount(workBuilding, buildingData, false, false); if (totalWorkCount > allWorkCount) { Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenId].SetWorkplace(citizenId, 0, 0u); } float vitualWorkersRatio = (totalWorkCount != 0) ? (allWorkCount / (float)totalWorkCount) : 1f; //Budget offset for Salary int budget = Singleton <EconomyManager> .instance.GetBudget(buildingData.Info.m_class); salary = (int)(salary * budget / 100f); salary = Math.Max(salary, salaryMax); #if Debug DebugLog.LogToFileOnly("DebugInfo: LandPrice offset for Salary is " + landPriceOffset.ToString()); #endif salary = UniqueFacultyAI.IncreaseByBonus(UniqueFacultyAI.FacultyBonus.Science, salary); if (!checkOnly) { var m_class = Singleton <BuildingManager> .instance.m_buildings.m_buffer[workBuilding].Info.m_class; Singleton <EconomyManager> .instance.FetchResource((EconomyManager.Resource) 16, (int)(salary * vitualWorkersRatio), m_class); MainDataStore.outsideTouristMoney += (salary * (vitualWorkersRatio - 1f) * MainDataStore.outsideTouristSalaryProfitRatio); } } } } return(salary); } //public
// Local reference. /// <summary> /// Harmony Prefix patch to CitizenManager.SimulationStepImpl, to detect and remove any citizens in the building that don't have the 'created' flag set. /// </summary> /// <param name="__instance">Instance reference</param> /// <param name="subStep">Simulation cycle substep.</param> public static void Prefix(CitizenManager __instance, int subStep) { // Don't do anything when subStep is zero. if (subStep != 0) { // Local references. Citizen[] citizenBuffer = __instance.m_citizens.m_buffer; CitizenUnit[] citizenUnits = __instance.m_units.m_buffer; // Get current framecount to align with parent method's frame, so we avoid unnecessary cache misses. uint frameCount = Singleton <SimulationManager> .instance.m_currentFrameIndex & 0xFFF; uint currentFrame = frameCount * 128; uint baseUnit = currentFrame + (stepCount * 8); uint endUnit = baseUnit + 7; // Increment our step counter when frameCount wraps back to zero (evey 4096 increments). if (frameCount == 0) { ++stepCount; // If our step counter is greater than 15, wrap back to zero. if (stepCount > 15) { stepCount = 0; } } // Iterate through next 8 units in this frame. for (uint currentUnit = baseUnit; currentUnit <= endUnit; ++currentUnit) { // Only interested in home units. if ((citizenUnits[currentUnit].m_flags & CitizenUnit.Flags.Home) != 0 && citizenUnits[currentUnit].m_building != 0) { // Check for citizens with invalid flags in this household. uint thisCitizen = citizenUnits[currentUnit].m_citizen0; if (thisCitizen != 0) { Citizen.Flags citizenFlags = citizenBuffer[thisCitizen].m_flags; if ((citizenFlags & Citizen.Flags.Created) == 0) { RemoveCitizen(__instance, ref citizenUnits[currentUnit].m_citizen0, currentUnit, citizenUnits[currentUnit].m_building, citizenFlags); } } thisCitizen = citizenUnits[currentUnit].m_citizen1; if (thisCitizen != 0) { Citizen.Flags citizenFlags = citizenBuffer[thisCitizen].m_flags; if ((citizenFlags & Citizen.Flags.Created) == 0) { RemoveCitizen(__instance, ref citizenUnits[currentUnit].m_citizen1, currentUnit, citizenUnits[currentUnit].m_building, citizenFlags); } } thisCitizen = citizenUnits[currentUnit].m_citizen2; if (thisCitizen != 0) { Citizen.Flags citizenFlags = citizenBuffer[thisCitizen].m_flags; if ((citizenFlags & Citizen.Flags.Created) == 0) { RemoveCitizen(__instance, ref citizenUnits[currentUnit].m_citizen2, currentUnit, citizenUnits[currentUnit].m_building, citizenFlags); } } thisCitizen = citizenUnits[currentUnit].m_citizen3; if (thisCitizen != 0) { Citizen.Flags citizenFlags = citizenBuffer[thisCitizen].m_flags; if ((citizenFlags & Citizen.Flags.Created) == 0) { RemoveCitizen(__instance, ref citizenUnits[currentUnit].m_citizen3, currentUnit, citizenUnits[currentUnit].m_building, citizenFlags); } } thisCitizen = citizenUnits[currentUnit].m_citizen4; if (thisCitizen != 0) { Citizen.Flags citizenFlags = citizenBuffer[thisCitizen].m_flags; if ((citizenFlags & Citizen.Flags.Created) == 0) { RemoveCitizen(__instance, ref citizenUnits[currentUnit].m_citizen4, currentUnit, citizenUnits[currentUnit].m_building, citizenFlags); } } } } } }
/// <summary> /// Removes a citizen with invalid flags. /// </summary> /// <param name="citizenManager">CitizenManager instance reference</param> /// <param name="citizenID">Citizen ID to remove</param> /// <param name="citizenUnit">Owning CitizenUnit ID</param> /// <param name="buildingID">Home building ID</param> /// <param name="flags">Citizen flags</param> private static void RemoveCitizen(CitizenManager citizenManager, ref uint citizenID, uint citizenUnit, ushort buildingID, Citizen.Flags flags) { // Log messaged. Logging.Message("found citizen ", citizenID.ToString(), " in unit ", citizenUnit.ToString(), " of building ", buildingID.ToString(), " with invalid flags ", flags.ToString()); // Remove citizen and reset reference in CitizenUnit. citizenManager.ReleaseCitizen(citizenID); citizenID = 0; }