コード例 #1
0
        private void ProcessMoving(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort instanceId = CitizenProxy.GetInstance(ref citizen);
            ushort vehicleId  = CitizenProxy.GetVehicle(ref citizen);

            if (instanceId == 0)
            {
                if (vehicleId == 0)
                {
                    CitizenMgr.ReleaseCitizen(citizenId);
                }

                return;
            }

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

            if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, true))
            {
                FindRandomVisitPlace(instance, citizenId, ref citizen, TouristDoNothingProbability, 0);
            }
        }
コード例 #2
0
        private void ProcessCitizenMoving(TAI instance, uint citizenId, ref TCitizen citizen, bool mayCancel)
        {
            ushort instanceId = CitizenProxy.GetInstance(ref citizen);
            ushort vehicleId  = CitizenProxy.GetVehicle(ref citizen);

            // TODO: implement bored of traffic jam trip abandon
            if (vehicleId == 0 && instanceId == 0)
            {
                if (CitizenProxy.GetVisitBuilding(ref citizen) != 0)
                {
                    CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                }

                Log.Debug($"Teleporting {GetCitizenDesc(citizenId, ref citizen)} back home because they are moving but no instance is specified");
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                CitizenProxy.SetArrested(ref citizen, false);

                return;
            }

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

            if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, true))
            {
                ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);
                if (IsChance(AbandonTourChance) && homeBuilding != 0)
                {
                    CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating);
                    residentAI.StartMoving(instance, citizenId, ref citizen, 0, homeBuilding);
                }
            }
            else if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.WaitingTransport | CitizenInstance.Flags.WaitingTaxi))
            {
                if (mayCancel && CitizenMgr.GetInstanceWaitCounter(instanceId) == 255 && IsChance(AbandonTransportWaitChance))
                {
                    ushort home = CitizenProxy.GetHomeBuilding(ref citizen);
                    if (home == 0)
                    {
                        return;
                    }

                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} doesn't want to wait for transport anymore, goes back home");
                    residentAI.StartMoving(instance, citizenId, ref citizen, 0, home);
                }
            }
        }
コード例 #3
0
        private void ProcessCitizenOnTour(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            if (!CitizenMgr.InstanceHasFlags(CitizenProxy.GetInstance(ref citizen), CitizenInstance.Flags.TargetIsNode))
            {
                return;
            }

            ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);

            if (homeBuilding != 0)
            {
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, false)} exits a guided tour and moves back home.");
                residentAI.StartMoving(instance, citizenId, ref citizen, 0, homeBuilding);
            }
        }
コード例 #4
0
        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);
        }
コード例 #5
0
        private void ProcessMoving(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort instanceId = CitizenProxy.GetInstance(ref citizen);
            ushort vehicleId  = CitizenProxy.GetVehicle(ref citizen);

            if (instanceId == 0)
            {
                if (vehicleId == 0)
                {
                    CitizenMgr.ReleaseCitizen(citizenId);
                }

                return;
            }

            bool isEvacuating = CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating);

            if (vehicleId == 0 && !isEvacuating && CitizenMgr.IsAreaEvacuating(instanceId))
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Searching for a shelter.");
                TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, touristAI.GetEvacuationReason(instance, 0));
                return;
            }

            if (isEvacuating)
            {
                return;
            }

            if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, all: true))
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} exits the guided tour.");
                FindRandomVisitPlace(instance, citizenId, ref citizen, TouristDoNothingProbability, 0);
                return;
            }

            ushort targetBuildingId = CitizenProxy.GetVisitBuilding(ref citizen);

            TouristTarget target;

            if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode))
            {
                if (CitizenMgr.GetTargetNode(instanceId) != 0)
                {
                    target = TouristTarget.Relaxing;
                }
                else
                {
                    return;
                }
            }
            else
            {
                if (targetBuildingId == 0)
                {
                    targetBuildingId = CitizenMgr.GetTargetBuilding(instanceId);
                }

                BuildingMgr.GetBuildingService(targetBuildingId, out ItemClass.Service targetService, out ItemClass.SubService targetSubService);
                switch (targetService)
                {
                // Heading to a hotel, no need to change anything
                case ItemClass.Service.Commercial when targetSubService == ItemClass.SubService.CommercialTourist:
                    return;

                case ItemClass.Service.Commercial when targetSubService == ItemClass.SubService.CommercialLeisure:
                    target = TouristTarget.Party;
                    break;

                case ItemClass.Service.Tourism:
                case ItemClass.Service.Beautification:
                case ItemClass.Service.Monument:
                    target = TouristTarget.Relaxing;
                    break;

                case ItemClass.Service.Commercial:
                    target = TouristTarget.Shopping;
                    break;

                default:
                    return;
                }
            }

            if (GetTouristGoingOutChance(ref citizen, target) > 0)
            {
                return;
            }

            ushort hotel = FindHotel(targetBuildingId);

            if (hotel != 0)
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} changes the target and moves to a hotel {hotel} because of time or weather");
                StartMovingToVisitBuilding(instance, citizenId, ref citizen, 0, hotel);
            }
            else
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} leaves the city because of time or weather");
                touristAI.FindVisitPlace(instance, citizenId, 0, touristAI.GetLeavingReason(instance, citizenId, ref citizen));
            }
        }
コード例 #6
0
        private void ProcessCitizenMoving(TAI instance, uint citizenId, ref TCitizen citizen, bool mayCancel)
        {
            ushort instanceId = CitizenProxy.GetInstance(ref citizen);
            ushort vehicleId  = CitizenProxy.GetVehicle(ref citizen);

            if (vehicleId == 0 && instanceId == 0)
            {
                if (CitizenProxy.GetVisitBuilding(ref citizen) != 0)
                {
                    CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                }

                if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn))
                {
                    CitizenMgr.ReleaseCitizen(citizenId);
                }
                else
                {
                    // TODO: check whether this makes sense and maybe remove/replace this logic
                    // Don't know why the original game does this...
                    CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                    CitizenProxy.SetArrested(ref citizen, false);
                }

                return;
            }

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

            bool   returnHome     = false;
            ushort targetBuilding = CitizenMgr.GetTargetBuilding(instanceId);

            if (targetBuilding != CitizenProxy.GetWorkBuilding(ref citizen))
            {
                ItemClass.Service targetService = BuildingMgr.GetBuildingService(targetBuilding);
                if (targetService == ItemClass.Service.Beautification && IsBadWeather(citizenId))
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, false)} cancels the trip to a park due to bad weather");
                    returnHome = true;
                }
            }

            if (!returnHome && CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.WaitingTransport | CitizenInstance.Flags.WaitingTaxi))
            {
                if (mayCancel && CitizenMgr.GetInstanceWaitCounter(instanceId) == 255 && Random.ShouldOccur(AbandonTransportWaitChance))
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, false)} goes back home");
                    returnHome = true;
                }
            }

            if (returnHome)
            {
                ushort home = CitizenProxy.GetHomeBuilding(ref citizen);
                if (home == 0)
                {
                    return;
                }

                residentAI.StartMoving(instance, citizenId, ref citizen, 0, home);
            }
        }
コード例 #7
0
        private ResidentState GetResidentState(ref TCitizen citizen)
        {
            if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.DummyTraffic))
            {
                return(ResidentState.Ignored);
            }

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding);

            if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating) &&
                buildingService != ItemClass.Service.Disaster)
            {
                return(ResidentState.Evacuating);
            }

            switch (CitizenProxy.GetLocation(ref citizen))
            {
            case Citizen.Location.Home:
                return(currentBuilding != 0
                        ? ResidentState.AtHome
                        : ResidentState.Unknown);

            case Citizen.Location.Work:
                if (buildingService == ItemClass.Service.Disaster && CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
                {
                    return(ResidentState.InShelter);
                }

                if (CitizenProxy.GetVisitBuilding(ref citizen) == currentBuilding)
                {
                    // A citizen may visit their own work building (e.g. shopping)
                    goto case Citizen.Location.Visit;
                }

                return(currentBuilding != 0
                        ? ResidentState.AtSchoolOrWork
                        : ResidentState.Unknown);

            case Citizen.Location.Visit:
                if (currentBuilding == 0)
                {
                    return(ResidentState.Unknown);
                }

                switch (buildingService)
                {
                case ItemClass.Service.Commercial:
                    if (CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDay &&
                        TimeInfo.CurrentHour > Config.LunchBegin && TimeInfo.CurrentHour < GetSpareTimeBeginHour(CitizenProxy.GetAge(ref citizen)))
                    {
                        return(ResidentState.AtLunch);
                    }

                    if (BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure)
                    {
                        return(ResidentState.AtLeisureArea);
                    }

                    return(ResidentState.Shopping);

                case ItemClass.Service.Beautification:
                    return(ResidentState.AtLeisureArea);

                case ItemClass.Service.Disaster:
                    return(ResidentState.InShelter);
                }

                return(ResidentState.Visiting);

            case Citizen.Location.Moving:
                ushort instanceId = CitizenProxy.GetInstance(ref citizen);
                if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.OnTour | CitizenInstance.Flags.TargetIsNode, true))
                {
                    return(ResidentState.OnTour);
                }

                ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);
                return(homeBuilding != 0 && CitizenMgr.GetTargetBuilding(instanceId) == homeBuilding
                        ? ResidentState.MovingHome
                        : ResidentState.MovingToTarget);

            default:
                return(ResidentState.Unknown);
            }
        }