Пример #1
0
        private void CreateFireman(ushort vehicleID, ref Vehicle data, Citizen.AgePhase agePhase)
        {
            SimulationManager instance         = Singleton <SimulationManager> .instance;
            CitizenManager    instance2        = Singleton <CitizenManager> .instance;
            CitizenInfo       groupCitizenInfo = instance2.GetGroupCitizenInfo(ref instance.m_randomizer, this.m_info.m_class.m_service, Citizen.Gender.Male, Citizen.SubCulture.Generic, agePhase);

            if (groupCitizenInfo != null)
            {
                int  family = instance.m_randomizer.Int32(256u);
                uint num    = 0u;
                if (instance2.CreateCitizen(out num, 90, family, ref instance.m_randomizer, groupCitizenInfo.m_gender))
                {
                    ushort num2;
                    if (instance2.CreateCitizenInstance(out num2, ref instance.m_randomizer, groupCitizenInfo, num))
                    {
                        Vector3 randomDoorPosition = data.GetRandomDoorPosition(ref instance.m_randomizer, VehicleInfo.DoorType.Exit);
                        groupCitizenInfo.m_citizenAI.SetCurrentVehicle(num2, ref instance2.m_instances.m_buffer[(int)num2], 0, 0u, randomDoorPosition);
                        groupCitizenInfo.m_citizenAI.SetTarget(num2, ref instance2.m_instances.m_buffer[(int)num2], data.m_targetBuilding);
                        instance2.m_citizens.m_buffer[(int)((UIntPtr)num)].SetVehicle(num, vehicleID, 0u);
                    }
                    else
                    {
                        instance2.ReleaseCitizen(num);
                    }
                }
            }
        }
        /// <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;
        }
Пример #3
0
        public static void UpdateLocation(ResidentAI resident, uint citizenID, ref Citizen data)
        {
            try
            {
                CitizenManager _citizenManager = Singleton <CitizenManager> .instance;

                if (data.m_homeBuilding == 0 && data.m_workBuilding == 0 && data.m_visitBuilding == 0 && data.m_instance == 0 && data.m_vehicle == 0)
                {
                    _citizenManager.ReleaseCitizen(citizenID);
                }
                else
                {
                    bool goodsSatisfied = false;

                    switch (data.CurrentLocation)
                    {
                    case Citizen.Location.Home:
                        goodsSatisfied = ResidentLocationHandler.ProcessHome(ref resident, citizenID, ref data);
                        break;

                    case Citizen.Location.Work:
                        goodsSatisfied = ResidentLocationHandler.ProcessWork(ref resident, citizenID, ref data);
                        break;

                    case Citizen.Location.Visit:
                        goodsSatisfied = ResidentLocationHandler.ProcessVisit(ref resident, citizenID, ref data);
                        break;

                    case Citizen.Location.Moving:
                        goodsSatisfied = ResidentLocationHandler.ProcessMoving(ref resident, citizenID, ref data);
                        break;
                    }

                    if (goodsSatisfied)
                    {
                        data.m_flags &= ~Citizen.Flags.NeedGoods;
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.LogWarning("Error on " + citizenID);
                Debug.LogException(ex);
            }
        }
Пример #4
0
        public override void OnUpdate(float realTimeDelta, float simulationTimeDelta)
        {
            _delta += simulationTimeDelta;

            if (_delta > 300) // run remover every 5 in-game minutes
            {
                _delta = 0;
                DebugOutputPanel.AddMessage(PluginManager.MessageType.Message, "iteration run");

                Citizen[] citizens = _citizenManager.m_citizens.m_buffer;

                int deadCount    = 0;
                int citizenCount = 0;

                for (uint i = 0; i < citizens.Length; i++)
                {
                    Citizen citizen = citizens[i];

                    if (citizen.m_flags != Citizen.Flags.None) // Check if citizen struct has any flags (i.e. is the citizen initialized)
                    {
                        citizenCount++;

                        if (citizen.Dead)
                        {
                            _citizenManager.ReleaseCitizen(i); // remove the citizen
                            deadCount++;
                        }
                    }
                }

                if (deadCount > 0)
                {
                    DebugOutputPanel.AddMessage(PluginManager.MessageType.Message, "Removed " + deadCount + " dead bodies out of " + citizenCount + " citizens");
                }
            }

            base.OnUpdate(realTimeDelta, simulationTimeDelta);
        }
Пример #5
0
        // copied from original private function ugh...
        private void MoveFamily(uint homeID, ref CitizenUnit data, ushort targetBuilding)
        {
            BuildingManager instance1 = Singleton <BuildingManager> .instance;
            CitizenManager  instance2 = Singleton <CitizenManager> .instance;
            uint            unitID    = 0;

            if (targetBuilding != (ushort)0)
            {
                unitID = instance1.m_buildings.m_buffer[(int)targetBuilding].GetEmptyCitizenUnit(CitizenUnit.Flags.Home);
            }
            for (int index = 0; index < 5; ++index)
            {
                uint citizen = data.GetCitizen(index);
                if (citizen != 0U && !instance2.m_citizens.m_buffer[citizen].Dead)
                {
                    instance2.m_citizens.m_buffer[citizen].SetHome(citizen, (ushort)0, unitID);
                    if (instance2.m_citizens.m_buffer[citizen].m_homeBuilding == (ushort)0)
                    {
                        instance2.ReleaseCitizen(citizen);
                    }
                }
            }
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
        public static bool ProcessHome(ref ResidentAI thisAI, uint citizenID, ref Citizen person)
        {
            CitizenManager    _citizenManager = Singleton <CitizenManager> .instance;
            SimulationManager _simulation     = Singleton <SimulationManager> .instance;

            if ((person.m_flags & Citizen.Flags.MovingIn) != Citizen.Flags.None)
            {
                _citizenManager.ReleaseCitizen(citizenID);
            }
            else if (ProcessGenerics(ref thisAI, citizenID, ref person))
            {
                if ((person.m_flags & Citizen.Flags.NeedGoods) != Citizen.Flags.None && (!Chances.WorkDay(ref person) || _simulation.m_currentDayTimeHour > Chances.m_startWorkHour)) //Wants to go shopping
                {
                    if (person.m_homeBuilding != 0 && person.m_instance == 0 && person.m_vehicle == 0)                                                                                //Person isn't already out and about
                    {
                        if (_simulation.m_isNightTime)
                        {
                            uint chance = _simulation.m_randomizer.UInt32(1000);

                            if (chance < Chances.GoOutAtNight(person.Age) && NewResidentAI.DoRandomMove(thisAI))
                            {
                                //Only go locally to find a shop at night
                                FindCloseVisitPlace(ref thisAI, citizenID, ref person, person.m_homeBuilding, 1000f);
                                return(true);
                            }
                        }
                        else if (NewResidentAI.DoRandomMove(thisAI))
                        {
                            uint chance = _simulation.m_randomizer.UInt32(100);

                            if (chance < 10)
                            {
                                uint   localChance     = _simulation.m_randomizer.UInt32(100);
                                ushort localVisitPlace = 0;

                                if (ExperimentsToggle.AllowLocalBuildingSearch && localChance < ExperimentsToggle.LocalBuildingPercentage)
                                {
                                    LoggingWrapper.Log("Citizen " + citizenID + " trying to find a local commercial building.");
                                    localVisitPlace = FindCloseVisitPlace(ref thisAI, citizenID, ref person, person.m_homeBuilding, 1000f);
                                }

                                if (localVisitPlace == 0)
                                {
                                    LoggingWrapper.Log("Citizen " + citizenID + " going to a random commercial building.");
                                    NewResidentAI.FindVisitPlace(thisAI, citizenID, person.m_homeBuilding, NewResidentAI.GetShoppingReason(thisAI));
                                }
                                return(true);
                            }
                        }
                    }
                }
                else if (person.m_homeBuilding != 0 && person.m_instance != 0 && person.m_vehicle == 0 || NewResidentAI.DoRandomMove(thisAI)) //If the person is already out and about, or can move (based on entities already visible)
                {
                    int eventId = CityEventManager.instance.EventStartsWithin(citizenID, ref person, StartMovingToEventTime);

                    if (eventId != -1)
                    {
                        CityEvent _cityEvent = CityEventManager.instance.m_nextEvents[eventId];

                        if (_cityEvent.EventStartsWithin(StartMovingToEventTime) && !_cityEvent.EventStartsWithin(MaxMoveToEventTime))
                        {
                            if ((person.m_instance != 0 || NewResidentAI.DoRandomMove(thisAI)) && _cityEvent.Register(citizenID, ref person))
                            {
                                NewResidentAI.StartMoving(thisAI, citizenID, ref person, person.m_homeBuilding, _cityEvent.m_eventData.m_eventBuilding);
                                person.SetVisitplace(citizenID, _cityEvent.m_eventData.m_eventBuilding, 0U);
                                person.m_visitBuilding = _cityEvent.m_eventData.m_eventBuilding;

                                return(true);
                            }
                        }
                    }
                    else
                    {
                        if (person.m_workBuilding != 0 && !_simulation.m_isNightTime && !Chances.ShouldReturnFromWork(ref person))
                        {
                            if (Chances.ShouldGoToWork(ref person))
                            {
                                NewResidentAI.StartMoving(thisAI, citizenID, ref person, person.m_homeBuilding, person.m_workBuilding);
                                return(true);
                            }
                        }
                        else
                        {
                            if (Chances.ShouldGoFindEntertainment(ref person))
                            {
                                if (_simulation.m_isNightTime)
                                {
                                    FindLeisure(ref thisAI, citizenID, ref person, person.m_homeBuilding);
                                }
                                else
                                {
                                    NewResidentAI.FindVisitPlace(thisAI, citizenID, person.m_homeBuilding, NewResidentAI.GetEntertainmentReason(thisAI));
                                }

                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
        int failedTimes;         // how many times creation of tourists has failed


        public void Update()  // called every frame by UnityEngine
        {
            // create tourists every minute, perhaps choose at which outside connections to create them
            // PROBABLY NOT spawn vehicles at outside connections more frequently, with reference to in game time?
            // TODO: Space Elevator NOT CONSIDERED!!!!!
            Debug.Log("Update() called by unity engine");

            if (DataStorage.instance.modifierType == TourismIncreaseType.PopulationSizeRelated)
            {
                if (Utils.ComponentActionRequired)
                {
                    ushort[] carConnections   = Utils.GetConnectedOutsideConnections(ItemClass.SubService.None); // ItemClass.Service.Road
                    ushort[] trainConnections = Utils.GetConnectedOutsideConnections(ItemClass.SubService.PublicTransportTrain);
                    ushort[] planeConnections = Utils.GetConnectedOutsideConnections(ItemClass.SubService.PublicTransportPlane);
                    ushort[] shipConnections  = Utils.GetConnectedOutsideConnections(ItemClass.SubService.PublicTransportShip);

                    // use avg land value to calculate the probability (percentage) of different modes of transport
                    int avgLandValue = Singleton <DistrictManager> .instance.m_districts.m_buffer[0].GetLandValue();

                    int planeProb = planeConnections.Length == 0 ? 0 : 100 * avgLandValue / (avgLandValue + 40);
                    int trainProb = trainConnections.Length == 0 ? 0 : planeProb == 0 ? ((100 - planeProb) * avgLandValue / (avgLandValue + 10)) / 2 : ((100 - planeProb) * avgLandValue / (avgLandValue + 15)) / 2;  // ship and train prob, maybe just divide by 2 for each of these
                    int shipProb  = 0;

                    if (trainProb == 0)
                    {
                        if (!(shipConnections.Length == 0))  // no train connections, do have ship connections
                        {
                            shipProb = planeProb == 0 ? ((100 - planeProb) * avgLandValue / (avgLandValue + 10)) : ((100 - planeProb) * avgLandValue / (avgLandValue + 15));
                        }
                    }
                    else
                    {
                        if (!(shipConnections.Length == 0))
                        {
                            shipProb = trainProb;
                        }
                        else  // have train connections but no ship connections
                        {
                            trainProb *= 2;
                        }
                    }

                    int carProb = 100 - (planeProb + trainProb + shipProb);  // would be pretty low even when land value is quite low


                    //int trainProb = trainConnections.Length == 0 ? 0 : 100 - 100 * (avgLandValue / (avgLandValue + 25));  // TODO: maybe customize this
                    //int shipProb = shipConnections.Length == 0 ? 0 : (100 - trainProb) - (100 - trainProb) * (avgLandValue / (avgLandValue + 30));
                    //int planeProb = 100 - (trainProb + shipProb);


                    float amountOfTouristsThisMinute = DataStorage.instance.amountOfTouristsThisMinute;
                    int   amount = (int)Math.Truncate(amountOfTouristsThisMinute);
                    amount += (float)random.NextDouble() < amountOfTouristsThisMinute - amount ? 1 : 0;
                    amount += createTouristFailed;

                    Debug.Log(string.Format("amount of tourists to create decided: {0}", amount));

                    int i;  // for debug purpose
                    for (i = 0; i < amount; ++i)
                    {
                        // decide which type of outside connection they are going to spawn at, hence decide the wealth level accordingly
                        ItemClass.SubService typeOfTransport = ItemClass.SubService.PublicTransportPlane;
                        int prob = randomizer.Int32(1, 100);
                        if (prob < carProb)
                        {
                            typeOfTransport = ItemClass.SubService.None;
                        }
                        else if (prob < trainProb + shipProb)
                        {
                            typeOfTransport = randomizer.Int32(2) < 1 ? ItemClass.SubService.PublicTransportTrain : ItemClass.SubService.PublicTransportShip;
                        }
                        // else it's plane


                        // decide the wealth of the tourist based on which type of outside connection it will come from
                        Citizen.Wealth wealth = Citizen.Wealth.Low;
                        if (typeOfTransport == ItemClass.SubService.PublicTransportPlane)
                        {
                            int rand = randomizer.Int32(100);
                            wealth = rand > 18 ? Citizen.Wealth.High : Citizen.Wealth.Medium;
                        }
                        else if (typeOfTransport == ItemClass.SubService.PublicTransportTrain)
                        {
                            int rand = randomizer.Int32(100);
                            wealth = rand > 80 ? Citizen.Wealth.High : rand > 40 ? Citizen.Wealth.Medium : Citizen.Wealth.Low;
                        }
                        else if (typeOfTransport == ItemClass.SubService.PublicTransportShip)
                        {
                            int rand = randomizer.Int32(100);
                            wealth = rand > 70 ? Citizen.Wealth.High : rand > 25 ? Citizen.Wealth.Medium : Citizen.Wealth.Low;
                        }
                        else  // roads, ItemClass.SubService.None
                        {
                            int rand = randomizer.Int32(100);
                            wealth = rand > 70 ? Citizen.Wealth.High : rand > 30 ? Citizen.Wealth.Medium : Citizen.Wealth.Low;
                        }


                        // randomly choose which sourceBuilding aka the outside connection building the tourist is coming from
                        ushort sourceBuilding = 0;

                        try
                        {
                            switch (typeOfTransport)
                            {
                            case ItemClass.SubService.PublicTransportPlane:
                                sourceBuilding = planeConnections[randomizer.Int32(Convert.ToUInt32(planeConnections.Length))];
                                break;

                            case ItemClass.SubService.PublicTransportTrain:
                                sourceBuilding = trainConnections[randomizer.Int32(Convert.ToUInt32(trainConnections.Length))];
                                break;

                            case ItemClass.SubService.PublicTransportShip:
                                sourceBuilding = shipConnections[randomizer.Int32(Convert.ToUInt32(shipConnections.Length))];
                                break;

                            default:      // road connections
                                sourceBuilding = carConnections[randomizer.Int32(Convert.ToUInt32(carConnections.Length))];
                                break;
                            }
                            Debug.Log("will be spawned at this outside connection: " + sourceBuilding);
                        }
                        catch
                        {
                            Debug.Log("choosing connection building has thrown an exception");
                        }


                        TransferManager.TransferReason transferReason = NewTouristAI.GetRandomTransferReason(0);
                        TransferManager.TransferOffer  offer          = Utils.FindOffer(transferReason, true);
                        ushort targetBuilding = offer.Building;
                        Debug.Log(string.Format("component found building {0} for new tourist", targetBuilding));
                        uint unitID = buildingManager.m_buildings.m_buffer[targetBuilding].GetEmptyCitizenUnit(CitizenUnit.Flags.Visit);
                        int  family = Singleton <SimulationManager> .instance.m_randomizer.Int32(256U);

                        int age = Singleton <SimulationManager> .instance.m_randomizer.Int32(0, 240);

                        if (citizenManager.CreateCitizen(out uint citizen, age, family, ref Singleton <SimulationManager> .instance.m_randomizer))
                        {
                            citizenManager.m_citizens.m_buffer[citizen].m_flags    |= Citizen.Flags.Tourist;
                            citizenManager.m_citizens.m_buffer[citizen].m_flags    |= Citizen.Flags.MovingIn;
                            citizenManager.m_citizens.m_buffer[citizen].WealthLevel = wealth;
                            citizenManager.m_citizens.m_buffer[citizen].SetVisitplace(citizen, (ushort)0, unitID);
                            CitizenInfo citizenInfo = citizenManager.m_citizens.m_buffer[citizen].GetCitizenInfo(citizen);
                            if (citizenInfo != null && citizenManager.CreateCitizenInstance(out ushort citizenInstance, ref Singleton <SimulationManager> .instance.m_randomizer, citizenInfo, citizen))
                            {
                                citizenInfo.m_citizenAI.SetSource(citizenInstance, ref citizenManager.m_instances.m_buffer[(int)citizenInstance], sourceBuilding);
                                citizenInfo.m_citizenAI.SetTarget(citizenInstance, ref citizenManager.m_instances.m_buffer[(int)citizenInstance], targetBuilding, false);
                                citizenManager.m_citizens.m_buffer[citizen].CurrentLocation = Citizen.Location.Moving;
                                Singleton <StatisticsManager> .instance.Acquire <StatisticArray>(StatisticType.IncomingTourists).Acquire <StatisticInt32>((int)wealth, 3).Add(1);
                            }
                            else
                            {
                                failedTimes         += 1;
                                createTouristFailed += amount - i;
                                citizenManager.ReleaseCitizen(citizen);
                                break;
                            }
                        }
                        else
                        {
                            failedTimes         += 1;
                            createTouristFailed += amount - i;
                            break;
                        }
                    }
                    Debug.Log(i + " amount of tourists created in this loop");
                }
            }
        }
Пример #9
0
        private void ProcessHumansUpdated()
        {
            SkylinesOverwatch.Data data = SkylinesOverwatch.Data.Instance;
            uint[] humans = data.HumansUpdated;

            if (humans.Length == 0)
            {
                return;
            }

            CitizenManager instance = Singleton <CitizenManager> .instance;

            foreach (uint i in humans)
            {
                if (!data.IsResident(i))
                {
                    continue;
                }

                Citizen[] residents = instance.m_citizens.m_buffer;
                Citizen   resident  = residents[(int)i];

                if (resident.Dead)
                {
                    continue;
                }

                if ((resident.m_flags & Citizen.Flags.Created) == Citizen.Flags.None)
                {
                    continue;
                }

                if ((resident.m_flags & Citizen.Flags.DummyTraffic) != Citizen.Flags.None)
                {
                    continue;
                }

                if (!Kill(resident))
                {
                    continue;
                }

                residents[(int)i].Sick = false;
                residents[(int)i].Dead = true;
                residents[(int)i].SetParkedVehicle(i, 0);

                ushort home = resident.GetBuildingByLocation();

                if (home == 0)
                {
                    home = resident.m_homeBuilding;
                }

                if (home != 0)
                {
                    DistrictManager dm = Singleton <DistrictManager> .instance;

                    Vector3 position = Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)home].m_position;

                    byte district = dm.GetDistrict(position);

                    District[] buffer = dm.m_districts.m_buffer;
                    buffer[(int)district].m_deathData.m_tempCount = buffer[(int)district].m_deathData.m_tempCount + 1;
                }

                if (_randomizer.Int32(2) == 0)
                {
                    instance.ReleaseCitizen(i);
                }

                SkylinesOverwatch.Helper.Instance.RequestHumanRemoval(i);
            }
        }
Пример #10
0
        protected override void ProduceGoods(ushort buildingID, ref Building buildingData, ref Building.Frame frameData, int productionRate, int finalProductionRate, ref Citizen.BehaviourData behaviour, int aliveWorkerCount, int totalWorkerCount, int workPlaceCount, int aliveVisitorCount, int totalVisitorCount, int visitPlaceCount)
        {
            base.ProduceGoods(buildingID, ref buildingData, ref frameData, productionRate, finalProductionRate, ref behaviour, aliveWorkerCount, totalWorkerCount, workPlaceCount, aliveVisitorCount, totalVisitorCount, visitPlaceCount);
            int num = productionRate * m_deathCareAccumulation / 100;

            if (num != 0)
            {
                Singleton <ImmaterialResourceManager> .instance.AddResource(ImmaterialResourceManager.Resource.DeathCare, num, buildingData.m_position, m_deathCareRadius);
            }
            if (finalProductionRate != 0)
            {
                int            num2     = buildingData.m_customBuffer1;
                int            num3     = (m_burialRate * finalProductionRate * 100 + m_corpseCapacity - 1) / m_corpseCapacity;
                CitizenManager instance = Singleton <CitizenManager> .instance;
                uint           num4     = buildingData.m_citizenUnits;
                int            num5     = 0;
                int            num6     = 0;
                int            num7     = 0;
                while (num4 != 0)
                {
                    uint nextUnit = instance.m_units.m_buffer[num4].m_nextUnit;
                    if ((instance.m_units.m_buffer[num4].m_flags & CitizenUnit.Flags.Visit) != 0)
                    {
                        for (int i = 0; i < 5; i++)
                        {
                            uint citizen = instance.m_units.m_buffer[num4].GetCitizen(i);
                            if (citizen != 0)
                            {
                                if (instance.m_citizens.m_buffer[citizen].Dead)
                                {
                                    if (instance.m_citizens.m_buffer[citizen].CurrentLocation == Citizen.Location.Visit)
                                    {
                                        if (Singleton <SimulationManager> .instance.m_randomizer.Int32(10000u) < num3)
                                        {
                                            instance.ReleaseCitizen(citizen);
                                            num7++;
                                            num2++;
                                        }
                                        else
                                        {
                                            num6++;
                                        }
                                    }
                                    else
                                    {
                                        num6++;
                                    }
                                }
                                else if (instance.m_citizens.m_buffer[citizen].Sick && instance.m_citizens.m_buffer[citizen].CurrentLocation == Citizen.Location.Visit)
                                {
                                    instance.m_citizens.m_buffer[citizen].Sick = false;
                                }
                            }
                        }
                    }
                    num4 = nextUnit;
                    if (++num5 > 524288)
                    {
                        CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace);

                        break;
                    }
                }
                behaviour.m_deadCount += num6;
                if (m_graveCount == 0)
                {
                    for (int j = num7; j < num2; j++)
                    {
                        if (Singleton <SimulationManager> .instance.m_randomizer.Int32(10000u) < num3)
                        {
                            num7++;
                            num2--;
                        }
                        else
                        {
                            num6++;
                        }
                    }
                }
                buildingData.m_tempExport = (byte)Mathf.Min(buildingData.m_tempExport + num7, 255);
                DistrictManager instance2 = Singleton <DistrictManager> .instance;
                byte            district  = instance2.GetDistrict(buildingData.m_position);
                bool            flag      = IsFull(buildingID, ref buildingData);
                if (m_graveCount != 0)
                {
                    num2 = Mathf.Min(num2, m_graveCount);
                    buildingData.m_customBuffer1 = (ushort)num2;
                    instance2.m_districts.m_buffer[district].m_productionData.m_tempDeadAmount   += (uint)num2;
                    instance2.m_districts.m_buffer[district].m_productionData.m_tempDeadCapacity += (uint)m_graveCount;
                }
                else
                {
                    buildingData.m_customBuffer1 = (ushort)num2;
                    instance2.m_districts.m_buffer[district].m_productionData.m_tempCremateCapacity += (uint)m_corpseCapacity;
                }
                bool flag2 = IsFull(buildingID, ref buildingData);
                if (flag != flag2)
                {
                    if (flag2)
                    {
                        if ((object)m_fullPassMilestone != null)
                        {
                            m_fullPassMilestone.Unlock();
                        }
                    }
                    else if ((object)m_fullPassMilestone != null)
                    {
                        m_fullPassMilestone.Relock();
                    }
                }
                int count    = 0;
                int count2   = 0;
                int cargo    = 0;
                int capacity = 0;
                int outside  = 0;
                CalculateOwnVehicles(buildingID, ref buildingData, TransferManager.TransferReason.Dead, ref count, ref cargo, ref capacity, ref outside);
                CalculateGuestVehicles(buildingID, ref buildingData, TransferManager.TransferReason.DeadMove, ref count2, ref cargo, ref capacity, ref outside);
                int num8 = m_corpseCapacity - num6 - capacity;
                int num9 = (finalProductionRate * m_hearseCount + 99) / 100;
                if ((buildingData.m_flags & Building.Flags.Downgrading) != 0)
                {
                    if (m_graveCount != 0)
                    {
                        int count3    = 0;
                        int cargo2    = 0;
                        int capacity2 = 0;
                        int outside2  = 0;
                        CalculateOwnVehicles(buildingID, ref buildingData, TransferManager.TransferReason.DeadMove, ref count3, ref cargo2, ref capacity2, ref outside2);
                        if (num2 > 0 && count3 < num9)
                        {
                            TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
                            offer.Priority = 7;
                            offer.Building = buildingID;
                            offer.Position = buildingData.m_position;
                            offer.Amount   = 1;
                            offer.Active   = true;
                            Singleton <TransferManager> .instance.AddOutgoingOffer(TransferManager.TransferReason.DeadMove, offer);
                        }
                    }
                }
                else if (m_graveCount != 0)
                {
                    num8 = Mathf.Min(num8, m_graveCount - num2 - num6 - capacity + 9);
                    int num10 = num8 / 10;
                    if (count != 0)
                    {
                        num10--;
                    }
                    bool flag4 = num10 >= 1 && count < num9 && (num10 > 1);

                    if (flag4)
                    {
                        TransferManager.TransferOffer offer3 = default(TransferManager.TransferOffer);
                        offer3.Priority = 2 - count;
                        offer3.Building = buildingID;
                        offer3.Position = buildingData.m_position;
                        offer3.Amount   = 1;
                        offer3.Active   = true;
                        Singleton <TransferManager> .instance.AddIncomingOffer(TransferManager.TransferReason.Dead, offer3);
                    }

                    if (buildingData.m_customBuffer1 > (m_corpseCapacity * 2 / 3))
                    {
                        TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
                        offer.Priority = 0;
                        offer.Building = buildingID;
                        offer.Position = buildingData.m_position;
                        offer.Amount   = 1;
                        offer.Active   = true;
                        Singleton <TransferManager> .instance.AddOutgoingOffer(TransferManager.TransferReason.DeadMove, offer);
                    }
                }
                else
                {
                    int  num11 = num8 / 10;
                    bool flag5 = num11 >= 1 && (num11 > 1 || count >= num9 || Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0);
                    bool flag6 = num11 >= 1 && count < num9 && (num11 > 1 || !flag5);
                    if (flag5)
                    {
                        TransferManager.TransferOffer offer4 = default(TransferManager.TransferOffer);
                        offer4.Priority = Mathf.Max(1, num8 * 6 / m_corpseCapacity);
                        offer4.Building = buildingID;
                        offer4.Position = buildingData.m_position;
                        offer4.Amount   = Mathf.Max(1, num11 - 1);
                        offer4.Active   = false;
                        Singleton <TransferManager> .instance.AddIncomingOffer(TransferManager.TransferReason.DeadMove, offer4);
                    }
                    if (flag6)
                    {
                        TransferManager.TransferOffer offer5 = default(TransferManager.TransferOffer);
                        offer5.Priority = 2 - count;
                        offer5.Building = buildingID;
                        offer5.Position = buildingData.m_position;
                        offer5.Amount   = 1;
                        offer5.Active   = true;
                        Singleton <TransferManager> .instance.AddIncomingOffer(TransferManager.TransferReason.Dead, offer5);
                    }
                }
            }
        }
Пример #11
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 bool Prefix(ref bool __result, ref ResidentAI __instance, uint citizenID, ref Citizen data)
        {
            // Method result.
            bool removed = false;

            if ((citizenID % DataStore.lifeSpanMultiplier) == Threading.counter)
            {
                // Local reference.
                CitizenManager citizenManager = Singleton <CitizenManager> .instance;

                if (citizenID == 575960)
                {
                    Logging.Message("foundTarget");
                }

                int num = data.Age + 1;

                if (num <= 45)
                {
                    if (num == 15 || num == 45)
                    {
                        FinishSchoolOrWorkRev(__instance, citizenID, ref data);
                    }
                }
                else if (num == 90 || num >= ModSettings.retirementAge)
                {
                    FinishSchoolOrWorkRev(__instance, citizenID, ref data);
                }
                else if ((data.m_flags & Citizen.Flags.Student) != Citizen.Flags.None && (num % 15 == 0))  // Workspeed multiplier?
                {
                    FinishSchoolOrWorkRev(__instance, citizenID, ref data);
                }

                if ((data.m_flags & Citizen.Flags.Original) != Citizen.Flags.None)
                {
                    if (citizenManager.m_tempOldestOriginalResident < num)
                    {
                        citizenManager.m_tempOldestOriginalResident = num;
                    }
                    if (num == 240)
                    {
                        Singleton <StatisticsManager> .instance.Acquire <StatisticInt32>(StatisticType.FullLifespans).Add(1);
                    }
                }

                data.Age = num;

                // Checking for death and sickness chances.
                // Citizens who are currently moving or currently in a vehicle aren't affected.
                if (data.CurrentLocation != Citizen.Location.Moving && data.m_vehicle == 0)
                {
                    // Local reference.
                    SimulationManager simulationManager = Singleton <SimulationManager> .instance;

                    bool died = false;

                    if (ModSettings.VanillaCalcs)
                    {
                        // Using vanilla lifecycle calculations.
                        int num2 = 240;
                        int num3 = 255;
                        int num4 = Mathf.Max(0, 145 - (100 - data.m_health) * 3);
                        if (num4 != 0)
                        {
                            num2 += num4 / 3;
                            num3 += num4;
                        }
                        if (num >= num2)
                        {
                            bool flag = simulationManager.m_randomizer.Int32(2000u) < 3;
                            died = (simulationManager.m_randomizer.Int32(num2 * 100, num3 * 100) / 100 <= num || flag);
                        }
                    }
                    else
                    {
                        // Using custom lifecycle calculations.
                        // Game defines years as being age divided by 3.5.  Hence, 35 age increments per decade.
                        // Legacy mod behaviour worked on 25 increments per decade.
                        // If older than the maximum index - lucky them, but keep going using that final index.
                        int index = Math.Min((int)(num * ModSettings.decadeFactor), 10);

                        // Calculate 90% - 110%; using 100,000 as 100% (for precision).
                        int modifier = 100000 + ((150 * data.m_health) + (50 * data.m_wellbeing) - 10000);

                        // Death chance is simply if a random number between 0 and the modifier calculated above is less than the survival probability calculation for that decade of life.
                        // Also set maximum age of 400 (~114 years) to be consistent with the base game.
                        died = (simulationManager.m_randomizer.Int32(0, modifier) < DataStore.survivalProbCalc[index]) || num > 400;

                        // Check for sickness chance if they haven't died.
                        if (!died && simulationManager.m_randomizer.Int32(0, modifier) < DataStore.sicknessProbCalc[index])
                        {
                            // Make people sick, if they're unlucky.
                            data.Sick = true;

                            if (Logging.UseSicknessLog)
                            {
                                Logging.WriteToLog(Logging.SicknessLogName, "Citizen became sick with chance factor ", DataStore.sicknessProbCalc[index].ToString());
                            }
                        }
                    }

                    // Handle citizen death.
                    if (died)
                    {
                        // Check if citizen is only remaining parent and there are children.
                        uint        unitID         = data.GetContainingUnit(citizenID, Singleton <BuildingManager> .instance.m_buildings.m_buffer[data.m_homeBuilding].m_citizenUnits, CitizenUnit.Flags.Home);
                        CitizenUnit containingUnit = citizenManager.m_units.m_buffer[unitID];

                        // Log if we're doing that.
                        if (Logging.UseDeathLog)
                        {
                            Logging.WriteToLog(Logging.DeathLogName, "Killed citzen ", citizenID.ToString(), " at age ", data.Age.ToString(), " (", ((int)(data.Age / 3.5)).ToString(), " years old) with family ", containingUnit.m_citizen0.ToString(), ", " + containingUnit.m_citizen1.ToString(), ", " + containingUnit.m_citizen2.ToString(), ", ", containingUnit.m_citizen3.ToString(), ", ", containingUnit.m_citizen4.ToString());
                        }

                        // Reverse redirect to access private method Die().
                        DieRev(__instance, citizenID, ref data);

                        // If there are no adults remaining in this CitizenUnit, remove the others, as orphan households end up in simulation purgatory.
                        bool isParent     = containingUnit.m_citizen0 == citizenID || containingUnit.m_citizen1 == citizenID;
                        bool singleParent = isParent && (containingUnit.m_citizen0 == 0 || containingUnit.m_citizen1 == 0);
                        bool hasChild     = containingUnit.m_citizen2 != 0 || containingUnit.m_citizen3 != 0 || containingUnit.m_citizen4 != 0;

                        if (singleParent && hasChild)
                        {
                            for (int i = 0; i < 2; ++i)
                            {
                                uint currentChild;
                                switch (i)
                                {
                                case 0:
                                    currentChild = containingUnit.m_citizen2;
                                    break;

                                case 1:
                                    currentChild = containingUnit.m_citizen3;
                                    break;

                                default:
                                    currentChild = containingUnit.m_citizen4;
                                    break;
                                }

                                if (currentChild != 0)
                                {
                                    if (Logging.UseDeathLog)
                                    {
                                        Logging.WriteToLog(Logging.DeathLogName, "Removed orphan ", currentChild.ToString());
                                        citizenManager.ReleaseCitizen(currentChild);
                                    }
                                }
                            }
                        }

                        // Chance for 'vanishing corpse' (no need for deathcare).
                        if (!AIUtils.KeepCorpse())
                        {
                            citizenManager.ReleaseCitizen(citizenID);
                            removed = true;
                        }
                    }
                }
            }

            // Original method return value.
            __result = removed;

            // Don't execute base method after this.
            return(false);
        }
Пример #13
0
        public void CustomSimulationStep(ushort instanceID, ref CitizenInstance instanceData, Vector3 physicsLodRefPos)
        {
#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;
#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;
            }

            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 DEBUG
                if (debug)
                {
                    Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Path: {instanceData.m_path}, mainPathState={mainPathState}");
                }
#endif

                ExtSoftPathState finalPathState = ExtSoftPathState.None;
#if BENCHMARK
                using (var bm = new Benchmark(null, "ConvertPathStateToSoftPathState+UpdateCitizenPathState")) {
#endif
                finalPathState = ExtCitizenInstance.ConvertPathStateToSoftPathState(mainPathState);
                if (Options.prohibitPocketCars)
                {
                    finalPathState = AdvancedParkingManager.Instance.UpdateCitizenPathState(instanceID, ref instanceData, ref ExtCitizenInstanceManager.Instance.ExtInstances[instanceID], ref ExtCitizenManager.Instance.ExtCitizens[citizenId], ref citizenManager.m_citizens.m_buffer[instanceData.m_citizen], mainPathState);
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Applied Parking AI logic. Path: {instanceData.m_path}, mainPathState={mainPathState}, finalPathState={finalPathState}, extCitizenInstance={ExtCitizenInstanceManager.Instance.ExtInstances[instanceID]}");
                    }
#endif
                }
#if BENCHMARK
            }
#endif

                switch (finalPathState)
                {
                case ExtSoftPathState.Ready:
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Path-finding succeeded for citizen instance {instanceID} (finalPathState={finalPathState}). Path: {instanceData.m_path} -- calling HumanAI.PathfindSuccess");
                    }
#endif
                    if (citizenId == 0 || citizenManager.m_citizens.m_buffer[instanceData.m_citizen].m_vehicle == 0)
                    {
                        this.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)
                    if (citizenId != 0 && (citizenManager.m_citizens.m_buffer[citizenId].m_flags & (Citizen.Flags.Tourist | Citizen.Flags.MovingIn | Citizen.Flags.DummyTraffic)) == Citizen.Flags.MovingIn)
                    {
                        StatisticBase statisticBase = Singleton <StatisticsManager> .instance.Acquire <StatisticInt32>(StatisticType.MoveRate);

                        statisticBase.Add(1);
                    }
                    // NON-STOCK CODE END
                    this.PathfindSuccess(instanceID, ref instanceData);
                    break;

                case ExtSoftPathState.Ignore:
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Path-finding result shall be ignored for citizen instance {instanceID} (finalPathState={finalPathState}). Path: {instanceData.m_path} -- ignoring");
                    }
#endif
                    return;

                case ExtSoftPathState.Calculating:
                default:
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): Path-finding result undetermined for citizen instance {instanceID} (finalPathState={finalPathState}). Path: {instanceData.m_path} -- continue");
                    }
#endif
                    break;

                case ExtSoftPathState.FailedHard:
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): HARD path-finding failure for citizen instance {instanceID} (finalPathState={finalPathState}). Path: {instanceData.m_path} -- calling HumanAI.PathfindFailure");
                    }
#endif
                    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;
                    this.PathfindFailure(instanceID, ref instanceData);
                    return;

                case ExtSoftPathState.FailedSoft:
#if DEBUG
                    if (debug)
                    {
                        Log._Debug($"CustomHumanAI.CustomSimulationStep({instanceID}): SOFT path-finding failure for citizen instance {instanceID} (finalPathState={finalPathState}). Path: {instanceData.m_path} -- calling HumanAI.InvalidPath");
                    }
#endif
                    // 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);
                    this.InvalidPath(instanceID, ref instanceData);
                    return;
                }
                // NON-STOCK CODE END
            }

            // NON-STOCK CODE START
#if BENCHMARK
            using (var bm = new Benchmark(null, "ExtSimulationStep")) {
#endif
            if (Options.prohibitPocketCars)
            {
                if (ExtSimulationStep(instanceID, ref instanceData, ref ExtCitizenInstanceManager.Instance.ExtInstances[instanceID], physicsLodRefPos))
                {
                    return;
                }
            }
#if BENCHMARK
        }
#endif
            // NON-STOCK CODE END

            base.SimulationStep(instanceID, ref instanceData, physicsLodRefPos);

            VehicleManager vehicleManager = Singleton <VehicleManager> .instance;
            ushort vehicleId = 0;
            if (instanceData.m_citizen != 0u)
            {
                vehicleId = citizenManager.m_citizens.m_buffer[instanceData.m_citizen].m_vehicle;
            }
            if (vehicleId != 0)
            {
                VehicleInfo vehicleInfo = vehicleManager.m_vehicles.m_buffer[(int)vehicleId].Info;
                if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle)
                {
                    vehicleInfo.m_vehicleAI.SimulationStep(vehicleId, ref vehicleManager.m_vehicles.m_buffer[(int)vehicleId], vehicleId, ref vehicleManager.m_vehicles.m_buffer[(int)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)
            {
                instanceData.m_flags &= ~(CitizenInstance.Flags.HangAround | CitizenInstance.Flags.Panicking | CitizenInstance.Flags.SittingDown);
                CustomArriveAtDestination(instanceID, ref instanceData, false);
                citizenManager.ReleaseCitizenInstance(instanceID);
            }
        }