public void CustomUpdateParkedVehicle(ushort parkedId, ref VehicleParked data)
        {
            float  x = this.m_info.m_generatedInfo.m_size.x;
            float  z = this.m_info.m_generatedInfo.m_size.z;
            uint   ownerCitizenId = data.m_ownerCitizen;
            ushort homeID         = 0;

            if (ownerCitizenId != 0u)
            {
                homeID = Singleton <CitizenManager> .instance.m_citizens.m_buffer[ownerCitizenId].m_homeBuilding;
            }

            ExtParkingSpaceLocation parkingSpaceLocation;
            ushort     parkingSpaceLocationId;
            Vector3    parkPos;
            Quaternion parkRot;
            float      parkOffset;

            if (AdvancedParkingManager.Instance.FindParkingSpaceInVicinity(data.m_position, data.Info, homeID, 0, GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToBuilding, out parkingSpaceLocation, out parkingSpaceLocationId, out parkPos, out parkRot, out parkOffset))
            {
                Singleton <VehicleManager> .instance.RemoveFromGrid(parkedId, ref data);

                data.m_position = parkPos;
                data.m_rotation = parkRot;
                Singleton <VehicleManager> .instance.AddToGrid(parkedId, ref data);
            }
            else
            {
                Singleton <VehicleManager> .instance.ReleaseParkedVehicle(parkedId);
            }
        }
示例#2
0
 private static ushort CheckOverlap(ushort ignoreParked, ref Bezier3 bezier,
                                    Vector3 pos, Vector3 dir, float offset, float length,
                                    ushort otherID, ref VehicleParked otherData,
                                    ref bool overlap, ref float minPos, ref float maxPos)
 {
     if (otherID != ignoreParked)
     {
         VehicleInfo info       = otherData.Info;
         Vector3     otherPos   = otherData.m_position;
         Vector3     diff       = otherPos - pos;
         float       carLength  = info.m_generatedInfo.m_size.z;
         float       lengthAvr  = (length + carLength) * 0.5f + 1f;
         float       diffLength = diff.magnitude;
         if (diffLength < lengthAvr - 0.5f)
         {
             overlap = true;
             float l1;
             float l2;
             if (Vector3.Dot(diff, dir) >= 0f)
             {
                 l1 = lengthAvr + diffLength;
                 l2 = lengthAvr - diffLength;
             }
             else
             {
                 l1 = lengthAvr - diffLength;
                 l2 = lengthAvr + diffLength;
             }
             maxPos = Mathf.Max(maxPos, bezier.Travel(offset, l1));
             minPos = Mathf.Min(minPos, bezier.Travel(offset, -l2));
         }
     }
     return(otherData.m_nextGridParked);
 }
示例#3
0
        public static IEnumerator RemoveAllUnwantedVehicles(ThreadBase t)
        {
            ushort vehId = 1;

            while (vehId < Singleton <VehicleManager> .instance.m_vehicles.m_size)
            {
                Vehicle     vehicle     = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehId];
                VehicleInfo vehicleInfo = vehicle.Info;
                if (vehicleInfo != null && !VehicleUtils.IsTrailer(vehicleInfo) && vehicle.m_transportLine == 0)
                {
                    uint citizenOwner = vehicle.Info.m_vehicleAI.GetOwnerID(vehId, ref vehicle).Citizen;
                    if (citizenOwner > 0)
                    {
                        var ownerWealth = CitizenWealthDefinition.from(CitizenManager.instance.m_citizens.m_buffer[citizenOwner].WealthLevel);
                        if (ownerWealth != null)
                        {
                            var ext = ownerWealth.GetVehicleExtension();
                            if (!ext.IsModelCompatible(vehicleInfo))
                            {
                                Singleton <VehicleManager> .instance.ReleaseVehicle(vehId);
                            }
                        }
                    }
                }
                if (vehId % 256 == 255)
                {
                    yield return(vehId);
                }
                vehId++;
            }

            vehId = 1;
            while (vehId < Singleton <VehicleManager> .instance.m_parkedVehicles.m_size)
            {
                VehicleParked vehicle     = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[vehId];
                VehicleInfo   vehicleInfo = vehicle.Info;
                if (vehicleInfo != null && !VehicleUtils.IsTrailer(vehicleInfo))
                {
                    uint citizenOwner = vehicle.m_ownerCitizen;
                    if (citizenOwner > 0)
                    {
                        var ownerWealth = CitizenWealthDefinition.from(CitizenManager.instance.m_citizens.m_buffer[citizenOwner].WealthLevel);
                        if (ownerWealth != null)
                        {
                            if (!ownerWealth.GetVehicleExtension().IsModelCompatible(vehicleInfo))
                            {
                                Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[vehId].Info = ownerWealth.GetVehicleExtension().GetAModel();
                            }
                        }
                    }
                }
                if (vehId % 256 == 255)
                {
                    yield return(vehId);
                }
                vehId++;
            }
            yield break;
        }
 public override string GetLocalizedStatus(
     ushort parkedVehicleID,
     ref VehicleParked data,
     out InstanceID target)
 {
     target = InstanceID.Empty;
     return(ColossalFramework.Globalization.Locale.Get("VEHICLE_STATUS_CARGOSHIP_LOADING"));
 }
        private void clickGoToParkedVehicle(UIComponent component, UIMouseEventParameter eventParam)
        {
            ushort        parkedVehicleId = Convert.ToUInt16(_goToField.text);
            VehicleParked parkedVehicle   = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId];

            if ((parkedVehicle.m_flags & (ushort)VehicleParked.Flags.Created) != 0)
            {
                CSUtil.CameraControl.CameraController.Instance.GoToParkedVehicle(parkedVehicleId);
            }
        }
示例#6
0
        private void clickGoToParkedVehicle(UIComponent component, UIMouseEventParameter eventParam)
        {
            ushort        parkedVehicleId = Convert.ToUInt16(_goToField.text);
            VehicleParked parkedVehicle   = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId];

            if ((parkedVehicle.m_flags & (ushort)VehicleParked.Flags.Created) != 0)
            {
                CameraCtrl.GoToParkedVehicle(parkedVehicleId, new Vector3(parkedVehicle.m_position.x, Camera.main.transform.position.y, parkedVehicle.m_position.z));
            }
        }
示例#7
0
 public static bool PreGetColorParked(ushort parkedVehicleID, ref VehicleParked data, InfoManager.InfoMode infoMode, ref Color __result)
 {
     if (infoMode != InfoManager.InfoMode.None)
     {
         LogUtils.DoLog($"NOT GETTING COLOR FOR VEHICLE: {parkedVehicleID} INFO = {infoMode}");
         return(true);
     }
     if (!m_colorConfigData.TryGetValue(data.Info.name, out ColorConfigurationXml itemData) &&
         !m_colorConfigData.TryGetValue(data.Info.m_vehicleAI.GetType().Name, out itemData) &&
         !m_colorConfigData.TryGetValue("*", out itemData))
     {
         LogUtils.DoLog($"NOT GETTING COLOR FOR VEHICLE: {parkedVehicleID} ({data.Info.m_vehicleAI.GetType().Name} | {data.Info.name}) - not found");
         return(true);
     }
     LogUtils.DoLog($"GETTING COLOR FOR VEHICLE: {parkedVehicleID}  ({data.Info.m_vehicleAI.GetType().Name} | {data.Info.name}) ");
     return(GetNewColor(parkedVehicleID, ref __result, itemData));
 }
示例#8
0
        public void CustomUpdateParkedVehicle(ushort parkedId, ref VehicleParked data)
        {
            float x             = this.m_info.m_generatedInfo.m_size.x;
            float z             = this.m_info.m_generatedInfo.m_size.z;
            uint ownerCitizenId = data.m_ownerCitizen;
            ushort homeID       = 0;

            if (ownerCitizenId != 0u)
            {
                homeID = Singleton <CitizenManager> .instance.m_citizens.m_buffer[ownerCitizenId].m_homeBuilding;
            }

            // NON-STOCK CODE START
            if (!AdvancedParkingManager.Instance.TryMoveParkedVehicle(parkedId, ref data, data.m_position, GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToBuilding, homeID))
            {
                Singleton <VehicleManager> .instance.ReleaseParkedVehicle(parkedId);
            }
            // NON-STOCK CODE END
        }
示例#9
0
        public static bool Prefix(ushort parkedID, ref VehicleParked parkedData)
        {
            uint   ownerCitizenId = parkedData.m_ownerCitizen;
            ushort homeId         = 0;

            if (ownerCitizenId != 0u)
            {
                homeId = Singleton <CitizenManager> .instance.m_citizens.m_buffer[ownerCitizenId].m_homeBuilding;
            }

            // NON-STOCK CODE START
            if (!AdvancedParkingManager.Instance.TryMoveParkedVehicle(
                    parkedID,
                    ref parkedData,
                    parkedData.m_position,
                    GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToBuilding,
                    homeId))
            {
                Singleton <VehicleManager> .instance.ReleaseParkedVehicle(parkedID);
            }
            // NON-STOCK CODE STOP
            return(false);
        }
示例#10
0
 public void ProcessParkedVehicle(ushort parkedVehicleId,
                                  ref VehicleParked parkedVehicle,
                                  ParkedVehicleHandler handler)
 {
     handler(parkedVehicleId, ref parkedVehicle);
 }
 private ushort CheckCollisions(ushort instanceID, ref CitizenInstance citizenData, Segment3 segment, Vector3 min, Vector3 max, ushort otherID, ref VehicleParked otherData, ref Vector3 pushAmount, ref float pushDivider)
 {
     VehicleInfo info = otherData.Info;
     Vector3 position = otherData.m_position;
     Vector3 b = otherData.m_rotation * new Vector3 (0f, 0f, Mathf.Max (0.5f, info.m_generatedInfo.m_size.z * 0.5f - 1f));
     Segment3 segment2;
     segment2.a = position - b;
     segment2.b = position + b;
     Vector3 vector = segment2.Min ();
     vector.x -= 1f;
     vector.z -= 1f;
     Vector3 vector2 = segment2.Max ();
     vector2.x += 1f;
     vector2.y += 1f;
     vector2.z += 1f;
     if (min.x < vector2.x && max.x > vector.x && min.z < vector2.z && max.z > vector.z && min.y < vector2.y && max.y > vector.y)
     {
         float num = this.m_info.m_radius + 1f;
         float num3;
         float t;
         float num2 = segment.DistanceSqr (segment2, out num3, out t);
         if (num2 < num * num)
         {
             float num4 = num - Mathf.Sqrt (num2);
             float num5 = 1f - num2 / (num * num);
             Vector3 a = segment.Position (num3 * 0.9f);
             Vector3 b2 = segment2.Position (t);
             a.y = 0f;
             b2.y = 0f;
             Vector3 vector3 = Vector3.Normalize (a - b2);
             Vector3 rhs = Vector3.Normalize (new Vector3 (segment.b.x - segment.a.x, 0f, segment.b.z - segment.a.z));
             Vector3 vector4 = new Vector3 (rhs.z, 0f, -rhs.x) * Mathf.Abs (Vector3.Dot (vector3, rhs) * 0.5f);
             if (Vector3.Dot (vector3, vector4) >= 0f)
             {
                 vector3 += vector4;
             }
             else
             {
                 vector3 -= vector4;
             }
             pushAmount += vector3 * (num4 * num5);
             pushDivider += num5;
         }
     }
     return otherData.m_nextGridParked;
 }
        public bool ExtStartPathFind(ushort instanceID, ref CitizenInstance citizenData, ref ExtCitizenInstance extInstance, Vector3 startPos, Vector3 endPos, VehicleInfo vehicleInfo)
        {
#if DEBUG
            if (GlobalConfig.Instance.Debug.Switches[2])
            {
                Log.Warning($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID}, citizen {citizenData.m_citizen}, startPos={startPos}, endPos={endPos}, sourceBuilding={citizenData.m_sourceBuilding}, targetBuilding={citizenData.m_targetBuilding}, pathMode={extInstance.pathMode}");
            }
#endif

            // NON-STOCK CODE START
            ExtVehicleType extVehicleType  = ExtVehicleType.None;
            ushort         parkedVehicleId = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenData.m_citizen].m_parkedVehicle;
            //bool mayUseOwnPassengerCar = true; // allowed to use a passenger car?
            bool           canUseOwnPassengerCar = false;   // allowed to use a passenger car AND given vehicle type is a passenger car?
            CarUsagePolicy carUsageMode          = CarUsagePolicy.Allowed;
            //bool forceUseCar = false;
#if BENCHMARK
            using (var bm = new Benchmark(null, "ParkingAI.Preparation")) {
#endif
            if (Options.prohibitPocketCars)
            {
                switch (extInstance.pathMode)
                {
                case ExtPathMode.RequiresWalkingPathToParkedCar:
                case ExtPathMode.CalculatingWalkingPathToParkedCar:
                case ExtPathMode.WalkingToParkedCar:
                case ExtPathMode.ApproachingParkedCar:
#if DEBUG
                    if (GlobalConfig.Instance.Debug.Switches[2])
                    {
                        Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} has CurrentPathMode={extInstance.pathMode}. Change to 'CalculatingWalkingPathToParkedCar'.");
                    }
#endif
                    extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToParkedCar;
                    break;

                case ExtPathMode.RequiresWalkingPathToTarget:
                case ExtPathMode.CalculatingWalkingPathToTarget:
                case ExtPathMode.WalkingToTarget:
#if DEBUG
                    if (GlobalConfig.Instance.Debug.Switches[2])
                    {
                        Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} has CurrentPathMode={extInstance.pathMode}. Change to 'CalculatingWalkingPathToTarget'.");
                    }
#endif
                    extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget;
                    break;

                case ExtPathMode.RequiresCarPath:
                case ExtPathMode.DrivingToTarget:
                case ExtPathMode.DrivingToKnownParkPos:
                case ExtPathMode.DrivingToAltParkPos:
                case ExtPathMode.CalculatingCarPathToAltParkPos:
                case ExtPathMode.CalculatingCarPathToKnownParkPos:
                case ExtPathMode.CalculatingCarPathToTarget:
#if DEBUG
                    if (GlobalConfig.Instance.Debug.Switches[2])
                    {
                        Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} has CurrentPathMode={extInstance.pathMode}. Change to 'RequiresCarPath'.");
                    }
#endif
                    extInstance.pathMode = ExtPathMode.RequiresCarPath;
                    break;

                default:
#if DEBUG
                    if (GlobalConfig.Instance.Debug.Switches[2])
                    {
                        Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} has CurrentPathMode={extInstance.pathMode}. Change to 'None'.");
                    }
#endif
                    extInstance.Reset();
                    break;
                }

                // pathMode is now either CalculatingWalkingPathToParkedCar, CalculatingWalkingPathToTarget, RequiresCarPath or None.

                if (parkedVehicleId != 0 && extInstance.pathMode != ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToTarget)
                {
                    // Reuse parked vehicle info
                    VehicleParked vehicleParked = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId];
                    vehicleInfo = vehicleParked.Info;

                    // Does citizen need to move their car
                    if (extInstance.pathMode != ExtCitizenInstance.ExtPathMode.RequiresCarPath)
                    {
                        // Citizen may use their car if they want to
                        carUsageMode = CarUsagePolicy.Allowed;

                        // Is citizen going home
                        ushort homeId = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenData.m_citizen].m_homeBuilding;
                        if (homeId != 0 && citizenData.m_targetBuilding == homeId)
                        {
                            // Check distance between home and parked car. If too far away: force citizen to take their car back home
                            float distHomeToParked = (vehicleParked.m_position - Singleton <BuildingManager> .instance.m_buildings.m_buffer[homeId].m_position).magnitude;
                            if (distHomeToParked > GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToHome)
                            {
                                // Force citizen to go to car first, using public transport if required
                                extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar;
#if DEBUG
                                if (GlobalConfig.Instance.Debug.Switches[2])
                                {
                                    Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} will try to go to parkedVehicleId={parkedVehicleId}. distHomeToParked={distHomeToParked}");
                                }
#endif
                            }
                            // Don't force citizen to use their car if they are at home
                        }
                        else if (homeId == 0 || citizenData.m_sourceBuilding != homeId)
                        {
                            // Check if citizen parked their car nearby
                            BuildingManager buildingManager    = Singleton <BuildingManager> .instance;
                            float           distSourceToParked = (vehicleParked.m_position - buildingManager.m_buildings.m_buffer[citizenData.m_sourceBuilding].m_position).magnitude;
                            if (distSourceToParked <= GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToBuilding)
                            {
                                // Check if target is far enough away to drive to
                                float distTargetToParked = (vehicleParked.m_position - buildingManager.m_buildings.m_buffer[citizenData.m_targetBuilding].m_position).magnitude;
                                if (distTargetToParked > GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToBuilding)
                                {
                                    // Make sure car isn't parked near home
                                    float distHomeToParked = 0.0f;
                                    if (homeId != 0)
                                    {
                                        distHomeToParked = (vehicleParked.m_position - buildingManager.m_buildings.m_buffer[homeId].m_position).magnitude;
                                    }

                                    if (homeId == 0 || distHomeToParked > GlobalConfig.Instance.ParkingAI.MaxParkedCarDistanceToHome)
                                    {
                                        // Force citizen to go to car first, using public transport if required
                                        extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar;
#if DEBUG
                                        if (GlobalConfig.Instance.Debug.Switches[2])
                                        {
                                            Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} will try to go to parkedVehicleId={parkedVehicleId}. distSourceToParked={distSourceToParked}, distTargetToParked={distTargetToParked}, distHomeToParked={distHomeToParked}");
                                        }
#endif
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        // Citizen has reached their car, force them to drive it
                        carUsageMode = CarUsagePolicy.Forced;
#if DEBUG
                        if (GlobalConfig.Instance.Debug.Switches[2])
                        {
                            Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} will try to use parkedVehicleId={parkedVehicleId} to get to target={citizenData.m_targetBuilding}.");
                        }
#endif
                    }
                }

                if (extInstance.pathMode == ExtPathMode.CalculatingWalkingPathToParkedCar || extInstance.pathMode == ExtPathMode.CalculatingWalkingPathToTarget)
                {
                    // vehicle must not be used since we need a walking path
                    vehicleInfo  = null;
                    carUsageMode = CarUsagePolicy.Forbidden;

                    if (extInstance.pathMode == ExtCitizenInstance.ExtPathMode.CalculatingWalkingPathToParkedCar)
                    {
                        // check if parked car is present
                        if (parkedVehicleId == 0)
                        {
#if DEBUG
                            if (GlobalConfig.Instance.Debug.Switches[2])
                            {
                                Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} should go to parked car (CurrentPathMode={extInstance.pathMode}) but parked vehicle could not be found. Setting CurrentPathMode='CalculatingWalkingPathToTarget'.");
                            }
#endif
                            extInstance.pathMode = ExtPathMode.CalculatingWalkingPathToTarget;
                        }
                        else
                        {
                            endPos = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position;
#if DEBUG
                            if (GlobalConfig.Instance.Debug.Switches[4])
                            {
                                Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} shall go to parked vehicle @ {endPos}");
                            }
#endif
                        }
                    }
                }
            }
#if BENCHMARK
        }
#endif

            /*if (Options.parkingRestrictionsEnabled && carUsageMode == CarUsagePolicy.Allowed && parkedVehicleId != 0) {
             *      // force removal of illegaly parked vehicle
             *      PathUnit.Position parkedPathPos;
             *      if (PathManager.FindPathPosition(Singleton<VehicleManager>.instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position, ItemClass.Service.Road, NetInfo.LaneType.Parking, VehicleInfo.VehicleType.Car, false, false, 32f, out parkedPathPos)) {
             *              if (! ParkingRestrictionsManager.Instance.IsParkingAllowed(parkedPathPos.m_segment, Singleton<NetManager>.instance.m_segments.m_buffer[parkedPathPos.m_segment].Info.m_lanes[parkedPathPos.m_lane].m_finalDirection)) {
             *                      carUsageMode = CarUsagePolicy.Forced;
             *                      vehicleInfo = Singleton<VehicleManager>.instance.m_parkedVehicles.m_buffer[parkedVehicleId].Info;
             *              }
             *      }
             * }*/
            // NON-STOCK CODE END

            NetInfo.LaneType laneTypes           = NetInfo.LaneType.Pedestrian;
            VehicleInfo.VehicleType vehicleTypes = VehicleInfo.VehicleType.None;
            bool randomParking    = false;
            bool combustionEngine = false;
            if (vehicleInfo != null)
            {
                if (vehicleInfo.m_class.m_subService == ItemClass.SubService.PublicTransportTaxi)
                {
                    if ((citizenData.m_flags & CitizenInstance.Flags.CannotUseTaxi) == CitizenInstance.Flags.None && Singleton <DistrictManager> .instance.m_districts.m_buffer[0].m_productionData.m_finalTaxiCapacity != 0u)
                    {
                        SimulationManager instance = Singleton <SimulationManager> .instance;
                        if (instance.m_isNightTime || instance.m_randomizer.Int32(2u) == 0)
                        {
                            laneTypes     |= (NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle);
                            vehicleTypes  |= vehicleInfo.m_vehicleType;
                            extVehicleType = ExtVehicleType.Taxi;                             // NON-STOCK CODE
                            // NON-STOCK CODE START
                            if (Options.prohibitPocketCars)
                            {
                                extInstance.pathMode = ExtPathMode.TaxiToTarget;
                            }
                            // NON-STOCK CODE END
                        }
                    }
                }
                else
                {
                    // NON-STOCK CODE START
                    if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Car)
                    {
                        if (carUsageMode == CarUsagePolicy.Allowed || carUsageMode == CarUsagePolicy.Forced)
                        {
                            extVehicleType        = ExtVehicleType.PassengerCar;
                            laneTypes            |= NetInfo.LaneType.Vehicle;
                            vehicleTypes         |= vehicleInfo.m_vehicleType;
                            combustionEngine      = vehicleInfo.m_class.m_subService == ItemClass.SubService.ResidentialLow;
                            canUseOwnPassengerCar = true;
                        }
                    }
                    else if (vehicleInfo.m_vehicleType == VehicleInfo.VehicleType.Bicycle)
                    {
                        extVehicleType = ExtVehicleType.Bicycle;
                        laneTypes     |= NetInfo.LaneType.Vehicle;
                        vehicleTypes  |= vehicleInfo.m_vehicleType;
                        if (citizenData.m_targetBuilding != 0 && Singleton <BuildingManager> .instance.m_buildings.m_buffer[citizenData.m_targetBuilding].Info.m_class.m_service > ItemClass.Service.Office)
                        {
                            randomParking = true;
                        }
                    }
                    // NON-STOCK CODE END
                }
            }
            NetInfo.LaneType startLaneType = laneTypes;

            // NON-STOCK CODE START
            if (Options.prohibitPocketCars)
            {
                if (carUsageMode == CarUsagePolicy.Forced && !canUseOwnPassengerCar)
                {
                    carUsageMode = CarUsagePolicy.Forbidden;
                }
            }

            PathUnit.Position endPosA = default(PathUnit.Position);
            bool calculateEndPos      = true;
            bool allowRandomParking   = true;
#if BENCHMARK
            using (var bm = new Benchmark(null, "ParkingAI.Main")) {
#endif
            if (Options.prohibitPocketCars)
            {
                // Parking AI

                if (extInstance.pathMode == ExtCitizenInstance.ExtPathMode.RequiresCarPath)
                {
                    if (canUseOwnPassengerCar)
                    {
                        ushort homeId = Singleton <CitizenManager> .instance.m_citizens.m_buffer[citizenData.m_citizen].m_homeBuilding;

                        startLaneType &= ~NetInfo.LaneType.Pedestrian;                                                               // force to use the car from the beginning
                        startPos       = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position; // force to start from the parked car

#if DEBUG
                        if (GlobalConfig.Instance.Debug.Switches[2])
                        {
                            Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Setting startLaneType={startLaneType}, startPos={startPos} for citizen instance {instanceID}. CurrentDepartureMode={extInstance.pathMode}");
                        }
#endif

                        if (citizenData.m_targetBuilding == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[citizenData.m_targetBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None)
                        {
                            // the citizen is starting their journey and the target is not an outside connection: find a suitable parking space near the target

#if DEBUG
                            if (GlobalConfig.Instance.Debug.Switches[2])
                            {
                                Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Finding parking space at target for citizen instance {instanceID}. CurrentDepartureMode={extInstance.pathMode} parkedVehicleId={parkedVehicleId}");
                            }
#endif

                            // find a parking space in the vicinity of the target
                            bool    calcEndPos;
                            Vector3 parkPos;
                            if (AdvancedParkingManager.Instance.FindParkingSpaceForCitizen(endPos, vehicleInfo, ref extInstance, homeId, citizenData.m_targetBuilding == homeId, 0, false, out parkPos, ref endPosA, out calcEndPos) && extInstance.CalculateReturnPath(parkPos, endPos))
                            {
                                // success
                                extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingCarPathToKnownParkPos;
                                calculateEndPos      = calcEndPos;                                  // if true, the end path position still needs to be calculated
                                allowRandomParking   = false;                                       // find a direct path to the calculated parking position
#if DEBUG
                                if (GlobalConfig.Instance.Debug.Switches[2])
                                {
                                    Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Finding known parking space for citizen instance {instanceID}, parked vehicle {parkedVehicleId} succeeded and return path {extInstance.returnPathId} ({extInstance.returnPathState}) is calculating. PathMode={extInstance.pathMode}");
                                }
#endif

                                /*if (! extInstance.CalculateReturnPath(parkPos, endPos)) {
                                 *      // TODO retry?
                                 *      if (GlobalConfig.Instance.Debug.Switches[2])
                                 *              Log._Debug($"CustomCitizenAI.CustomStartPathFind: [PFFAIL] Could not calculate return path for citizen instance {instanceID}, parked vehicle {parkedVehicleId}. Calling OnPathFindFailed.");
                                 *      CustomHumanAI.OnPathFindFailure(extInstance);
                                 *      return false;
                                 * }*/
                            }
                        }

                        if (extInstance.pathMode == ExtPathMode.RequiresCarPath)
                        {
                            // no known parking space found. calculate direct path to target
#if DEBUG
                            if (GlobalConfig.Instance.Debug.Switches[2])
                            {
                                Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} is still at CurrentPathMode={extInstance.pathMode} (no parking space found?). Setting it to CalculatingCarPath. parkedVehicleId={parkedVehicleId}");
                            }
#endif
                            extInstance.pathMode = ExtCitizenInstance.ExtPathMode.CalculatingCarPathToTarget;
                        }
                    }
                    else if (extInstance.pathMode == ExtPathMode.RequiresCarPath)
                    {
#if DEBUG
                        if (GlobalConfig.Instance.Debug.Switches[2])
                        {
                            Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} requires car path but no parked car present. Citizen will need to walk to target.");
                        }
#endif
                        extInstance.Reset();
                    }
                }
            }
#if BENCHMARK
        }
#endif

            if (canUseOwnPassengerCar)
            {
                if (allowRandomParking && citizenData.m_targetBuilding != 0 && Singleton <BuildingManager> .instance.m_buildings.m_buffer[citizenData.m_targetBuilding].Info.m_class.m_service > ItemClass.Service.Office)
                {
                    randomParking = true;
                }
            }

            // determine path type
            ExtPathType extPathType = ExtPathType.None;
            if (Options.prohibitPocketCars)
            {
                extPathType = extInstance.GetPathType();
            }

            // NON-STOCK CODE END
            PathUnit.Position vehiclePosition = default(PathUnit.Position);

            if (parkedVehicleId != 0 && canUseOwnPassengerCar)
            {
                Vector3 position = Singleton <VehicleManager> .instance.m_parkedVehicles.m_buffer[parkedVehicleId].m_position;
                CustomPathManager.FindPathPosition(position, ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, false, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out vehiclePosition);
            }
            bool allowUnderground = (citizenData.m_flags & (CitizenInstance.Flags.Underground | CitizenInstance.Flags.Transition)) != CitizenInstance.Flags.None;

#if DEBUG
            if (GlobalConfig.Instance.Debug.Switches[2])
            {
                Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Requesting path-finding for citizen instance {instanceID}, citizen {citizenData.m_citizen}, extVehicleType={extVehicleType}, extPathType={extPathType}, startPos={startPos}, endPos={endPos}, sourceBuilding={citizenData.m_sourceBuilding}, targetBuilding={citizenData.m_targetBuilding} pathMode={extInstance.pathMode}");
            }
#endif

            bool foundEndPos   = !calculateEndPos || FindPathPosition(instanceID, ref citizenData, endPos, Options.prohibitPocketCars && (citizenData.m_targetBuilding == 0 || (Singleton <BuildingManager> .instance.m_buildings.m_buffer[citizenData.m_targetBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None) ? NetInfo.LaneType.Pedestrian : (laneTypes | NetInfo.LaneType.Pedestrian), vehicleTypes, false, out endPosA);         // NON-STOCK CODE: with Parking AI enabled, the end position must be a pedestrian position
            bool foundStartPos = false;
            PathUnit.Position startPosA;

            if (Options.prohibitPocketCars && (extInstance.pathMode == ExtPathMode.CalculatingCarPathToTarget || extInstance.pathMode == ExtPathMode.CalculatingCarPathToKnownParkPos))
            {
                foundStartPos = CustomPathManager.FindPathPosition(startPos, ItemClass.Service.Road, laneTypes & ~NetInfo.LaneType.Pedestrian, vehicleTypes, allowUnderground, false, GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance, out startPosA);
            }
            else
            {
                foundStartPos = FindPathPosition(instanceID, ref citizenData, startPos, startLaneType, vehicleTypes, allowUnderground, out startPosA);
            }

            if (foundStartPos &&            // TODO probably fails if vehicle is parked too far away from road
                foundEndPos                 // NON-STOCK CODE
                )
            {
                bool canUseTransport = (citizenData.m_flags & CitizenInstance.Flags.CannotUseTransport) == CitizenInstance.Flags.None;
                if (canUseTransport)
                {
                    if (carUsageMode != CarUsagePolicy.Forced)                       // NON-STOCK CODE
                    {
                        laneTypes |= NetInfo.LaneType.PublicTransport;

                        CitizenManager citizenManager = Singleton <CitizenManager> .instance;
                        uint           citizenId      = citizenManager.m_instances.m_buffer[instanceID].m_citizen;
                        if (citizenId != 0u && (citizenManager.m_citizens.m_buffer[citizenId].m_flags & Citizen.Flags.Evacuating) != Citizen.Flags.None)
                        {
                            laneTypes |= NetInfo.LaneType.EvacuationTransport;
                        }
                    }
                }
                else if (Options.prohibitPocketCars)                     // TODO check for incoming connection
                // cim tried to use public transport but waiting time was too long
                {
                    if (citizenData.m_sourceBuilding != 0)
                    {
#if DEBUG
                        if (GlobalConfig.Instance.Debug.Switches[2])
                        {
                            Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Citizen instance {instanceID} cannot uses public transport from building {citizenData.m_sourceBuilding} to {citizenData.m_targetBuilding}. Incrementing public transport demand.");
                        }
#endif
                        ExtBuildingManager.Instance.ExtBuildings[citizenData.m_sourceBuilding].AddPublicTransportDemand((uint)GlobalConfig.Instance.ParkingAI.PublicTransportDemandWaitingIncrement, true);
                    }
                }

                PathUnit.Position dummyPathPos = default(PathUnit.Position);
                uint path;
                // NON-STOCK CODE START
                PathCreationArgs args;
                args.extPathType         = extPathType;
                args.extVehicleType      = extVehicleType;
                args.vehicleId           = 0;
                args.buildIndex          = Singleton <SimulationManager> .instance.m_currentBuildIndex;
                args.startPosA           = startPosA;
                args.startPosB           = dummyPathPos;
                args.endPosA             = endPosA;
                args.endPosB             = dummyPathPos;
                args.vehiclePosition     = vehiclePosition;
                args.laneTypes           = laneTypes;
                args.vehicleTypes        = vehicleTypes;
                args.maxLength           = 20000f;
                args.isHeavyVehicle      = false;
                args.hasCombustionEngine = combustionEngine;
                args.ignoreBlocked       = false;
                args.ignoreFlooded       = false;
                args.randomParking       = randomParking;
                args.stablePath          = false;
                args.skipQueue           = false;

                bool res = CustomPathManager._instance.CreatePath(out path, ref Singleton <SimulationManager> .instance.m_randomizer, args);
                // NON-STOCK CODE END

                if (res)
                {
#if DEBUG
                    if (GlobalConfig.Instance.Debug.Switches[2])
                    {
                        Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): Path-finding starts for citizen instance {instanceID}, path={path}, extVehicleType={extVehicleType}, startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, laneType={laneTypes}, vehicleType={vehicleTypes}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}, vehiclePos.m_segment={vehiclePosition.m_segment}, vehiclePos.m_lane={vehiclePosition.m_lane}, vehiclePos.m_offset={vehiclePosition.m_offset}");
                    }
#endif

                    if (citizenData.m_path != 0u)
                    {
                        Singleton <PathManager> .instance.ReleasePath(citizenData.m_path);
                    }
                    citizenData.m_path   = path;
                    citizenData.m_flags |= CitizenInstance.Flags.WaitingPath;
                    return(true);
                }
            }

#if DEBUG
            if (Options.prohibitPocketCars)
            {
                if (GlobalConfig.Instance.Debug.Switches[2])
                {
                    Log._Debug($"CustomCitizenAI.ExtStartPathFind({instanceID}): CustomCitizenAI.CustomStartPathFind: [PFFAIL] failed for citizen instance {instanceID} (CurrentPathMode={extInstance.pathMode}). startPosA.segment={startPosA.m_segment}, startPosA.lane={startPosA.m_lane}, startPosA.offset={startPosA.m_offset}, endPosA.segment={endPosA.m_segment}, endPosA.lane={endPosA.m_lane}, endPosA.offset={endPosA.m_offset}, foundStartPos={foundStartPos}, foundEndPos={foundEndPos}");
                }
            }
#endif
            return(false);
        }
        private ushort CheckCollisions(ushort instanceID, ref CitizenInstance citizenData, Segment3 segment, Vector3 min, Vector3 max, ushort otherID, ref VehicleParked otherData, ref Vector3 pushAmount, ref float pushDivider)
        {
            VehicleInfo info     = otherData.Info;
            Vector3     position = otherData.m_position;
            Vector3     b        = otherData.m_rotation * new Vector3(0f, 0f, Mathf.Max(0.5f, info.m_generatedInfo.m_size.z * 0.5f - 1f));
            Segment3    segment2;

            segment2.a = position - b;
            segment2.b = position + b;
            Vector3 vector = segment2.Min();

            vector.x -= 1f;
            vector.z -= 1f;
            Vector3 vector2 = segment2.Max();

            vector2.x += 1f;
            vector2.y += 1f;
            vector2.z += 1f;
            if (min.x < vector2.x && max.x > vector.x && min.z < vector2.z && max.z > vector.z && min.y < vector2.y && max.y > vector.y)
            {
                float num = this.m_info.m_radius + 1f;
                float num3;
                float t;
                float num2 = segment.DistanceSqr(segment2, out num3, out t);
                if (num2 < num * num)
                {
                    float   num4 = num - Mathf.Sqrt(num2);
                    float   num5 = 1f - num2 / (num * num);
                    Vector3 a    = segment.Position(num3 * 0.9f);
                    Vector3 b2   = segment2.Position(t);
                    a.y  = 0f;
                    b2.y = 0f;
                    Vector3 vector3 = Vector3.Normalize(a - b2);
                    Vector3 rhs     = Vector3.Normalize(new Vector3(segment.b.x - segment.a.x, 0f, segment.b.z - segment.a.z));
                    Vector3 vector4 = new Vector3(rhs.z, 0f, -rhs.x) * Mathf.Abs(Vector3.Dot(vector3, rhs) * 0.5f);
                    if (Vector3.Dot(vector3, vector4) >= 0f)
                    {
                        vector3 += vector4;
                    }
                    else
                    {
                        vector3 -= vector4;
                    }
                    pushAmount  += vector3 * (num4 * num5);
                    pushDivider += num5;
                }
            }
            return(otherData.m_nextGridParked);
        }