├── .gitattributes ├── .gitignore ├── .gitmodules ├── BuildingSpawnPoints.sln ├── BuildingSpawnPoints ├── BuildingSpawnPoints.csproj ├── Data │ ├── BuildingData.cs │ ├── DataExtensions.cs │ ├── LaneData.cs │ ├── Manager.cs │ ├── SpawnPoint.cs │ └── VehicleCategory.cs ├── Mod.cs ├── Patcher.cs ├── Properties │ ├── Localize.cs │ ├── Localize.cs-CZ.resx │ ├── Localize.da-DK.resx │ ├── Localize.de-DE.resx │ ├── Localize.es-ES.resx │ ├── Localize.fi-FI.resx │ ├── Localize.fr-FR.resx │ ├── Localize.hu-HU.resx │ ├── Localize.it-IT.resx │ ├── Localize.ja-JP.resx │ ├── Localize.ko-KR.resx │ ├── Localize.nl-NL.resx │ ├── Localize.pl-PL.resx │ ├── Localize.pt-PT.resx │ ├── Localize.resx │ ├── Localize.ro-RO.resx │ ├── Localize.ru-RU.resx │ ├── Localize.th-TH.resx │ ├── Localize.tr-TR.resx │ ├── Localize.uk-UA.resx │ ├── Localize.vi-VN.resx │ ├── Localize.zh-CN.resx │ ├── Localize.zh-TW.resx │ └── launchSettings.json ├── Resources │ ├── HeaderButtons │ │ ├── AddAllVehiclesHeaderButton.png │ │ ├── AddVehicleGroupHeaderButton.png │ │ ├── AddVehicleHeaderButton.png │ │ ├── AppendHeaderButton.png │ │ ├── ApplyAllHeaderButton.png │ │ ├── CopyHeaderButton.png │ │ ├── DuplicateHeaderButton.png │ │ ├── HeaderButtons.psd │ │ ├── PasteHeaderButton.png │ │ └── ResetHeaderButton.png │ ├── Icons │ │ ├── InfoIcon.psd │ │ ├── InfoNormal.png │ │ └── InfoPressed.png │ ├── PreviewImage.png │ └── UUIButton │ │ ├── UUIButton.psd │ │ ├── UUIButtonHovered.png │ │ ├── UUIButtonNormal.png │ │ └── UUIButtonPressed.png ├── Settings.cs ├── Tool │ ├── DragPoint.cs │ ├── EditPoint.cs │ ├── SelectBuilding.cs │ ├── Tool.cs │ └── Utilites.cs ├── UI │ ├── Panel.cs │ ├── PanelHeader.cs │ ├── PointPanel.cs │ ├── Utilities │ │ ├── SpawnPointsTextures.cs │ │ └── UIStyle.cs │ ├── VehicleCategoryProperty.cs │ └── WarningPanel.cs └── Utilites │ ├── AIExtensions.cs │ ├── MoveItIntegration.cs │ └── ObjectMap.cs ├── Workshop ├── Banner.psd ├── Icon.ai ├── Preview.psd ├── PreviewImageBeta.png ├── PreviewImageStable.png ├── Workshop BETA description.txt └── Workshop description.txt └── crowdin.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ModsCommon"] 2 | path = ModsCommon 3 | url = C:\\Users\\MacSergey\\source\\repos\\ModsCommon 4 | branch = BuildingSpawnPoints 5 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Data/BuildingData.cs: -------------------------------------------------------------------------------- 1 | using BuildingSpawnPoints.Utilites; 2 | using ColossalFramework; 3 | using ColossalFramework.Math; 4 | using HarmonyLib; 5 | using ModsCommon; 6 | using ModsCommon.Utilities; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.ComponentModel; 10 | using System.Linq; 11 | using System.Reflection.Emit; 12 | using System.Text; 13 | using System.Xml.Linq; 14 | using UnityEngine; 15 | 16 | namespace BuildingSpawnPoints 17 | { 18 | public class BuildingData : IToXml 19 | { 20 | public static string XmlName => "B"; 21 | 22 | public ushort Id { get; } 23 | private List SpawnPoints { get; } = new List(); 24 | public IEnumerable Points => SpawnPoints; 25 | 26 | public VehicleCategory DefaultVehicles => Id.GetBuilding().GetDefaultVehicles(); 27 | public VehicleCategory NeededVehicles => Id.GetBuilding().GetNeededVehicles(); 28 | public VehicleCategory PossibleVehicles => Id.GetBuilding().GetPossibleVehicles(); 29 | 30 | public VehicleCategory LostVehicles => SpawnPoints.Aggregate(NeededVehicles, (v, p) => v & ~p.Categories.Value); 31 | public VehicleCategory NotAddedVehicles => SpawnPoints.Aggregate(PossibleVehicles, (v, p) => v & ~p.Categories.Value); 32 | 33 | public bool IsCorrect => LostVehicles == VehicleCategory.None; 34 | 35 | public string XmlSection => XmlName; 36 | 37 | public BuildingData(ushort id, bool init = true) 38 | { 39 | Id = id; 40 | 41 | if (init) 42 | ResetToDefault(); 43 | } 44 | 45 | private static List TempPoints { get; } = new List(); 46 | public bool GetPosition(PointType type, ref Building data, VehicleInfo vehicle, ref Randomizer randomizer, out Vector3 position, out Vector3 target) 47 | { 48 | var category = (VehicleCategory)vehicle.m_vehicleAI.vehicleCategory; 49 | TempPoints.Clear(); 50 | foreach (var point in SpawnPoints) 51 | { 52 | if ((point.Type & type) != PointType.None && (point.Categories & category) != VehicleCategory.None) 53 | TempPoints.Add(point); 54 | } 55 | 56 | if (TempPoints.Count != 0) 57 | { 58 | #if DEBUG 59 | var vehicleId = randomizer.seed; 60 | #endif 61 | var index = randomizer.Int32((uint)TempPoints.Count); 62 | TempPoints[index].GetAbsolute(ref data, out position, out target); 63 | #if DEBUG 64 | SingletonMod.Logger.Debug($"{type} {category} on building #{Id}; {index + 1} of {TempPoints.Count}; {position}"); 65 | #endif 66 | return true; 67 | } 68 | else 69 | { 70 | position = Vector3.zero; 71 | target = Vector3.zero; 72 | return false; 73 | } 74 | } 75 | 76 | private void AddPoint(BuildingSpawnPoint point) 77 | { 78 | point.OnChanged = OnChanged; 79 | SpawnPoints.Add(point); 80 | } 81 | public BuildingSpawnPoint AddPoint() 82 | { 83 | var spawnPoint = new BuildingSpawnPoint(this, Vector3.zero, vehicleType: VehicleCategory.None); 84 | AddPoint(spawnPoint); 85 | return spawnPoint; 86 | } 87 | public void DeletePoint(BuildingSpawnPoint point) 88 | { 89 | point.OnChanged = null; 90 | SpawnPoints.Remove(point); 91 | } 92 | public BuildingSpawnPoint DuplicatePoint(BuildingSpawnPoint point) 93 | { 94 | var copyPoint = point.Copy(); 95 | AddPoint(copyPoint); 96 | return copyPoint; 97 | } 98 | public void ResetToDefault() 99 | { 100 | SpawnPoints.Clear(); 101 | AddPoint(new BuildingSpawnPoint(this, Vector3.back * (Id.GetBuilding().Length * 4f + 2f), 0f, DefaultVehicles)); 102 | foreach (var point in this.GetDefaultPoints()) 103 | AddPoint(point); 104 | } 105 | public void OnChanged() 106 | { 107 | //var vehicleId = Id.GetBuilding().m_ownVehicles; 108 | //var i = 0; 109 | 110 | //while (vehicleId != 0 && i < VehicleManager.MAX_VEHICLE_COUNT) 111 | //{ 112 | // var vehicle = vehicleId.GetVehicle(); 113 | // vehicle.Info.m_vehicleAI.BuildingRelocated(vehicleId, ref vehicle, Id); 114 | 115 | // vehicleId = vehicle.m_nextOwnVehicle; 116 | // i += 1; 117 | //} 118 | 119 | //vehicleId = Id.GetBuilding().m_guestVehicles; 120 | //i = 0; 121 | 122 | //while (vehicleId != 0 && i < VehicleManager.MAX_VEHICLE_COUNT) 123 | //{ 124 | // var vehicle = vehicleId.GetVehicle(); 125 | // vehicle.Info.m_vehicleAI.BuildingRelocated(vehicleId, ref vehicle, Id); 126 | 127 | // vehicleId = vehicle.m_nextGuestVehicle; 128 | // i += 1; 129 | //} 130 | } 131 | 132 | public XElement ToXml() 133 | { 134 | var config = new XElement(XmlSection); 135 | 136 | config.AddAttr(nameof(Id), Id); 137 | 138 | foreach (var point in Points) 139 | config.Add(point.ToXml()); 140 | 141 | return config; 142 | } 143 | 144 | public void FromXml(Version version, XElement config) 145 | { 146 | SpawnPoints.Clear(); 147 | 148 | foreach (var pointConfig in config.Elements(BuildingSpawnPoint.XmlName)) 149 | { 150 | if (BuildingSpawnPoint.FromXml(version, pointConfig, this, out var point)) 151 | AddPoint(point); 152 | } 153 | } 154 | public static bool FromXml(Version version, XElement config, ObjectsMap map, out BuildingData data) 155 | { 156 | var id = config.GetAttrValue(nameof(Id), (ushort)0); 157 | 158 | if (map.TryGetBuilding(id, out var targetId)) 159 | id = targetId; 160 | 161 | if (id != 0 && id <= BuildingManager.MAX_BUILDING_COUNT) 162 | { 163 | try 164 | { 165 | data = new BuildingData(id, false); 166 | data.FromXml(version, config); 167 | 168 | return true; 169 | } 170 | catch { } 171 | } 172 | 173 | data = null; 174 | return false; 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Data/DataExtensions.cs: -------------------------------------------------------------------------------- 1 | using BuildingSpawnPoints.Utilites; 2 | using ModsCommon; 3 | using ModsCommon.Utilities; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Xml.Linq; 9 | 10 | namespace BuildingSpawnPoints 11 | { 12 | public class LoadingExtension : BaseLoadingExtension 13 | { 14 | protected override void OnUnload() 15 | { 16 | base.OnUnload(); 17 | SingletonManager.Destroy(); 18 | BuildingSpawnPoint.DestroyMarker(); 19 | } 20 | protected override void OnPreLoaded() 21 | { 22 | BuildingSpawnPoint.CreateMarker(); 23 | } 24 | } 25 | public class SerializableDataExtension : BaseSerializableDataExtension 26 | { 27 | protected override string Id => nameof(BuildingSpawnPoints); 28 | 29 | protected override XElement GetSaveData() => SingletonManager.Instance.ToXml(); 30 | 31 | protected override void SetLoadData(XElement config) => SingletonManager.Instance.FromXml(config, new ObjectsMap(true)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Data/LaneData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace BuildingSpawnPoints 4 | { 5 | public struct VehicleLaneData 6 | { 7 | public ItemClass.Service Service; 8 | public NetInfo.LaneType Lane; 9 | public VehicleInfo.VehicleType Type; 10 | public VehicleInfo.VehicleCategory VehicleCategory; 11 | public float Distance; 12 | 13 | public VehicleLaneData(ItemClass.Service service, NetInfo.LaneType lane, VehicleInfo.VehicleType type, VehicleInfo.VehicleCategory vehicleCategory, float distance) 14 | { 15 | Service = service; 16 | Lane = lane; 17 | Type = type; 18 | VehicleCategory = vehicleCategory; 19 | Distance = distance; 20 | } 21 | private static Dictionary Dictinary { get; } = new Dictionary() 22 | { 23 | {VehicleService.Car, new VehicleLaneData(ItemClass.Service.Road, NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car, VehicleInfo.VehicleCategory.RoadTransport, 32f) }, 24 | {VehicleService.Trolleybus, new VehicleLaneData(ItemClass.Service.Road, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Trolleybus, VehicleInfo.VehicleCategory.Trolleybus, 32f) }, 25 | {VehicleService.Tram, new VehicleLaneData(ItemClass.Service.Road, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Tram, VehicleInfo.VehicleCategory.Tram, 32f) }, 26 | {VehicleService.Plane, new VehicleLaneData(ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Plane, VehicleInfo.VehicleCategory.Planes, 16f) }, 27 | {VehicleService.Balloon, new VehicleLaneData(ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Balloon, VehicleInfo.VehicleCategory.PassengerBalloon, 64f) }, 28 | {VehicleService.Blimp, new VehicleLaneData(ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Blimp, VehicleInfo.VehicleCategory.PassengerBlimp, 64f) }, 29 | {VehicleService.Ship, new VehicleLaneData(ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Ship, VehicleInfo.VehicleCategory.Ships, 64f) }, 30 | {VehicleService.Ferry, new VehicleLaneData(ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Ferry, VehicleInfo.VehicleCategory.PassengerFerry, 64f) }, 31 | {VehicleService.Fishing, new VehicleLaneData(ItemClass.Service.Fishing, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Ship, VehicleInfo.VehicleCategory.FishingBoat, 40f) }, 32 | {VehicleService.Train, new VehicleLaneData(ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Train, VehicleInfo.VehicleCategory.Trains, 32f) }, 33 | {VehicleService.Metro, new VehicleLaneData(ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Metro, VehicleInfo.VehicleCategory.MetroTrain, 32f) }, 34 | {VehicleService.Monorail, new VehicleLaneData(ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.Monorail, VehicleInfo.VehicleCategory.Monorail, 32f) }, 35 | {VehicleService.CableCar, new VehicleLaneData(ItemClass.Service.PublicTransport, NetInfo.LaneType.Vehicle, VehicleInfo.VehicleType.CableCar, VehicleInfo.VehicleCategory.CableCar, 32f) }, 36 | }; 37 | 38 | public static bool TryGet(VehicleService type, out VehicleLaneData value) => Dictinary.TryGetValue(type, out value); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Data/Manager.cs: -------------------------------------------------------------------------------- 1 | using BuildingSpawnPoints.Utilites; 2 | using ModsCommon; 3 | using ModsCommon.Utilities; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Xml.Linq; 9 | 10 | namespace BuildingSpawnPoints 11 | { 12 | public class Manager : IManager 13 | { 14 | private BuildingData[] Buffer { get; set; } 15 | 16 | public Manager() 17 | { 18 | SingletonMod.Logger.Debug("Create manager"); 19 | Buffer = new BuildingData[BuildingManager.MAX_BUILDING_COUNT]; 20 | } 21 | 22 | public BuildingData this[ushort id, Options options = Options.None] 23 | { 24 | get 25 | { 26 | if (Buffer[id] is not BuildingData data) 27 | { 28 | if (options.IsSet(Options.Create)) 29 | { 30 | data = new BuildingData(id, options.IsSet(Options.Init)); 31 | Buffer[id] = data; 32 | } 33 | else 34 | data = null; 35 | } 36 | return data; 37 | } 38 | } 39 | 40 | public XElement ToXml() 41 | { 42 | var config = new XElement(nameof(BuildingSpawnPoints)); 43 | 44 | config.AddAttr("V", SingletonMod.Version); 45 | 46 | foreach (var data in Buffer) 47 | { 48 | if (data != null) 49 | config.Add(data.ToXml()); 50 | } 51 | 52 | return config; 53 | } 54 | public void FromXml(XElement config, ObjectsMap map) 55 | { 56 | var version = GetVersion(config); 57 | 58 | foreach (var nodeConfig in config.Elements(BuildingData.XmlName)) 59 | { 60 | if (BuildingData.FromXml(version, nodeConfig, map, out BuildingData data)) 61 | Buffer[data.Id] = data; 62 | } 63 | } 64 | private static Version GetVersion(XElement config) 65 | { 66 | try { return new Version(config.Attribute("V").Value); } 67 | catch { return SingletonMod.Version; } 68 | } 69 | } 70 | 71 | [Flags] 72 | public enum Options 73 | { 74 | None = 0, 75 | Create = 1, 76 | Init = 2, 77 | Default = Create | Init, 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Mod.cs: -------------------------------------------------------------------------------- 1 | using ColossalFramework.Math; 2 | using ICities; 3 | using ModsCommon; 4 | using ModsCommon.Utilities; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Globalization; 8 | using UnityEngine; 9 | using static ColossalFramework.Plugins.PluginManager; 10 | 11 | namespace BuildingSpawnPoints 12 | { 13 | public class Mod : BasePatcherMod 14 | { 15 | #region PROPERTIES 16 | public override string NameRaw => "Building Spawn Points"; 17 | public override string Description => !IsBeta ? Localize.Mod_Description : CommonLocalize.Mod_DescriptionBeta; 18 | 19 | public override List Versions => new List() 20 | { 21 | new ModVersion(new Version(1,4,3), new DateTime(2025, 5, 23)), 22 | new ModVersion(new Version(1,4,2), new DateTime(2024, 10, 26)), 23 | new ModVersion(new Version(1,4,1), new DateTime(2023, 5, 27)), 24 | new ModVersion(new Version(1,4), new DateTime(2023, 4, 9)), 25 | new ModVersion(new Version(1,3,2), new DateTime(2022, 12, 13)), 26 | new ModVersion(new Version(1,3,1), new DateTime(2022, 11, 16)), 27 | new ModVersion(new Version(1,3), new DateTime(2022, 9, 14)), 28 | new ModVersion(new Version(1,2,4), new DateTime(2022, 6, 19)), 29 | new ModVersion(new Version(1,2,3), new DateTime(2021, 8, 25)), 30 | new ModVersion(new Version(1,2,2), new DateTime(2021, 8, 7)), 31 | new ModVersion(new Version(1,2,1), new DateTime(2021, 8, 1)), 32 | new ModVersion(new Version(1,2), new DateTime(2021, 7, 16)), 33 | new ModVersion(new Version(1,1), new DateTime(2021, 6, 19)), 34 | new ModVersion(new Version(1,0,2), new DateTime(2021, 6, 12)), 35 | new ModVersion(new Version(1,0,1), new DateTime(2021, 6, 10)), 36 | new ModVersion(new Version(1,0), new DateTime(2021, 6, 8)), 37 | }; 38 | protected override Version RequiredGameVersion => new Version(1, 19, 2, 3); 39 | 40 | protected override ulong StableWorkshopId => 2511258910ul; 41 | protected override ulong BetaWorkshopId => 2504315382ul; 42 | public override string CrowdinUrl => "https://crowdin.com/translate/macsergey-other-mods/106"; 43 | 44 | protected override string IdRaw => nameof(BuildingSpawnPoints); 45 | 46 | #if BETA 47 | public override bool IsBeta => true; 48 | #else 49 | public override bool IsBeta => false; 50 | #endif 51 | #endregion 52 | protected override LocalizeManager LocalizeManager => Localize.LocaleManager; 53 | protected override bool NeedMonoDevelopImpl => true; 54 | 55 | private static string METMName => "More Effective Transfer Manager"; 56 | private static ulong METMId => 1680840913ul; 57 | private static PluginSearcher METMSearcher { get; } = PluginUtilities.GetSearcher(METMName, METMId); 58 | public static PluginInfo METM => PluginUtilities.GetPlugin(METMSearcher); 59 | 60 | protected override void GetSettings(UIHelperBase helper) 61 | { 62 | var settings = new Settings(); 63 | settings.OnSettingsUI(helper); 64 | } 65 | protected override void SetCulture(CultureInfo culture) => Localize.Culture = culture; 66 | 67 | #region PATCHES 68 | 69 | protected override bool PatchProcess() 70 | { 71 | var success = true; 72 | 73 | success &= AddTool(); 74 | success &= ToolOnEscape(); 75 | success &= Patch_BuildingWorldInfoPanel_Start(); 76 | 77 | PatchBuildings(ref success); 78 | PatchVehicles(ref success); 79 | 80 | if (METM is null) 81 | Logger.Debug("METM not exist, skip patches"); 82 | else 83 | Patch_METM(ref success); 84 | 85 | return success; 86 | } 87 | 88 | private bool AddTool() 89 | { 90 | return AddTranspiler(typeof(Patcher), nameof(Patcher.ToolControllerAwakeTranspiler), typeof(ToolController), "Awake"); 91 | } 92 | 93 | private bool ToolOnEscape() 94 | { 95 | return AddTranspiler(typeof(Patcher), nameof(Patcher.GameKeyShortcutsEscapeTranspiler), typeof(GameKeyShortcuts), "Escape"); 96 | } 97 | 98 | #region BUILDINGS 99 | 100 | private void PatchBuildings(ref bool success) 101 | { 102 | var parameters = new Type[] { typeof(ushort), typeof(Building).MakeByRefType(), typeof(Randomizer).MakeByRefType(), typeof(VehicleInfo), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType() }; 103 | 104 | success &= Patch_BuildingAI_CalculateSpawnPosition(parameters); 105 | success &= Patch_BuildingAI_CalculateUnspawnPosition(parameters); 106 | 107 | success &= Patch_CalculateSpawnPosition(typeof(DepotAI), parameters); 108 | success &= Patch_CalculateUnspawnPosition(typeof(DepotAI), parameters); 109 | 110 | success &= Patch_CalculateSpawnPosition(typeof(CargoStationAI), parameters); 111 | success &= Patch_CalculateUnspawnPosition(typeof(CargoStationAI), parameters); 112 | 113 | success &= Patch_CalculateSpawnPosition(typeof(FishingHarborAI), parameters); 114 | success &= Patch_CalculateUnspawnPosition(typeof(FishingHarborAI), parameters); 115 | 116 | success &= Patch_CalculateSpawnPosition(typeof(PostOfficeAI), parameters); 117 | success &= Patch_CalculateUnspawnPosition(typeof(PostOfficeAI), parameters); 118 | 119 | success &= Patch_CalculateSpawnPosition(typeof(BankOfficeAI), parameters); 120 | success &= Patch_CalculateUnspawnPosition(typeof(BankOfficeAI), parameters); 121 | 122 | success &= Patch_CalculateSpawnPosition(typeof(TaxiStandAI), parameters); 123 | success &= Patch_CalculateUnspawnPosition(typeof(TaxiStandAI), parameters); 124 | 125 | success &= Patch_CalculateSpawnPosition(typeof(MaintenanceDepotAI), parameters); 126 | success &= Patch_CalculateUnspawnPosition(typeof(MaintenanceDepotAI), parameters); 127 | 128 | success &= Patch_CalculateSpawnPosition(typeof(ShelterAI), parameters); 129 | success &= Patch_CalculateUnspawnPosition(typeof(ShelterAI), parameters); 130 | 131 | success &= Patch_CalculateSpawnPosition(typeof(ServicePointAI), parameters); 132 | success &= Patch_CalculateUnspawnPosition(typeof(ServicePointAI), parameters); 133 | 134 | success &= Patch_CalculateUnspawnPosition(typeof(TourBuildingAI), parameters); 135 | } 136 | private bool Patch_BuildingWorldInfoPanel_Start() 137 | { 138 | return AddPostfix(typeof(Patcher), nameof(Patcher.BuildingWorldInfoPanelStartPostfix), typeof(BuildingWorldInfoPanel), "Start"); 139 | } 140 | 141 | private bool Patch_BuildingAI_CalculateSpawnPosition(Type[] parameters) 142 | { 143 | return AddPrefix(typeof(Patcher), nameof(Patcher.BuildingAI_CalculateSpawnPosition_Prefix), typeof(BuildingAI), nameof(BuildingAI.CalculateSpawnPosition), parameters); 144 | } 145 | private bool Patch_BuildingAI_CalculateUnspawnPosition(Type[] parameters) 146 | { 147 | return AddPrefix(typeof(Patcher), nameof(Patcher.BuildingAI_CalculateUnpawnPosition_Prefix), typeof(BuildingAI), nameof(BuildingAI.CalculateUnspawnPosition), parameters); 148 | } 149 | 150 | private bool Patch_CalculateSpawnPosition(Type type, Type[] parameters) 151 | { 152 | return AddPrefix(typeof(Patcher), nameof(Patcher.CalculateSpawnPosition_Prefix), type, nameof(BuildingAI.CalculateSpawnPosition), parameters); 153 | } 154 | private bool Patch_CalculateUnspawnPosition(Type type, Type[] parameters) 155 | { 156 | return AddPrefix(typeof(Patcher), nameof(Patcher.CalculateUnspawnPosition_Prefix), type, nameof(BuildingAI.CalculateUnspawnPosition), parameters); 157 | } 158 | 159 | #endregion 160 | 161 | #region VEHICLES 162 | 163 | private void PatchVehicles(ref bool success) 164 | { 165 | var startPathFindParams = new Type[] { typeof(ushort), typeof(Vehicle).MakeByRefType() }; 166 | success &= Patch_PoliceCarAI_StartPathFind(startPathFindParams); 167 | success &= Patch_FireTruckAI_StartPathFind(startPathFindParams); 168 | success &= Patch_DisasterResponseVehicleAI_StartPathFind(startPathFindParams); 169 | success &= Patch_ParkMaintenanceVehicleAI_StartPathFind(startPathFindParams); 170 | success &= Patch_BusAI_StartPathFind(startPathFindParams); 171 | success &= Patch_PassengerTrainAI_StartPathFind(startPathFindParams); 172 | success &= Patch_PassengerPlaneAI_StartPathFind(startPathFindParams); 173 | success &= Patch_PassengerBlimpAI_StartPathFind(startPathFindParams); 174 | success &= Patch_PassengerHelicopterAI_StartPathFind(startPathFindParams); 175 | success &= Patch_CargoPlaneAI_StartPathFind(startPathFindParams); 176 | 177 | success &= Patch_FireTruckAI_SetSource(); 178 | success &= Patch_DisasterResponseVehicleAI_SetSource(); 179 | //success &= Patch_BalloonAI_SetSource(); 180 | success &= Patch_CargoTrainAI_SetSource(); 181 | 182 | success &= Patch_CargoPlaneAI_UpdateBuildingTargetPositions(); 183 | } 184 | 185 | private bool Patch_PoliceCarAI_StartPathFind(Type[] parameters) 186 | { 187 | return AddTranspiler(typeof(Patcher), nameof(Patcher.Service_StartPathFind_Transpiler), typeof(PoliceCarAI), "StartPathFind", parameters); 188 | } 189 | private bool Patch_FireTruckAI_StartPathFind(Type[] parameters) 190 | { 191 | return AddTranspiler(typeof(Patcher), nameof(Patcher.Service_StartPathFind_Transpiler), typeof(FireTruckAI), "StartPathFind", parameters); 192 | } 193 | private bool Patch_DisasterResponseVehicleAI_StartPathFind(Type[] parameters) 194 | { 195 | return AddTranspiler(typeof(Patcher), nameof(Patcher.Service_StartPathFind_Transpiler), typeof(DisasterResponseVehicleAI), "StartPathFind", parameters); 196 | } 197 | private bool Patch_ParkMaintenanceVehicleAI_StartPathFind(Type[] parameters) 198 | { 199 | return AddTranspiler(typeof(Patcher), nameof(Patcher.Service_StartPathFind_Transpiler), typeof(ParkMaintenanceVehicleAI), "StartPathFind", parameters); 200 | } 201 | private bool Patch_BusAI_StartPathFind(Type[] parameters) 202 | { 203 | return AddTranspiler(typeof(Patcher), nameof(Patcher.Bus_StartPathFind_Transpiler), typeof(BusAI), "StartPathFind", parameters); 204 | } 205 | private bool Patch_PassengerTrainAI_StartPathFind(Type[] parameters) 206 | { 207 | return AddTranspiler(typeof(Patcher), nameof(Patcher.Train_StartPathFind_Transpiler), typeof(PassengerTrainAI), "StartPathFind", parameters); 208 | } 209 | private bool Patch_PassengerPlaneAI_StartPathFind(Type[] parameters) 210 | { 211 | return AddTranspiler(typeof(Patcher), nameof(Patcher.Plane_StartPathFind_Transpiler), typeof(PassengerPlaneAI), "StartPathFind", parameters); 212 | } 213 | private bool Patch_PassengerBlimpAI_StartPathFind(Type[] parameters) 214 | { 215 | return AddTranspiler(typeof(Patcher), nameof(Patcher.Blimp_StartPathFind_Transpiler), typeof(PassengerBlimpAI), "StartPathFind", parameters); 216 | } 217 | private bool Patch_PassengerHelicopterAI_StartPathFind(Type[] parameters) 218 | { 219 | return AddTranspiler(typeof(Patcher), nameof(Patcher.Copter_StartPathFind_Transpiler), typeof(PassengerHelicopterAI), "StartPathFind", parameters); 220 | } 221 | 222 | private bool Patch_FireTruckAI_SetSource() 223 | { 224 | return AddPrefix(typeof(Patcher), nameof(Patcher.FireTruckAI_SetSource_Prefix), typeof(FireTruckAI), nameof(FireTruckAI.SetSource)); 225 | } 226 | private bool Patch_DisasterResponseVehicleAI_SetSource() 227 | { 228 | return AddPrefix(typeof(Patcher), nameof(Patcher.DisasterResponseAI_SetSource_Prefix), typeof(DisasterResponseVehicleAI), nameof(DisasterResponseVehicleAI.SetSource)); 229 | } 230 | private bool Patch_BalloonAI_SetSource() 231 | { 232 | return AddPrefix(typeof(Patcher), nameof(Patcher.BalloonAI_SetSource_Prefix), typeof(BalloonAI), nameof(BalloonAI.SetSource)); 233 | } 234 | private bool Patch_CargoTrainAI_SetSource() 235 | { 236 | return AddPrefix(typeof(Patcher), nameof(Patcher.CargoTrainAI_SetSource_Prefix), typeof(CargoTrainAI), nameof(CargoTrainAI.SetSource)); 237 | } 238 | 239 | private bool Patch_CargoPlaneAI_UpdateBuildingTargetPositions() 240 | { 241 | return AddTranspiler(typeof(Patcher), nameof(Patcher.CargoPlaneAI_FixRandomizer_Transpiler), typeof(CargoPlaneAI), nameof(CargoPlaneAI.UpdateBuildingTargetPositions)); 242 | } 243 | private bool Patch_CargoPlaneAI_StartPathFind(Type[] parameters) 244 | { 245 | return AddTranspiler(typeof(Patcher), nameof(Patcher.CargoPlaneAI_FixRandomizer_Transpiler), typeof(CargoPlaneAI), "StartPathFind", parameters); 246 | } 247 | 248 | #endregion 249 | 250 | #region METM 251 | 252 | private void Patch_METM(ref bool success) 253 | { 254 | success &= AddTranspiler(typeof(Patcher), nameof(Patcher.METMTargetMethodTranspiler), Type.GetType("MoreEffectiveTransfer.Patch.WarehouseAICalculateSpawnPositionPatch"), "TargetMethod"); 255 | success &= AddTranspiler(typeof(Patcher), nameof(Patcher.METMTargetMethodTranspiler), Type.GetType("MoreEffectiveTransfer.Patch.WarehouseAICalculateUnspawnPositionPatch"), "TargetMethod"); 256 | success &= AddTranspiler(typeof(Patcher), nameof(Patcher.METMPostfixTranspiler), Type.GetType("MoreEffectiveTransfer.Patch.WarehouseAICalculateSpawnPositionPatch"), "Postfix"); 257 | success &= AddTranspiler(typeof(Patcher), nameof(Patcher.METMPostfixTranspiler), Type.GetType("MoreEffectiveTransfer.Patch.WarehouseAICalculateUnspawnPositionPatch"), "Postfix"); 258 | } 259 | 260 | #endregion 261 | 262 | #endregion 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Properties/Localize.da-DK.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Ændre og tilføje køretøjers spawn points 122 | 123 | 124 | Tilføj alle typer køretøjer 125 | 126 | 127 | Tilføj point 128 | 129 | 130 | Tilføj køretøjstype 131 | 132 | 133 | Tilføj køretøjstype 134 | 135 | 136 | {0}° 137 | 138 | 139 | Anvend på alle bygninger af denne type 140 | 141 | 142 | Kopier 143 | 144 | 145 | Kopier punkt 146 | 147 | 148 | Dupliker punkt 149 | 150 | 151 | Intet punkt i denne bygning indeholder disse typer af køretøjer: 152 | 153 | 154 | De vil spawn i standard position. 155 | 156 | 157 | Indsæt 158 | 159 | 160 | Indsæt punkt (tilføj køretøjstyper) 161 | 162 | 163 | Indsæt punkt (erstat køretøjstyper) 164 | 165 | 166 | {0}min 167 | 168 | 169 | Nulstil til standard 170 | 171 | 172 | Bygning #{0} 173 | 174 | 175 | Dette punkt er for langt væk fra vejen for nogle typer af køretøjer, flyt punktet tættere på, ellers vil det ikke virke 176 | 177 | 178 | Spawn 179 | 180 | 181 | Fjern spawn 182 | 183 | 184 | Type 185 | 186 | 187 | Placering 188 | 189 | 190 | Anvend på alle bygninger af denne type 191 | 192 | 193 | Vil du virkelig anvende denne indstilling på alle bygninger af denne type? 194 | 195 | 196 | Bygning #{0} 197 | 198 | 199 | Vælg bygning 200 | 201 | 202 | Helikoptere 203 | 204 | 205 | Fly 206 | 207 | 208 | Service køretøjer 209 | 210 | 211 | Skibe 212 | 213 | 214 | Tog 215 | 216 | 217 | Lastbiler 218 | 219 | 220 | Ambulance 221 | 222 | 223 | Ambulance helikopter 224 | 225 | 226 | Ballon 227 | 228 | 229 | Bus 230 | 231 | 232 | Sporvogn 233 | 234 | 235 | Fragt fly 236 | 237 | 238 | Fragtskib 239 | 240 | 241 | Gods tog 242 | 243 | 244 | Fragt lastbil 245 | 246 | 247 | Katastrofeberedskabs helikopter 248 | 249 | 250 | Katastrofeberedskab 251 | 252 | 253 | Brand helikopter 254 | 255 | 256 | Brandbil 257 | 258 | 259 | Fiskebåd 260 | 261 | 262 | Skraldebil 263 | 264 | 265 | Rustvogn 266 | 267 | 268 | Metro 269 | 270 | 271 | Letbane 272 | 273 | 274 | Park vedligeholdelse 275 | 276 | 277 | Passager luftskib 278 | 279 | 280 | Passager Helikopter 281 | 282 | 283 | Passagerfærge 284 | 285 | 286 | Passagertog 287 | 288 | 289 | Politi 290 | 291 | 292 | Politi helikopter 293 | 294 | 295 | Postbil 296 | 297 | 298 | Vejvedligeholdelse 299 | 300 | 301 | Sneplov 302 | 303 | 304 | Taxi 305 | 306 | 307 | Sporvogn 308 | 309 | 310 | Trolleybus 311 | 312 | 313 | Fejemaskine 314 | 315 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Properties/Localize.fi-FI.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Muuta ja lisää sisään- ja uloskäyntejä 122 | 123 | 124 | Lisää kaikki ajoneuvotyypit 125 | 126 | 127 | Lisää piste 128 | 129 | 130 | Lisää ajoneuvon tyyppi 131 | 132 | 133 | Lisää ajoneuvon tyyppi ryhmään 134 | 135 | 136 | {0}° 137 | 138 | 139 | Käytä kaikissa samanlaisissa rakennuksissa 140 | 141 | 142 | Kopioi 143 | 144 | 145 | Kopioi piste 146 | 147 | 148 | Monista piste 149 | 150 | 151 | Mikään piste rakennuksessa ei sisällä näitä ajoneuvoja: 152 | 153 | 154 | Ne syntyvät oletussijaintiin. 155 | 156 | 157 | Liitä 158 | 159 | 160 | Liitä piste (lisää ajoneuvotyyppejä) 161 | 162 | 163 | Liitä piste (korvaa ajoneuvotyypit) 164 | 165 | 166 | {0}m 167 | 168 | 169 | Palauta oletukseksi 170 | 171 | 172 | Rakennus #{0} 173 | 174 | 175 | Tämä piste on liian kaukana tiestä tietyntyyppisille ajoneuvoille. Siirrä sitä lähemmäksi, muuten se ei toimi 176 | 177 | 178 | Uloskäynti 179 | 180 | 181 | Sisäänkäynti 182 | 183 | 184 | Tyyppi 185 | 186 | 187 | Sijainti 188 | 189 | 190 | Käytä kaikissa samanlaisissa rakennuksissa 191 | 192 | 193 | Haluatko varmasti asettaa nämä asetukset kaikkiin tämäntyyppisiin rakennuksiin? 194 | 195 | 196 | Rakennus #{0} 197 | 198 | 199 | Valitse rakennus 200 | 201 | 202 | Rahtiajoneuvot 203 | 204 | 205 | Helikopterit 206 | 207 | 208 | Oletusarvoiset ajoneuvot 209 | 210 | 211 | Lentokoneet 212 | 213 | 214 | Huoltoajoneuvot 215 | 216 | 217 | Laivat 218 | 219 | 220 | Junat 221 | 222 | 223 | Rekat 224 | 225 | 226 | Kaikki 227 | 228 | 229 | Ambulanssit 230 | 231 | 232 | Pelastushelikopterit 233 | 234 | 235 | Kuumailmapallot 236 | 237 | 238 | Polkupyörät 239 | 240 | 241 | Linja-autot 242 | 243 | 244 | Köysiradan vaunut 245 | 246 | 247 | Rahtilentokoneet 248 | 249 | 250 | Rahtilaivat 251 | 252 | 253 | Rahtijunat 254 | 255 | 256 | Rahtirekka 257 | 258 | 259 | Katastrofiapuhelikopterit 260 | 261 | 262 | Katastrofiapu 263 | 264 | 265 | Palohelikopterit 266 | 267 | 268 | Paloautot 269 | 270 | 271 | Kalastusalukset 272 | 273 | 274 | Roska-autot 275 | 276 | 277 | Ruumisautot 278 | 279 | 280 | Metrot 281 | 282 | 283 | Yksiraiteiset 284 | 285 | 286 | Puiston kunnossapito 287 | 288 | 289 | Ilmalaivat 290 | 291 | 292 | Matkustajahelikopterit 293 | 294 | 295 | Matkustajalautat 296 | 297 | 298 | Matkustajalentokoneet 299 | 300 | 301 | Matkustajalaivat 302 | 303 | 304 | Matkustajajunat 305 | 306 | 307 | Poliisiautot 308 | 309 | 310 | Poliisihelikopterit 311 | 312 | 313 | Posti 314 | 315 | 316 | Yksityislentokoneet 317 | 318 | 319 | Teiden kunnossapito 320 | 321 | 322 | Avaruusraketit 323 | 324 | 325 | Aura-autot 326 | 327 | 328 | Taksit 329 | 330 | 331 | Raitiovaunut 332 | 333 | 334 | Johdinautot 335 | 336 | 337 | Imuauto 338 | 339 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Properties/Localize.hu-HU.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Járművek kezdőpontjának változtatása és létrehozása 122 | 123 | 124 | Összes járműtípus hozzáadása 125 | 126 | 127 | Pont hozzáadása 128 | 129 | 130 | Járműtípus hozzáadása 131 | 132 | 133 | Jármű típus csoport hozzáadása 134 | 135 | 136 | {0}° 137 | 138 | 139 | Alkalmazás az összes ilyen típusú épületre 140 | 141 | 142 | Másolás 143 | 144 | 145 | Pont másolása 146 | 147 | 148 | Pont duplikálása 149 | 150 | 151 | Az épület egyetlen pontja sem tartalmaz ilyen típusú járműveket: 152 | 153 | 154 | Az alapértelmezett helyen fognak megjelenni. 155 | 156 | 157 | Beillesztés 158 | 159 | 160 | {0}m 161 | 162 | 163 | Visszaállítás alapértelmezettre 164 | 165 | 166 | Épület #{0} 167 | 168 | 169 | Ez a pont túl messze lett elhelyezve az úttól bizonyos típusú járműveknek, vidd közelebb, különben nem fog működni 170 | 171 | 172 | Megjelenés 173 | 174 | 175 | Eltűnés 176 | 177 | 178 | Típus 179 | 180 | 181 | Pozíció 182 | 183 | 184 | Alkalmazás az összes azonos típusú épületre 185 | 186 | 187 | Valóban alkalmazni szeretnéd ezt a beállítást minden ilyen típusú épületre? 188 | 189 | 190 | Épület #{0} 191 | 192 | 193 | Válassz épületet 194 | 195 | 196 | Szállító járművek 197 | 198 | 199 | Helikopterek 200 | 201 | 202 | Alapértelmezett járművek 203 | 204 | 205 | Repülők 206 | 207 | 208 | Hajók 209 | 210 | 211 | Vonatok 212 | 213 | 214 | Teherautók 215 | 216 | 217 | Összes 218 | 219 | 220 | Mentőautó 221 | 222 | 223 | Mentőhelikopter 224 | 225 | 226 | Hőlégballon 227 | 228 | 229 | Bicikli 230 | 231 | 232 | Busz 233 | 234 | 235 | Libegő 236 | 237 | 238 | Teherszállító repülőgép 239 | 240 | 241 | Teherszállító hajó 242 | 243 | 244 | Teherszállító vonat 245 | 246 | 247 | Teherautó 248 | 249 | 250 | Katasztrófaelhárító helikopter 251 | 252 | 253 | Katasztrófaelhárító 254 | 255 | 256 | Tűzoltó helikopter 257 | 258 | 259 | Tűzoltóautó 260 | 261 | 262 | Halászhajó 263 | 264 | 265 | Szemetes autó 266 | 267 | 268 | Halottas kocsi 269 | 270 | 271 | Metró 272 | 273 | 274 | Nyeregvasút 275 | 276 | 277 | Parkgondozás 278 | 279 | 280 | Utasszállító léghajó 281 | 282 | 283 | Utasszállító helikopter 284 | 285 | 286 | Utasszállító komp 287 | 288 | 289 | Utasszállító vonat 290 | 291 | 292 | Rendőrség 293 | 294 | 295 | Rendőrségi helikopter 296 | 297 | 298 | Posta 299 | 300 | 301 | Privát repülő 302 | 303 | 304 | Útkarbantartás 305 | 306 | 307 | Rakéta 308 | 309 | 310 | Hókotró 311 | 312 | 313 | Taxi 314 | 315 | 316 | Villamos 317 | 318 | 319 | Trolibusz 320 | 321 | 322 | Szippantós kocsi 323 | 324 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Properties/Localize.pt-PT.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Alterar e adicionar pontos de spawn de veículos 122 | 123 | 124 | [ATUALIZAÇÃO] Adicionado suporte ao DLC Plazas & Promenades. 125 | 126 | 127 | [CORRIGIDO] Spawn point de carro da polícia. 128 | [CORRIGIDO] Camões de bombeiros de resposta a desastres infinitos. 129 | 130 | 131 | [NOVO] Adicionado suporte a camiões de banco da DLC de Distritos Financeiros. 132 | 133 | 134 | Adicionar todos os tipos de veículo 135 | 136 | 137 | Adicionar ponto 138 | 139 | 140 | Adicionar tipo de veículo 141 | 142 | 143 | Adicionar grupo de tipo de veículo 144 | 145 | 146 | {0}° 147 | 148 | 149 | Aplicar a todos os edifícios deste tipo 150 | 151 | 152 | Copiar 153 | 154 | 155 | Copiar ponto 156 | 157 | 158 | Duplicar ponto 159 | 160 | 161 | Nenhum ponto neste edifício contém estes tipos de veículos: 162 | 163 | 164 | Eles aparecerão na posição predefinida. 165 | 166 | 167 | Colar 168 | 169 | 170 | Colar ponto (junta tipo do veículo) 171 | 172 | 173 | Colar ponto (substitui tipo do veículo) 174 | 175 | 176 | {0}m 177 | 178 | 179 | Repor predefinição 180 | 181 | 182 | Edifício #{0} 183 | 184 | 185 | Este ponto ficou muito longe da estrada para algum tipo de veículo, mova-o para perto, caso contrário não funcionará 186 | 187 | 188 | Invocar 189 | 190 | 191 | Destino 192 | 193 | 194 | Tipo 195 | 196 | 197 | Posição 198 | 199 | 200 | Aplicar a todos os edifícios deste tipo 201 | 202 | 203 | Deseja realmente aplicar esta configuração a todos os edifícios deste tipo? 204 | 205 | 206 | Edifício #{0} 207 | 208 | 209 | Selecione o edifício 210 | 211 | 212 | Veículos de carga 213 | 214 | 215 | Helicópteros 216 | 217 | 218 | Veículos padrão 219 | 220 | 221 | Aviões 222 | 223 | 224 | Veículos de serviço 225 | 226 | 227 | Barcos 228 | 229 | 230 | Comboios 231 | 232 | 233 | Camiões 234 | 235 | 236 | Todos 237 | 238 | 239 | Ambulância 240 | 241 | 242 | Helicóptero-ambulância 243 | 244 | 245 | Balão de ar quente 246 | 247 | 248 | Camião bancário 249 | 250 | 251 | Bicicleta 252 | 253 | 254 | Autocarro 255 | 256 | 257 | Teleférico 258 | 259 | 260 | Avião de carga 261 | 262 | 263 | Cargueiro 264 | 265 | 266 | Comboio de carga 267 | 268 | 269 | Camião de carga 270 | 271 | 272 | Helicóptero de resposta a desastres 273 | 274 | 275 | Resposta a desastres 276 | 277 | 278 | Helicóptero de combate a incêndios 279 | 280 | 281 | Camião dos bombeiros 282 | 283 | 284 | Barco de pesca 285 | 286 | 287 | Camião do lixo 288 | 289 | 290 | Carro funerário 291 | 292 | 293 | Metro 294 | 295 | 296 | Monotrilho 297 | 298 | 299 | Manutenção de parques 300 | 301 | 302 | Dirigível 303 | 304 | 305 | Helicóptero 306 | 307 | 308 | Ferry 309 | 310 | 311 | Avião de passageiros 312 | 313 | 314 | Navio de passageiros 315 | 316 | 317 | Comboio de passageiros 318 | 319 | 320 | Polícia 321 | 322 | 323 | Helicóptero da polícia 324 | 325 | 326 | Correios 327 | 328 | 329 | Avião privado 330 | 331 | 332 | Manutenção de parques 333 | 334 | 335 | Foguetão 336 | 337 | 338 | Limpa-neve 339 | 340 | 341 | Táxi 342 | 343 | 344 | Elétrico 345 | 346 | 347 | Trolleybus 348 | 349 | 350 | Camião de vácuo 351 | 352 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Properties/Localize.ro-RO.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Schimbați și adaugați punctele de spawn al vehiculelor 122 | 123 | 124 | [UPDATED] Adăugat suportul pentru Plazas & Promenades DLC. 125 | 126 | 127 | [FIXED] Punctul de spawn al mașinii de poliție. 128 | [FIXED] Camioane de pompieri și camioane de urgență dezastre infinite. 129 | 130 | 131 | Adăugați toate tipurile de vehicule 132 | 133 | 134 | Adăugați punct 135 | 136 | 137 | Adăugați un tip de vehicul 138 | 139 | 140 | Adăugați un grup de tipuri de vehicule 141 | 142 | 143 | {0}° 144 | 145 | 146 | Aplicați la toate clădirile din acest tip 147 | 148 | 149 | Copiere 150 | 151 | 152 | Copiază punctul 153 | 154 | 155 | Duplică punctul 156 | 157 | 158 | Niciun punct din această clădire conține aceste tipuri de vehicule: 159 | 160 | 161 | Ele o să spawneze in pozițiile implicite. 162 | 163 | 164 | Lipire 165 | 166 | 167 | Lipiți punctul (adăugați tipurile de vehicule) 168 | 169 | 170 | Lipiți punctul (înlocuiți tipurile de vehicule) 171 | 172 | 173 | {0}m 174 | 175 | 176 | Resetare la valori implicite 177 | 178 | 179 | Clădirea #{0} 180 | 181 | 182 | Acest punct a fost plasat prea departe din stradă pentru câteva tipuri de vehicule, plasați-l mai aproape, dacă nu el nu o să funcționeze 183 | 184 | 185 | Spawn 186 | 187 | 188 | Despawn 189 | 190 | 191 | Tip 192 | 193 | 194 | Poziție 195 | 196 | 197 | Aplicați la toate clădirile din tipul 198 | 199 | 200 | Sigur doriți să aplicați această setare pentru toate clădirile din acest tip? 201 | 202 | 203 | Clădirea #{0} 204 | 205 | 206 | Selectați clădirea 207 | 208 | 209 | Vehicule de marfă 210 | 211 | 212 | Elicoptere 213 | 214 | 215 | Vehicule implicite 216 | 217 | 218 | Avioane 219 | 220 | 221 | Vehicule utilitare 222 | 223 | 224 | Nave 225 | 226 | 227 | Trenuri 228 | 229 | 230 | Camioane 231 | 232 | 233 | Toate 234 | 235 | 236 | Ambulanță 237 | 238 | 239 | Elicopter ambulanță 240 | 241 | 242 | Balon cu aer cald 243 | 244 | 245 | Camion bancar 246 | 247 | 248 | Bicicletă 249 | 250 | 251 | Autobuz 252 | 253 | 254 | Telecabină 255 | 256 | 257 | Avioane de marfă 258 | 259 | 260 | Nave de marfă 261 | 262 | 263 | Trenuri de marfă 264 | 265 | 266 | Camioane de marfă 267 | 268 | 269 | Elicopter de urgențe 270 | 271 | 272 | Vehicule de urgență 273 | 274 | 275 | Elicopter de pompieri 276 | 277 | 278 | Mașină de pompieri 279 | 280 | 281 | Barcă de pescuit 282 | 283 | 284 | Mașină de gunoi 285 | 286 | 287 | Mașină funebră 288 | 289 | 290 | Metrou 291 | 292 | 293 | Monoșină 294 | 295 | 296 | Autoutilitare ecologice 297 | 298 | 299 | Dirijabil 300 | 301 | 302 | Elicopter transport persoane 303 | 304 | 305 | Feribot transport persoane 306 | 307 | 308 | Avion transport persoane 309 | 310 | 311 | Navă transport persoane 312 | 313 | 314 | Tren transport persoane 315 | 316 | 317 | Mașină de poliție 318 | 319 | 320 | Elicopter de poliție 321 | 322 | 323 | Mașină poștală 324 | 325 | 326 | Avion privat 327 | 328 | 329 | Autoutilitare stradă 330 | 331 | 332 | Rachetă 333 | 334 | 335 | Plug de zăpadă 336 | 337 | 338 | Taxi 339 | 340 | 341 | Tramvai 342 | 343 | 344 | Troleibuz 345 | 346 | 347 | Mașină pentru vidanjări 348 | 349 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Properties/Localize.tr-TR.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Araç oluşma noktası ekleyin veya değiştirin 122 | 123 | 124 | [UPDATED] Plazalar ve Gezinti Yerleri DLC Desteği Eklendi. 125 | 126 | 127 | Tüm araç türlerini ekle 128 | 129 | 130 | Nokta ekle 131 | 132 | 133 | Araç türü ekle 134 | 135 | 136 | Araç türü grubu ekle 137 | 138 | 139 | {0}° 140 | 141 | 142 | Bu türdeki tüm binalara uygula 143 | 144 | 145 | Kopyala 146 | 147 | 148 | Noktayı kopyala 149 | 150 | 151 | Noktayı yinele 152 | 153 | 154 | Bu bina belirtilen türde araç içermemektedir: 155 | 156 | 157 | Araçlar varsayılan konumda oluşacaklar. 158 | 159 | 160 | Yapıştır 161 | 162 | 163 | Noktayı yapıştır (araç türlerini değiştir) 164 | 165 | 166 | Noktayı yapıştır (araç türlerini değiştir) 167 | 168 | 169 | {0}m 170 | 171 | 172 | Varsayılanlara sıfırla 173 | 174 | 175 | #{0} numaralı bina 176 | 177 | 178 | Bu nokta bazı araçlar için çok uzağa konulmuş, yakınlaştırmazsanız çalışmayacaktır 179 | 180 | 181 | Başlangıç noktası 182 | 183 | 184 | Yok et 185 | 186 | 187 | Tür 188 | 189 | 190 | Konum 191 | 192 | 193 | Seçilen türdeki tüm binalara uygula 194 | 195 | 196 | Gerçekten bu türdeki tüm binalara bunu uygulamak istediğinize emin misiniz? 197 | 198 | 199 | #{0} nolu bina 200 | 201 | 202 | Bina seçiniz 203 | 204 | 205 | Kargo taşıtları 206 | 207 | 208 | Helikopterler 209 | 210 | 211 | Varsayılan taşıtlar 212 | 213 | 214 | Uçaklar 215 | 216 | 217 | Hizmet araçları 218 | 219 | 220 | Gemiler 221 | 222 | 223 | Trenler 224 | 225 | 226 | Kamyonlar 227 | 228 | 229 | Tümü 230 | 231 | 232 | Ambulans 233 | 234 | 235 | Ambulans Helicopter 236 | 237 | 238 | Hava Balonu 239 | 240 | 241 | Bisiklet 242 | 243 | 244 | Otobüs 245 | 246 | 247 | Teleferik 248 | 249 | 250 | Kargo uçağı 251 | 252 | 253 | Yük gemisi 254 | 255 | 256 | Kargo treni 257 | 258 | 259 | Yük kamyonu 260 | 261 | 262 | Afet müdahale helikopteri 263 | 264 | 265 | Afet müdahale 266 | 267 | 268 | İtfaye helikopteri 269 | 270 | 271 | İtfaiye aracı 272 | 273 | 274 | Balıkçı teknesi 275 | 276 | 277 | Çöp kamyonu 278 | 279 | 280 | Cenaze aracı 281 | 282 | 283 | Metro 284 | 285 | 286 | Monoray 287 | 288 | 289 | Park Hizmetleri 290 | 291 | 292 | Yolcu balonu 293 | 294 | 295 | Yolcu helikopteri 296 | 297 | 298 | Yolcu feribotu 299 | 300 | 301 | Yolcu uçağı 302 | 303 | 304 | Yolcu gemisi 305 | 306 | 307 | Yolcu treni 308 | 309 | 310 | Polis 311 | 312 | 313 | Polis helikopteri 314 | 315 | 316 | Posta 317 | 318 | 319 | Özel uçak 320 | 321 | 322 | Yol Hizmetleri 323 | 324 | 325 | Roket 326 | 327 | 328 | Kar küreme aracı 329 | 330 | 331 | Taksi 332 | 333 | 334 | Tramvay 335 | 336 | 337 | Troleybüs 338 | 339 | 340 | Su pompa kamyonu 341 | 342 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Properties/Localize.vi-VN.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Properties/Localize.zh-TW.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | [新功能] 新增用滑鼠拖曳點的功能。 122 | [新功能] 新增可以查看點的實際高度的3D標記。 123 | [更新] 新的UI風格。 124 | [新功能] 車輛標籤根據車輛類型有不同的顏色。 125 | [新功能] 新增添加新點的快捷鍵。 126 | [修復] 新增將貨車點設置為魚市場的功能。 127 | 128 | 129 | [UPDATED] 新增了對 Hotels & Retreats DLC 更新的支援。 130 | [TRANSLATION] 新增了繁體中文、泰語和烏克蘭語翻譯。 131 | 132 | 133 | 新增所有載具類型 134 | 135 | 136 | 新增點 137 | 138 | 139 | 新增載具類型 140 | 141 | 142 | 新增載具類型組 143 | 144 | 145 | {0}° 146 | 147 | 148 | 應用於全部同類建築 149 | 150 | 151 | 複製 152 | 153 | 154 | 複製點 155 | 156 | 157 | 完全複製點 158 | 159 | 160 | 此建築沒有任何包含以下類別載具的點: 161 | 162 | 163 | 載具將在預設位置生成 164 | 165 | 166 | 複製 167 | 168 | 169 | 複製點(新增載具類型) 170 | 171 | 172 | 複製點(替換載具類型) 173 | 174 | 175 | {0}公尺 176 | 177 | 178 | 重置為預設值 179 | 180 | 181 | 建築 #{0} 182 | 183 | 184 | 對某些類型的載具來說,此點距離道路過遠。請靠近道路,否則它將無法工作 185 | 186 | 187 | 生成 188 | 189 | 190 | 消失 191 | 192 | 193 | 跟隨地面 194 | 195 | 196 | 類型 197 | 198 | 199 | 位置 200 | 201 | 202 | 為面板的載具上色 203 | 204 | 205 | 使用立體顯示 206 | 207 | 208 | 新增點 209 | 210 | 211 | 適用於所有同類型的建築 212 | 213 | 214 | 確定將本設置應用於所有同類型的建築嗎? 215 | 216 | 217 | 設置正確 218 | 219 | 220 | 拖曳標記以移動 221 | 222 | 223 | 空生成點 224 | 225 | 226 | 建築 #{0} 227 | 228 | 229 | 設置錯誤 230 | 231 | 232 | 按下 {0} 以變更高度 233 | 234 | 235 | 選擇建築 236 | 237 | 238 | 貨運載具 239 | 240 | 241 | 直升機 242 | 243 | 244 | 預設載具 245 | 246 | 247 | 應急服務載具 248 | 249 | 250 | 飛機 251 | 252 | 253 | 大眾運輸工具 254 | 255 | 256 | 維護用載具 257 | 258 | 259 | 船舶 260 | 261 | 262 | 火車 263 | 264 | 265 | 貨車 266 | 267 | 268 | 全部 269 | 270 | 271 | 救護車 272 | 273 | 274 | 救護直升機 275 | 276 | 277 | 熱氣球 278 | 279 | 280 | 運鈔車 281 | 282 | 283 | 自行車 284 | 285 | 286 | 公車 287 | 288 | 289 | 纜車 290 | 291 | 292 | 貨機 293 | 294 | 295 | 貨船 296 | 297 | 298 | 貨運列車 299 | 300 | 301 | 貨運卡車 302 | 303 | 304 | 災難反應直升機 305 | 306 | 307 | 應急回應 308 | 309 | 310 | 消防直升機 311 | 312 | 313 | 消防車 314 | 315 | 316 | 漁船 317 | 318 | 319 | 垃圾車 320 | 321 | 322 | 靈車 323 | 324 | 325 | 地鐵列車 326 | 327 | 328 | 單軌列車 329 | 330 | 331 | 公園維護 332 | 333 | 334 | 載客飛艇 335 | 336 | 337 | 載客直升機 338 | 339 | 340 | 載客輪渡 341 | 342 | 343 | 載客飛機 344 | 345 | 346 | 郵輪 347 | 348 | 349 | 載客列車 350 | 351 | 352 | 警車 353 | 354 | 355 | 警用直升機 356 | 357 | 358 | 郵政服務車輛 359 | 360 | 361 | 私人飛機 362 | 363 | 364 | 道路維護車 365 | 366 | 367 | 火箭 368 | 369 | 370 | 除雪車 371 | 372 | 373 | 計程車 374 | 375 | 376 | 路面電車 377 | 378 | 379 | 無軌電車 380 | 381 | 382 | 真空吸水車 383 | 384 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Normal": { 4 | "commandName": "Executable", 5 | "executablePath": "C:\\Program Files (x86)\\Steam\\steam.exe", 6 | "commandLineArgs": "-applaunch 255710 --refreshWorkshop" 7 | }, 8 | "No Workshop": { 9 | "commandName": "Executable", 10 | "executablePath": "C:\\Program Files (x86)\\Steam\\steam.exe", 11 | "commandLineArgs": "-applaunch 255710 --noWorkshop" 12 | }, 13 | "Release": { 14 | "commandName": "Executable", 15 | "executablePath": "C:\\Program Files (x86)\\Steam\\steamapps\\workshop\\content\\255710\\2953447919\\App\\Skyve.exe", 16 | "commandLineArgs": " -launch -noWindow -profile Release" 17 | }, 18 | "Debug": { 19 | "commandName": "Executable", 20 | "executablePath": "C:\\Program Files (x86)\\Steam\\steamapps\\workshop\\content\\255710\\2953447919\\App\\Skyve.exe", 21 | "commandLineArgs": "-launch -noWindow -profile Debug" 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/HeaderButtons/AddAllVehiclesHeaderButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/HeaderButtons/AddAllVehiclesHeaderButton.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/HeaderButtons/AddVehicleGroupHeaderButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/HeaderButtons/AddVehicleGroupHeaderButton.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/HeaderButtons/AddVehicleHeaderButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/HeaderButtons/AddVehicleHeaderButton.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/HeaderButtons/AppendHeaderButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/HeaderButtons/AppendHeaderButton.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/HeaderButtons/ApplyAllHeaderButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/HeaderButtons/ApplyAllHeaderButton.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/HeaderButtons/CopyHeaderButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/HeaderButtons/CopyHeaderButton.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/HeaderButtons/DuplicateHeaderButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/HeaderButtons/DuplicateHeaderButton.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/HeaderButtons/HeaderButtons.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/HeaderButtons/HeaderButtons.psd -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/HeaderButtons/PasteHeaderButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/HeaderButtons/PasteHeaderButton.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/HeaderButtons/ResetHeaderButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/HeaderButtons/ResetHeaderButton.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/Icons/InfoIcon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/Icons/InfoIcon.psd -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/Icons/InfoNormal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/Icons/InfoNormal.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/Icons/InfoPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/Icons/InfoPressed.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/PreviewImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/PreviewImage.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/UUIButton/UUIButton.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/UUIButton/UUIButton.psd -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/UUIButton/UUIButtonHovered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/UUIButton/UUIButtonHovered.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/UUIButton/UUIButtonNormal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/UUIButton/UUIButtonNormal.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Resources/UUIButton/UUIButtonPressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/BuildingSpawnPoints/Resources/UUIButton/UUIButtonPressed.png -------------------------------------------------------------------------------- /BuildingSpawnPoints/Settings.cs: -------------------------------------------------------------------------------- 1 | using ColossalFramework; 2 | using ModsCommon; 3 | using ModsCommon.Settings; 4 | 5 | namespace BuildingSpawnPoints 6 | { 7 | public class Settings : BaseSettings 8 | { 9 | public static SavedBool ShowDebugProperties { get; } = new SavedBool(nameof(ShowDebugProperties), SettingsFile, false); 10 | public static SavedBool ColorTags { get; } = new SavedBool(nameof(ColorTags), SettingsFile, true); 11 | public static SavedBool Marker3D { get; } = new SavedBool(nameof(Marker3D), SettingsFile, true); 12 | 13 | protected override void FillSettings() 14 | { 15 | base.FillSettings(); 16 | 17 | AddLanguage(GeneralTab); 18 | 19 | var generalSection = GeneralTab.AddOptionsSection(CommonLocalize.Settings_General); 20 | generalSection.AddKeyMappingButton(SpawnPointsTool.ActivationShortcut); 21 | generalSection.AddKeyMappingButton(SpawnPointsTool.AddPointShortcut); 22 | generalSection.AddToggle(Localize.Settings_Marker3D, Marker3D); 23 | generalSection.AddToggle(Localize.Settings_ColorTags, ColorTags); 24 | #if DEBUG 25 | var otherSection = DebugTab.AddOptionsSection("Properties"); 26 | otherSection.AddToggle("Show debug properties", ShowDebugProperties); 27 | #endif 28 | AddNotifications(GeneralTab); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Tool/DragPoint.cs: -------------------------------------------------------------------------------- 1 | using ModsCommon; 2 | using ModsCommon.Utilities; 3 | using UnityEngine; 4 | using static ToolBase; 5 | 6 | namespace BuildingSpawnPoints 7 | { 8 | public class DragSpawnPointsMode : SpawnPointsToolMode 9 | { 10 | public override ToolModeType Type => ToolModeType.Drag; 11 | public BuildingSpawnPoint DragPoint { get; set; } = null; 12 | public bool DragOverlay { get; protected set; } 13 | 14 | private Vector3 CachedPosition { get; set; } 15 | private int WasModifierPressed { get; set; } 16 | 17 | protected override void Reset(IToolMode prevMode) 18 | { 19 | if (prevMode is EditSpawnPointsMode editMode) 20 | { 21 | DragPoint = editMode.HoverPoint; 22 | DragOverlay = editMode.HoverOverlay; 23 | } 24 | else 25 | { 26 | DragPoint = null; 27 | DragOverlay = false; 28 | } 29 | WasModifierPressed = 0; 30 | Cache(); 31 | } 32 | private void Cache() 33 | { 34 | ref var building = ref Tool.Data.Id.GetBuilding(); 35 | DragPoint.GetAbsolute(ref building, out var position, out _, PositionType.Final); 36 | CachedPosition = position; 37 | } 38 | 39 | public override void OnToolUpdate() 40 | { 41 | var isPressed = 0; 42 | if (Utility.AltIsPressed) 43 | isPressed += 1; 44 | if (Utility.CtrlIsPressed) 45 | isPressed += 2; 46 | if (Utility.ShiftIsPressed) 47 | isPressed += 4; 48 | 49 | if (isPressed != WasModifierPressed && !DragOverlay) 50 | { 51 | Cache(); 52 | } 53 | WasModifierPressed = isPressed; 54 | } 55 | public override void OnToolGUI(Event e) 56 | { 57 | if (!Input.GetMouseButton(0)) 58 | Exit(); 59 | } 60 | public override void OnMouseDrag(Event e) 61 | { 62 | Vector3 position; 63 | if (DragOverlay) 64 | { 65 | position = Tool.MouseWorldPosition; 66 | position.y = CachedPosition.y; 67 | } 68 | else if (Utility.OnlyShiftIsPressed) 69 | { 70 | position = CachedPosition; 71 | var plane = new Plane(Tool.CameraDirection, CachedPosition); 72 | if (plane.Raycast(Tool.MouseRay, out var rayT)) 73 | position.y = Mathf.Clamp((Tool.MouseRay.origin + Tool.MouseRay.direction * rayT).y, -1024f, 1024f); 74 | } 75 | else 76 | { 77 | position = Tool.Ray.GetRayPosition(CachedPosition.y, out _); 78 | } 79 | 80 | ref var building = ref Tool.Data.Id.GetBuilding(); 81 | DragPoint.SetAbsolute(ref building, position); 82 | 83 | Tool.Panel.SelectPoint(DragPoint); 84 | } 85 | public override void OnPrimaryMouseClicked(Event e) => Exit(); 86 | public override void OnMouseUp(Event e) => Exit(); 87 | private void Exit() => Tool.SetDefaultMode(); 88 | public override void RenderGeometry(RenderManager.CameraInfo cameraInfo) 89 | { 90 | DragPoint.RenderGeometry(cameraInfo, true); 91 | } 92 | public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) 93 | { 94 | DragPoint.Render(cameraInfo, true); 95 | } 96 | public override bool GetExtraInfo(out string text, out Color color, out float size, out Vector3 position, out Vector3 direction) 97 | { 98 | ref var building = ref Tool.Data.Id.GetBuilding(); 99 | DragPoint.GetAbsolute(ref building, out var absPos, out var target); 100 | direction = absPos - target; 101 | position = absPos + direction * 2f; 102 | 103 | size = 2f; 104 | color = CommonColors.Yellow; 105 | 106 | if (Utility.OnlyShiftIsPressed) 107 | { 108 | var h = absPos.y - BuildingSpawnPoint.GetHeightWithWater(absPos); 109 | var hSign = h < 0 ? "-" : h > 0 ? "+" : ""; 110 | text = $"{hSign}{Mathf.Abs(h):0.0}"; 111 | } 112 | else 113 | { 114 | var relPos = DragPoint.Position.Value; 115 | var xSign = relPos.x < 0 ? "-" : relPos.x > 0 ? "+" : ""; 116 | var zSign = relPos.z < 0 ? "-" : relPos.z > 0 ? "+" : ""; 117 | text = $"X: {xSign}{Mathf.Abs(relPos.x):0.0}\nY: {zSign}{Mathf.Abs(relPos.z):0.0}"; 118 | } 119 | 120 | return true; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Tool/EditPoint.cs: -------------------------------------------------------------------------------- 1 | using ModsCommon; 2 | using ModsCommon.Utilities; 3 | using UnityEngine; 4 | using static ToolBase; 5 | 6 | namespace BuildingSpawnPoints 7 | { 8 | public class EditSpawnPointsMode : SpawnPointsToolMode 9 | { 10 | public override ToolModeType Type => ToolModeType.Edit; 11 | 12 | public BuildingSpawnPoint HoverPoint { get; protected set; } 13 | public bool HoverOverlay { get; protected set; } 14 | 15 | public override string GetToolInfo() 16 | { 17 | if (HoverPoint != null) 18 | { 19 | var correct = string.Empty; 20 | var incorrect = string.Empty; 21 | var correctLength = 0; 22 | var incorrectLength = 0; 23 | foreach (var category in HoverPoint.SelectedCategories) 24 | { 25 | if (HoverPoint.IsServiceCorrect(category.GetService())) 26 | AddCategory(category, ref correct, ref correctLength); 27 | else 28 | AddCategory(category, ref incorrect, ref incorrectLength); 29 | } 30 | 31 | if (!string.IsNullOrEmpty(correct) && !string.IsNullOrEmpty(incorrect)) 32 | return $"{Localize.Tool_InfoCorrect.AddActionColor()}\n{correct.AddActionColor()}\n\n{Localize.Tool_InfoIncorrect.AddWarningColor()}\n{incorrect.AddWarningColor()}"; 33 | else if (!string.IsNullOrEmpty(correct)) 34 | return $"{Localize.Tool_InfoCorrect.AddActionColor()}\n{correct.AddActionColor()}"; 35 | else if (!string.IsNullOrEmpty(incorrect)) 36 | return $"{Localize.Tool_InfoIncorrect.AddWarningColor()}\n{incorrect.AddWarningColor()}"; 37 | else 38 | return Localize.Tool_InfoEmptyPoint; 39 | 40 | static void AddCategory(VehicleCategory category, ref string list, ref int length) 41 | { 42 | var name = category.Description(); 43 | 44 | if (length == 0) 45 | { 46 | list = name; 47 | length = name.Length; 48 | } 49 | else if (length + name.Length <= 50) 50 | { 51 | list = $"{list} | {name}"; 52 | length += name.Length + 3; 53 | } 54 | else 55 | { 56 | list = $"{list}\n{name}"; 57 | length = name.Length; 58 | } 59 | } 60 | } 61 | else 62 | return Localize.Tool_InfoDragPoint + '\n' + string.Format(Localize.Tool_InfoPointHeight, LocalizeExtension.Shift.AddInfoColor()); 63 | } 64 | public override void OnToolUpdate() 65 | { 66 | if (SingletonTool.Instance.MouseRayValid) 67 | { 68 | ref var building = ref Tool.Data.Id.GetBuilding(); 69 | foreach (var point in Tool.Data.Points) 70 | { 71 | point.GetAbsolute(ref building, out var position, out _, PositionType.Final); 72 | var bounds = new Bounds(position, new Vector3(2f, 2f, 2f)); 73 | if (bounds.IntersectRay(SingletonTool.Instance.MouseRay)) 74 | { 75 | HoverPoint = point; 76 | HoverOverlay = false; 77 | return; 78 | } 79 | } 80 | 81 | foreach (var point in Tool.Data.Points) 82 | { 83 | point.GetAbsolute(ref building, out var position, out _, PositionType.OnGround); 84 | var bounds = new Bounds(position, new Vector3(2f, 2f, 2f)); 85 | if (bounds.IntersectRay(SingletonTool.Instance.MouseRay)) 86 | { 87 | HoverPoint = point; 88 | HoverOverlay = true; 89 | return; 90 | } 91 | } 92 | } 93 | 94 | HoverPoint = null; 95 | } 96 | public override void OnMouseDrag(Event e) 97 | { 98 | if (HoverPoint != null) 99 | Tool.SetMode(ToolModeType.Drag); 100 | } 101 | 102 | public override void OnSecondaryMouseClicked() 103 | { 104 | Tool.SetData(null); 105 | Tool.SetMode(ToolModeType.Select); 106 | } 107 | public override void RenderGeometry(RenderManager.CameraInfo cameraInfo) 108 | { 109 | foreach (var point in Tool.Data.Points) 110 | { 111 | if (point == Tool.Panel.HoverPoint) 112 | Tool.Panel.RenderGeometry(cameraInfo); 113 | else 114 | point.RenderGeometry(cameraInfo, point == HoverPoint); 115 | } 116 | } 117 | public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) 118 | { 119 | foreach (var point in Tool.Data.Points) 120 | { 121 | if (point == Tool.Panel.HoverPoint) 122 | Tool.Panel.Render(cameraInfo); 123 | else 124 | point.Render(cameraInfo, point == HoverPoint); 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Tool/SelectBuilding.cs: -------------------------------------------------------------------------------- 1 | using ModsCommon; 2 | using ModsCommon.Utilities; 3 | using UnityEngine; 4 | using static ToolBase; 5 | 6 | namespace BuildingSpawnPoints 7 | { 8 | public class SelectBuildingMode : SpawnPointsToolMode 9 | { 10 | public override ToolModeType Type => ToolModeType.Select; 11 | public override bool ShowPanel => false; 12 | 13 | private ushort HoverBuildingId { get; set; } = 0; 14 | private bool IsHoverBuilding => HoverBuildingId != 0; 15 | 16 | public override void OnToolUpdate() 17 | { 18 | if (Tool.MouseRayValid) 19 | { 20 | var input = new RaycastInput(Tool.MouseRay, Camera.main.farClipPlane) 21 | { 22 | m_ignoreTerrain = true, 23 | m_ignoreBuildingFlags = Building.Flags.None, 24 | }; 25 | input.m_buildingService.m_itemLayers = ItemClass.Layer.Default; 26 | 27 | if (SpawnPointsTool.RayCast(input, out var output)) 28 | { 29 | if (output.m_building.GetBuilding().m_flags.IsSet(Building.Flags.Untouchable)) 30 | HoverBuildingId = Building.FindParentBuilding(output.m_building); 31 | else 32 | HoverBuildingId = output.m_building; 33 | return; 34 | } 35 | } 36 | 37 | HoverBuildingId = 0; 38 | } 39 | 40 | public override void OnPrimaryMouseClicked(Event e) 41 | { 42 | if (IsHoverBuilding) 43 | { 44 | Tool.SetData(SingletonManager.Instance[HoverBuildingId, Options.Default]); 45 | Tool.SetDefaultMode(); 46 | } 47 | } 48 | public override void OnMouseUp(Event e) => OnPrimaryMouseClicked(e); 49 | public override void OnSecondaryMouseClicked() => Tool.Disable(); 50 | 51 | public override string GetToolInfo() 52 | { 53 | if (IsHoverBuilding) 54 | return string.Format(Localize.Tool_InfoHoverBuilding, HoverBuildingId); 55 | else 56 | return Localize.Tool_InfoSelectBuilding; 57 | } 58 | public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) 59 | { 60 | if (IsHoverBuilding) 61 | { 62 | var building = HoverBuildingId.GetBuilding(); 63 | BuildingTool.RenderOverlay(cameraInfo, ref building, CommonColors.Yellow, CommonColors.Yellow); 64 | 65 | var i = 0; 66 | while (building.m_subBuilding != 0 && i < BuildingManager.MAX_BUILDING_COUNT) 67 | { 68 | building = building.m_subBuilding.GetBuilding(); 69 | BuildingTool.RenderOverlay(cameraInfo, ref building, CommonColors.Yellow, CommonColors.Yellow); 70 | i += 1; 71 | } 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Tool/Tool.cs: -------------------------------------------------------------------------------- 1 | using BuildingSpawnPoints.UI; 2 | using BuildingSpawnPoints.Utilities; 3 | using ColossalFramework; 4 | using ColossalFramework.Math; 5 | using ColossalFramework.UI; 6 | using ModsCommon; 7 | using ModsCommon.UI; 8 | using ModsCommon.Utilities; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Text; 13 | using System.Xml.Linq; 14 | using UnityEngine; 15 | using static ToolBase; 16 | 17 | namespace BuildingSpawnPoints 18 | { 19 | public class SpawnPointsTool : BaseTool 20 | { 21 | public static SpawnPointsShortcut ActivationShortcut { get; } = new SpawnPointsShortcut(nameof(ActivationShortcut), nameof(CommonLocalize.Settings_ShortcutActivateTool), SavedInputKey.Encode(KeyCode.P, true, false, false)); 22 | 23 | public static SpawnPointsShortcut AddPointShortcut { get; } = new SpawnPointsShortcut(nameof(AddPointShortcut), nameof(Localize.Settings_ShortcutAddNewPoint), SavedInputKey.Encode(KeyCode.A, true, true, false), () => SingletonTool.Instance.Panel.AddPoint(), ToolModeType.Edit); 24 | 25 | public override IEnumerable Shortcuts 26 | { 27 | get 28 | { 29 | yield return AddPointShortcut; 30 | } 31 | } 32 | 33 | public override Shortcut Activation => ActivationShortcut; 34 | protected override IToolMode DefaultMode => ToolModes[ToolModeType.Select]; 35 | public BuildingSpawnPointsPanel Panel => SingletonItem.Instance; 36 | 37 | public BuildingData Data { get; private set; } 38 | 39 | private XElement Buffer { get; set; } 40 | public bool IsBufferEmpty => Buffer == null; 41 | 42 | protected override UITextureAtlas UUIAtlas => SpawnPointsTextures.Atlas; 43 | protected override string UUINormalSprite => SpawnPointsTextures.UUIButtonNormal; 44 | protected override string UUIHoveredSprite => SpawnPointsTextures.UUIButtonHovered; 45 | protected override string UUIPressedSprite => SpawnPointsTextures.UUIButtonPressed; 46 | protected override string UUIDisabledSprite => string.Empty; 47 | 48 | protected override IEnumerable> GetModes() 49 | { 50 | yield return CreateToolMode(); 51 | yield return CreateToolMode(); 52 | yield return CreateToolMode(); 53 | } 54 | 55 | protected override void InitProcess() 56 | { 57 | base.InitProcess(); 58 | BuildingSpawnPointsPanel.CreatePanel(); 59 | } 60 | 61 | public void SetDefaultMode() => SetMode(ToolModeType.Edit); 62 | protected override void SetModeNow(IToolMode mode) 63 | { 64 | base.SetModeNow(mode); 65 | Panel.Active = (Mode as SpawnPointsToolMode)?.ShowPanel == true; 66 | } 67 | public void SetData(BuildingData data) 68 | { 69 | Data = data; 70 | Panel.SetData(Data); 71 | } 72 | 73 | public void Copy() 74 | { 75 | SingletonMod.Logger.Debug($"Copy data"); 76 | Buffer = Data.ToXml(); 77 | Panel?.RefreshHeader(); 78 | } 79 | public void Paste() 80 | { 81 | SingletonMod.Logger.Debug($"Paste data"); 82 | 83 | if (Buffer == null) 84 | return; 85 | 86 | Data.FromXml(SingletonMod.Version, Buffer); 87 | Panel.RefreshPanel(); 88 | } 89 | public void ResetToDefault() 90 | { 91 | SingletonMod.Logger.Debug($"Reset to default"); 92 | 93 | Data.ResetToDefault(); 94 | Panel.RefreshPanel(); 95 | } 96 | public void ApplyToAll() 97 | { 98 | SingletonMod.Logger.Debug($"Apply to all"); 99 | 100 | var messageBox = MessageBox.Show(); 101 | messageBox.CaptionText = Localize.Tool_ApplyToAllCaption; 102 | messageBox.MessageText = Localize.Tool_ApplyToAllMessage; 103 | messageBox.OnButton1Click = Apply; 104 | 105 | bool Apply() 106 | { 107 | var config = Data.ToXml(); 108 | var info = Data.Id.GetBuilding().Info; 109 | var version = SingletonMod.Version; 110 | 111 | var buildings = BuildingManager.instance.m_buildings.m_buffer; 112 | for (ushort i = 0; i < buildings.Length; i += 1) 113 | { 114 | if (i == Data.Id) 115 | continue; 116 | 117 | if (buildings[i].Info == info && buildings[i].m_flags.IsSet(Building.Flags.Created) && SingletonManager.Instance[i, Options.Create] is BuildingData data) 118 | data.FromXml(version, config); 119 | } 120 | 121 | return true; 122 | } 123 | } 124 | 125 | public static new bool RayCast(RaycastInput input, out RaycastOutput output) => ToolBase.RayCast(input, out output); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Tool/Utilites.cs: -------------------------------------------------------------------------------- 1 | using ColossalFramework; 2 | using ModsCommon; 3 | using System; 4 | 5 | namespace BuildingSpawnPoints 6 | { 7 | public abstract class SpawnPointsToolMode : BaseToolMode, IToolMode, IToolModePanel 8 | { 9 | public abstract ToolModeType Type { get; } 10 | public virtual bool ShowPanel => true; 11 | } 12 | public enum ToolModeType 13 | { 14 | None = 0, 15 | Select = 1, 16 | Edit = 2, 17 | Drag = 4, 18 | } 19 | 20 | public class SpawnPointsShortcut : ToolShortcut 21 | { 22 | public SpawnPointsShortcut(string name, string labelKey, InputKey key, Action action = null, ToolModeType mode = ToolModeType.None) : base(name, labelKey, key, action, mode) { } 23 | } 24 | public class SpawnPointsToolThreadingExtension : BaseUUIThreadingExtension { } 25 | public class SpawnPointsToolLoadingExtension : BaseUUIToolLoadingExtension { } 26 | } 27 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/UI/Panel.cs: -------------------------------------------------------------------------------- 1 | using BuildingSpawnPoints.Utilities; 2 | using ColossalFramework.UI; 3 | using ModsCommon; 4 | using ModsCommon.UI; 5 | using ModsCommon.Utilities; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using UnityEngine; 9 | using static ModsCommon.UI.ComponentStyle; 10 | 11 | namespace BuildingSpawnPoints.UI 12 | { 13 | public class BuildingSpawnPointsPanel : ToolPanel 14 | { 15 | private PanelHeader Header { get; set; } 16 | private CustomUIScrollablePanel ContentPanel { get; set; } 17 | private CustomUIButton AddButton { get; set; } 18 | private WarningPanel Warning { get; set; } 19 | 20 | public BuildingData Data { get; private set; } 21 | 22 | private Dictionary PointPanels { get; } = new Dictionary(); 23 | private PointPanel HoverPointPanel { get; set; } 24 | public BuildingSpawnPoint HoverPoint => HoverPointPanel?.Point; 25 | 26 | public override void Awake() 27 | { 28 | base.Awake(); 29 | 30 | name = nameof(BuildingSpawnPointsPanel); 31 | Atlas = CommonTextures.Atlas; 32 | BackgroundSprite = CommonTextures.PanelBig; 33 | BgColors = DarkPrimaryColor10; 34 | 35 | 36 | Header = AddUIComponent(); 37 | Header.name = nameof(Header); 38 | Header.Target = this; 39 | Header.BackgroundSprite = "ButtonWhite"; 40 | Header.BgColors = new Color32(36, 40, 40, 255); 41 | Header.Init(HeaderHeight); 42 | 43 | 44 | Warning = AddUIComponent(); 45 | Warning.Init(); 46 | SetItemMargin(Warning, new RectOffset(10, 10, 10, 10)); 47 | Warning.eventVisibilityChanged += WarningVisibilityChanged; 48 | Warning.eventSizeChanged += WarningSizeChanged; 49 | 50 | 51 | ContentPanel = AddUIComponent(); 52 | ContentPanel.name = nameof(ContentPanel); 53 | ContentPanel.ScrollOrientation = UIOrientation.Vertical; 54 | ContentPanel.Padding = new RectOffset(10, 10, 10, 10); 55 | ContentPanel.Atlas = TextureHelper.InGameAtlas; 56 | 57 | ContentPanel.AutoChildrenVertically = AutoLayoutChildren.None; 58 | ContentPanel.AutoChildrenHorizontally = AutoLayoutChildren.Fill; 59 | ContentPanel.AutoLayoutSpace = 10; 60 | ContentPanel.AutoLayout = AutoLayout.Vertical; 61 | 62 | ContentPanel.ScrollbarSize = 12f; 63 | ContentPanel.Scrollbar.DefaultStyle(); 64 | 65 | 66 | AddButton = AddUIComponent(); 67 | AddButton.name = nameof(AddButton); 68 | AddButton.text = BuildingSpawnPoints.Localize.Panel_AddPoint; 69 | AddButton.tooltip = SpawnPointsTool.AddPointShortcut; 70 | AddButton.SetDefaultStyle(); 71 | AddButton.height = 30; 72 | AddButton.TextHorizontalAlignment = UIHorizontalAlignment.Center; 73 | AddButton.TextPadding.top = 5; 74 | AddButton.eventClick += (_, _) => AddPoint(); 75 | SetItemMargin(AddButton, new RectOffset(10, 10, 10, 10)); 76 | 77 | 78 | var sizeChanger = AddUIComponent(); 79 | Ignore(sizeChanger, true); 80 | 81 | 82 | minimumSize = GetSize(400f, 300f); 83 | 84 | AutoChildrenHorizontally = AutoLayoutChildren.Fill; 85 | AutoLayout = AutoLayout.Vertical; 86 | } 87 | 88 | public override void Start() 89 | { 90 | base.Start(); 91 | SetDefaulSize(); 92 | } 93 | 94 | protected override void OnSizeChanged() 95 | { 96 | base.OnSizeChanged(); 97 | Header.width = width; 98 | SetContentSize(); 99 | MakePixelPerfect(); 100 | } 101 | private void WarningVisibilityChanged(UIComponent component, bool value) => SetContentSize(); 102 | private void WarningSizeChanged(UIComponent component, Vector2 value) => SetContentSize(); 103 | private void SetContentSize() => ContentPanel.height = height - Header.height - (Warning.isVisibleSelf ? 10f + Warning.height + 10f : 0f) - 10f - AddButton.height - 10f; 104 | private void SetDefaulSize() 105 | { 106 | SingletonMod.Logger.Debug($"Set default panel size"); 107 | size = GetSize(400f, 600f); 108 | } 109 | private Vector2 GetSize(float width, float height) => new Vector2(width, Header.height + height); 110 | 111 | public void SetData(BuildingData data) 112 | { 113 | if ((Data = data) != null) 114 | SetPanel(); 115 | else 116 | ResetPanel(); 117 | } 118 | private void SetPanel() 119 | { 120 | RefreshWarning(); 121 | ResetPanel(); 122 | 123 | ContentPanel.PauseLayout(() => 124 | { 125 | RefreshHeader(); 126 | 127 | foreach (var point in Data.Points) 128 | AddPointPanel(point); 129 | }); 130 | } 131 | private void ResetPanel() 132 | { 133 | ContentPanel.PauseLayout(() => 134 | { 135 | HoverPointPanel = null; 136 | 137 | foreach (var component in ContentPanel.components.ToArray()) 138 | { 139 | if (component != ContentPanel.Scrollbar) 140 | ComponentPool.Free(component); 141 | } 142 | 143 | PointPanels.Clear(); 144 | }); 145 | } 146 | private void AddPointPanel(BuildingSpawnPoint point) 147 | { 148 | var pointPanel = ComponentPool.Get(ContentPanel); 149 | pointPanel.Init(Data, point); 150 | pointPanel.PanelStyle = UIStyle.Default.PropertyPanel; 151 | pointPanel.OnEnter += PointMouseEnter; 152 | pointPanel.OnLeave += PointMouseLeave; 153 | pointPanel.OnChanged += RefreshWarning; 154 | 155 | PointPanels[point] = pointPanel; 156 | } 157 | 158 | public override void RefreshPanel() => SetPanel(); 159 | public void RefreshHeader() 160 | { 161 | Header.Text = string.Format(BuildingSpawnPoints.Localize.Panel_Title, Data.Id); 162 | Header.Refresh(); 163 | } 164 | private void RefreshWarning() => Warning.Init(Data.LostVehicles); 165 | 166 | public void AddPoint() 167 | { 168 | var newPoint = Data.AddPoint(); 169 | AddPointPanel(newPoint); 170 | 171 | ContentPanel.ScrollToEnd(); 172 | } 173 | 174 | public void DeletePoint(BuildingSpawnPoint point) 175 | { 176 | Data.DeletePoint(point); 177 | 178 | if (PointPanels.TryGetValue(point, out var pointPanel)) 179 | { 180 | if (HoverPointPanel == pointPanel) 181 | HoverPointPanel = null; 182 | 183 | ComponentPool.Free(pointPanel); 184 | PointPanels.Remove(point); 185 | } 186 | } 187 | public void DuplicatePoint(BuildingSpawnPoint point) 188 | { 189 | var copyPoint = Data.DuplicatePoint(point); 190 | AddPointPanel(copyPoint); 191 | 192 | ContentPanel.ScrollToEnd(); 193 | } 194 | public void SelectPoint(BuildingSpawnPoint point) 195 | { 196 | if (PointPanels.TryGetValue(point, out var pointPanel)) 197 | { 198 | pointPanel.Refresh(); 199 | ContentPanel.ScrollIntoView(pointPanel); 200 | } 201 | } 202 | 203 | private void PointMouseEnter(PointPanel rulePanel, UIMouseEventParameter eventParam) => HoverPointPanel = rulePanel; 204 | private void PointMouseLeave(PointPanel rulePanel, UIMouseEventParameter eventParam) 205 | { 206 | var uiView = rulePanel.GetUIView(); 207 | var mouse = uiView.ScreenPointToGUI((eventParam.position + eventParam.moveDelta) / uiView.inputScale); 208 | var pointRect = new Rect(ContentPanel.absolutePosition + rulePanel.relativePosition, rulePanel.size); 209 | var contentRect = new Rect(ContentPanel.absolutePosition, ContentPanel.size); 210 | 211 | if (eventParam.source == rulePanel || !pointRect.Contains(mouse) || !contentRect.Contains(mouse)) 212 | HoverPointPanel = null; 213 | } 214 | public void Render(RenderManager.CameraInfo cameraInfo) 215 | { 216 | if (HoverPointPanel is PointPanel pointPanel) 217 | pointPanel.Point.Render(cameraInfo, true, pointPanel.HoveredVehicleType); 218 | } 219 | public void RenderGeometry(RenderManager.CameraInfo cameraInfo) 220 | { 221 | if (HoverPointPanel is PointPanel pointPanel) 222 | pointPanel.Point.RenderGeometry(cameraInfo, true); 223 | } 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/UI/PanelHeader.cs: -------------------------------------------------------------------------------- 1 | using ModsCommon; 2 | using ModsCommon.UI; 3 | using BuildingSpawnPoints.Utilities; 4 | using static ModsCommon.UI.ComponentStyle; 5 | 6 | namespace BuildingSpawnPoints.UI 7 | { 8 | public class PanelHeader : HeaderMoveablePanel 9 | { 10 | private HeaderButtonInfo PasteButton { get; set; } 11 | 12 | protected override void FillContent() 13 | { 14 | Content.AddButton(new HeaderButtonInfo("Copy", HeaderButtonState.Main, SpawnPointsTextures.Atlas, SpawnPointsTextures.CopyHeaderButton, BuildingSpawnPoints.Localize.Panel_Copy, OnCopy)); 15 | 16 | PasteButton = new HeaderButtonInfo("Paste", HeaderButtonState.Main, SpawnPointsTextures.Atlas, SpawnPointsTextures.PasteHeaderButton, BuildingSpawnPoints.Localize.Panel_Paste, OnPaste); 17 | Content.AddButton(PasteButton); 18 | 19 | Content.AddButton(new HeaderButtonInfo("Apply to all", HeaderButtonState.Main, SpawnPointsTextures.Atlas, SpawnPointsTextures.ApplyAllHeaderButton, BuildingSpawnPoints.Localize.Panel_ApplyToAll, OnApplyToAll)); 20 | 21 | Content.AddButton(new HeaderButtonInfo("Reset", HeaderButtonState.Main, SpawnPointsTextures.Atlas, SpawnPointsTextures.ResetHeaderButton, BuildingSpawnPoints.Localize.Panel_ResetToDefault, OnResetToDefault)); 22 | } 23 | 24 | private void OnCopy() => SingletonTool.Instance.Copy(); 25 | private void OnPaste() => SingletonTool.Instance.Paste(); 26 | private void OnApplyToAll() => SingletonTool.Instance.ApplyToAll(); 27 | private void OnResetToDefault() => SingletonTool.Instance.ResetToDefault(); 28 | 29 | public override void Refresh() 30 | { 31 | PasteButton.Enable = !SingletonTool.Instance.IsBufferEmpty; 32 | base.Refresh(); 33 | } 34 | public void Init(float height) => base.Init(height); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/UI/Utilities/SpawnPointsTextures.cs: -------------------------------------------------------------------------------- 1 | using ColossalFramework.UI; 2 | using ModsCommon.Utilities; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using UnityEngine; 8 | 9 | namespace BuildingSpawnPoints.Utilities 10 | { 11 | public static class SpawnPointsTextures 12 | { 13 | public static UITextureAtlas Atlas; 14 | public static Texture2D Texture => Atlas.texture; 15 | 16 | public static string AddVehicleHeaderButton => nameof(AddVehicleHeaderButton); 17 | public static string AddVehicleGroupHeaderButton => nameof(AddVehicleGroupHeaderButton); 18 | public static string AddAllVehiclesHeaderButton => nameof(AddAllVehiclesHeaderButton); 19 | public static string CopyHeaderButton => nameof(CopyHeaderButton); 20 | public static string PasteHeaderButton => nameof(PasteHeaderButton); 21 | public static string AppendHeaderButton => nameof(AppendHeaderButton); 22 | public static string DuplicateHeaderButton => nameof(DuplicateHeaderButton); 23 | public static string ResetHeaderButton => nameof(ResetHeaderButton); 24 | public static string ApplyAllHeaderButton => nameof(ApplyAllHeaderButton); 25 | 26 | public static string UUIButtonNormal => nameof(UUIButtonNormal); 27 | public static string UUIButtonHovered => nameof(UUIButtonHovered); 28 | public static string UUIButtonPressed => nameof(UUIButtonPressed); 29 | 30 | public static string InfoNormal => nameof(InfoNormal); 31 | public static string InfoPressed => nameof(InfoPressed); 32 | 33 | static SpawnPointsTextures() 34 | { 35 | var spriteParams = new Dictionary(); 36 | 37 | //ActivationButton 38 | spriteParams[InfoNormal] = new RectOffset(); 39 | spriteParams[InfoPressed] = new RectOffset(); 40 | 41 | //UUIButton 42 | spriteParams[UUIButtonNormal] = new RectOffset(); 43 | spriteParams[UUIButtonHovered] = new RectOffset(); 44 | spriteParams[UUIButtonPressed] = new RectOffset(); 45 | 46 | //HeaderButtons 47 | spriteParams[AddVehicleHeaderButton] = new RectOffset(); 48 | spriteParams[AddVehicleGroupHeaderButton] = new RectOffset(); 49 | spriteParams[AddAllVehiclesHeaderButton] = new RectOffset(); 50 | spriteParams[CopyHeaderButton] = new RectOffset(); 51 | spriteParams[PasteHeaderButton] = new RectOffset(); 52 | spriteParams[AppendHeaderButton] = new RectOffset(); 53 | spriteParams[DuplicateHeaderButton] = new RectOffset(); 54 | spriteParams[ResetHeaderButton] = new RectOffset(); 55 | spriteParams[ApplyAllHeaderButton] = new RectOffset(); 56 | 57 | Atlas = TextureHelper.CreateAtlas(nameof(BuildingSpawnPoints), spriteParams); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/UI/Utilities/UIStyle.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using ModsCommon.UI; 3 | using static ModsCommon.UI.ComponentStyle; 4 | using static ModsCommon.Utilities.CommonTextures; 5 | 6 | namespace BuildingSpawnPoints.UI 7 | { 8 | public static class UIStyle 9 | { 10 | public static Color32 PropertyPanel => DarkPrimaryColor20; 11 | public static Color32 PropertyNormal => DarkPrimaryColor45; 12 | public static Color32 PropertyHovered => DarkPrimaryColor55; 13 | public static Color32 PropertyPressed => DarkPrimaryColor60; 14 | public static Color32 PropertyFocused => NormalBlue; 15 | 16 | public static Color32 PopupBackground => DarkPrimaryColor15; 17 | public static Color32 PopupEntitySelected => NormalBlue; 18 | public static Color32 PopupEntityHovered => DarkPrimaryColor50; 19 | public static Color32 PopupEntityPressed => DarkPrimaryColor60; 20 | 21 | public static ControlStyle Default { get; } = new ControlStyle() 22 | { 23 | TextField = new TextFieldStyle() 24 | { 25 | BgAtlas = Atlas, 26 | FgAtlas = Atlas, 27 | 28 | BgSprites = new SpriteSet(FieldSingle, FieldSingle, FieldSingle, FieldSingle, BorderSmall), 29 | BgColors = new ColorSet(PropertyNormal, PropertyHovered, PropertyHovered, PropertyNormal, PropertyNormal), 30 | 31 | FgSprites = new SpriteSet(default, default, default, BorderSmall, default), 32 | FgColors = new ColorSet(default, default, default, PropertyFocused, default), 33 | 34 | TextColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, Color.black), 35 | 36 | SelectionSprite = Empty, 37 | SelectionColor = PropertyFocused, 38 | }, 39 | Segmented = new SegmentedStyle() 40 | { 41 | Single = GetSegmentedStyle(FieldSingle, BorderSmall), 42 | Left = GetSegmentedStyle(FieldLeft, FieldBorderLeft), 43 | Middle = GetSegmentedStyle(FieldMiddle, FieldBorderMiddle), 44 | Right = GetSegmentedStyle(FieldRight, FieldBorderRight), 45 | }, 46 | LargeButton = new ButtonStyle() 47 | { 48 | BgAtlas = Atlas, 49 | FgAtlas = Atlas, 50 | 51 | BgSprites = new SpriteSet(PanelBig, PanelBig, PanelBig, PanelBig, BorderBig), 52 | BgColors = new ColorSet(PropertyNormal, PropertyHovered, PropertyPressed, PropertyNormal, PropertyNormal), 53 | SelBgColors = new ColorSet(), 54 | 55 | FgSprites = default, 56 | FgColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, Color.black), 57 | SelFgColors = default, 58 | 59 | TextColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, Color.black), 60 | SelTextColors = default, 61 | }, 62 | DropDown = new DropDownStyle() 63 | { 64 | BgAtlas = Atlas, 65 | FgAtlas = Atlas, 66 | 67 | AllBgSprites = new SpriteSet(FieldSingle, FieldSingle, FieldSingle, FieldSingle, BorderSmall), 68 | BgColors = new ColorSet(PropertyNormal, PropertyHovered, PropertyHovered, PropertyNormal, PropertyNormal), 69 | SelBgColors = PropertyFocused, 70 | 71 | FgSprites = new SpriteSet(VectorDown, VectorDown, VectorDown, VectorDown, default), 72 | FgColors = Color.white, 73 | 74 | AllTextColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, Color.black), 75 | 76 | 77 | PopupAtlas = Atlas, 78 | PopupSprite = FieldSingle, 79 | PopupColor = PopupBackground, 80 | PopupItemsPadding = new RectOffset(4, 4, 4, 4), 81 | 82 | 83 | EntityAtlas = Atlas, 84 | 85 | EntitySprites = new SpriteSet(default, FieldSingle, FieldSingle, default, default), 86 | EntitySelSprites = FieldSingle, 87 | 88 | EntityColors = new ColorSet(default, PopupEntityHovered, PopupEntityPressed, default, default), 89 | EntitySelColors = PopupEntitySelected, 90 | }, 91 | Toggle = new ToggleStyle() 92 | { 93 | BgAtlas = Atlas, 94 | MarkAtlas = Atlas, 95 | 96 | OnBgSprites = ToggleBackgroundSmall, 97 | OffBgSprites = new SpriteSet(ToggleBackgroundSmall, ToggleBackgroundSmall, ToggleBackgroundSmall, ToggleBackgroundSmall, ToggleBorderSmall), 98 | 99 | OnMarkSprites = ToggleCircle, 100 | OffMarkSprites = ToggleCircle, 101 | 102 | OnBgColors = new ColorSet(PropertyFocused, PropertyFocused, PropertyFocused, PropertyFocused, PropertyNormal), 103 | OffBgColors = new ColorSet(PropertyNormal, PropertyHovered, PropertyHovered, PropertyNormal, PropertyNormal), 104 | 105 | OnMarkColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, PropertyPanel), 106 | OffMarkColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, PropertyNormal), 107 | 108 | OnTextColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, PropertyPanel), 109 | OffTextColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, Color.black), 110 | }, 111 | Label = new LabelStyle() 112 | { 113 | NormalTextColor = Color.white, 114 | DisabledTextColor = Color.black, 115 | }, 116 | PropertyPanel = new PropertyPanelStyle() 117 | { 118 | BgAtlas = Atlas, 119 | BgSprites = PanelLarge, 120 | BgColors = PropertyPanel, 121 | MaskSprite = OpacitySliderMask, 122 | } 123 | }; 124 | private static ButtonStyle GetSegmentedStyle(string background, string border) 125 | { 126 | return new ButtonStyle() 127 | { 128 | BgAtlas = Atlas, 129 | FgAtlas = Atlas, 130 | 131 | BgSprites = new SpriteSet(background, background, background, background, border), 132 | BgColors = new ColorSet(PropertyNormal, PropertyHovered, PropertyHovered, PropertyNormal, PropertyNormal), 133 | SelBgSprites = background, 134 | SelBgColors = new ColorSet(PropertyFocused, HoveredBlue, PressedBlue, PropertyFocused, PropertyNormal), 135 | 136 | FgColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, PropertyNormal), 137 | SelFgColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, PropertyPanel), 138 | 139 | TextColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, Color.black), 140 | SelTextColors = new ColorSet(Color.white, Color.white, Color.white, Color.white, PropertyPanel), 141 | }; 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/UI/VehicleCategoryProperty.cs: -------------------------------------------------------------------------------- 1 | using ColossalFramework.UI; 2 | using ModsCommon.UI; 3 | using ModsCommon.Utilities; 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using UnityEngine; 10 | using static ModsCommon.UI.ComponentStyle; 11 | 12 | namespace BuildingSpawnPoints.UI 13 | { 14 | public class VehicleCategoryPropertyPanel : BaseEditorPanel, IReusable 15 | { 16 | public event Action OnRemove; 17 | public event Action OnHover; 18 | 19 | bool IReusable.InCache { get; set; } 20 | Transform IReusable.CachedTransform { get => m_CachedTransform; set => m_CachedTransform = value; } 21 | 22 | private Dictionary Items { get; } = new Dictionary(); 23 | public IEnumerable Values => Items.Values; 24 | 25 | public bool Deletable { get; set; } = true; 26 | 27 | public VehicleCategoryPropertyPanel() : base() 28 | { 29 | AutoLayout = AutoLayout.Disabled; 30 | Padding = new RectOffset(10, 10, 7, 7); 31 | AutoLayoutSpace = 5; 32 | } 33 | 34 | public void AddItems(VehicleCategory types) 35 | { 36 | foreach (var type in types.GetEnumValues().IsItem()) 37 | AddItem(type); 38 | 39 | FitItems(); 40 | } 41 | public void SetItems(VehicleCategory types) 42 | { 43 | ClearItems(); 44 | AddItems(types); 45 | } 46 | void IReusable.DeInit() 47 | { 48 | ClearItems(); 49 | OnRemove = null; 50 | OnHover = null; 51 | Deletable = true; 52 | } 53 | private void AddItem(VehicleCategory type) 54 | { 55 | if (!Items.ContainsKey(type)) 56 | { 57 | var item = ComponentPool.Get(this, type.ToString()); 58 | item.Init(type, Deletable); 59 | item.OnRemove += RemoveItem; 60 | item.OnEnter += EnterItem; 61 | item.OnLeave += LeaveItem; 62 | Items.Add(type, item); 63 | } 64 | } 65 | 66 | private void RemoveItem(VehicleItem item) 67 | { 68 | Items.Remove(item.Type); 69 | OnRemove?.Invoke(item.Type); 70 | ComponentPool.Free(item); 71 | 72 | FitItems(); 73 | } 74 | private void ClearItems() 75 | { 76 | foreach (var component in components.ToArray()) 77 | ComponentPool.Free(component); 78 | 79 | Items.Clear(); 80 | } 81 | 82 | private void FitItems() 83 | { 84 | var items = Items.Values.OrderBy(i => i.width).ToList(); 85 | var prev = default(VehicleItem); 86 | 87 | for (var i = items.Count - 1; i >= 0; i -= 1) 88 | { 89 | if (prev == null) 90 | { 91 | items[i].relativePosition = new Vector2(Padding.left, Padding.top); 92 | prev = items[i]; 93 | items.RemoveAt(i); 94 | } 95 | else 96 | { 97 | var j = i; 98 | while (j >= 0 && prev.relativePosition.x + prev.width + items[j].width + Padding.horizontal > width) 99 | j -= 1; 100 | 101 | if (j >= 0) 102 | { 103 | items[j].relativePosition = prev.relativePosition + new Vector3(prev.width + AutoLayoutSpace, 0f); 104 | prev = items[j]; 105 | items.RemoveAt(j); 106 | } 107 | else 108 | { 109 | items[i].relativePosition = new Vector2(Padding.left, prev.relativePosition.y + prev.height + AutoLayoutSpace); 110 | prev = items[i]; 111 | items.RemoveAt(i); 112 | } 113 | } 114 | } 115 | 116 | if (prev != null) 117 | height = prev.relativePosition.y + prev.height + Padding.vertical; 118 | else 119 | height = 0f; 120 | } 121 | 122 | protected override void OnSizeChanged() 123 | { 124 | base.OnSizeChanged(); 125 | FitItems(); 126 | } 127 | protected override void OnVisibilityChanged() 128 | { 129 | base.OnVisibilityChanged(); 130 | if (isVisibleSelf) 131 | FitItems(); 132 | } 133 | 134 | private void EnterItem(VehicleItem item) => OnHover?.Invoke(item.Type); 135 | private void LeaveItem(VehicleItem item) => OnHover?.Invoke(VehicleCategory.None); 136 | 137 | public override void SetStyle(ControlStyle style) { } 138 | } 139 | public class VehicleItem : CustomUIPanel, IReusable 140 | { 141 | public event Action OnRemove; 142 | public event Action OnEnter; 143 | public event Action OnLeave; 144 | 145 | bool IReusable.InCache { get; set; } 146 | Transform IReusable.CachedTransform { get => m_CachedTransform; set => m_CachedTransform = value; } 147 | 148 | private CustomUILabel Label { get; set; } 149 | private CustomUIButton Remove { get; set; } 150 | 151 | public VehicleCategory Type { get; private set; } 152 | 153 | private bool isCorrect; 154 | public bool IsCorrect 155 | { 156 | get => isCorrect; 157 | set 158 | { 159 | if (value != isCorrect) 160 | { 161 | isCorrect = value; 162 | SetColor(); 163 | } 164 | } 165 | } 166 | 167 | private bool isAllCorrect; 168 | public bool IsAllCorrect 169 | { 170 | get => isAllCorrect; 171 | set 172 | { 173 | if (value != isAllCorrect) 174 | { 175 | isAllCorrect = value; 176 | SetColor(); 177 | } 178 | } 179 | } 180 | 181 | public VehicleItem() 182 | { 183 | height = 20f; 184 | 185 | PauseLayout(() => 186 | { 187 | AutoLayout = AutoLayout.Horizontal; 188 | AutoChildrenHorizontally = AutoLayoutChildren.Fit; 189 | 190 | Atlas = CommonTextures.Atlas; 191 | BackgroundSprite = CommonTextures.PanelLarge; 192 | BgColors = UIStyle.PropertyNormal; 193 | 194 | Label = AddUIComponent(); 195 | Label.name = nameof(Label); 196 | Label.autoSize = true; 197 | Label.WordWrap = false; 198 | Label.textScale = 0.8f; 199 | Label.VerticalAlignment = UIVerticalAlignment.Middle; 200 | Label.Padding = new RectOffset(7, 4, 4, 0); 201 | 202 | Remove = AddUIComponent(); 203 | Remove.name = nameof(Remove); 204 | Remove.size = new Vector2(16f, 20f); 205 | Remove.text = "×"; 206 | Remove.textScale = 1.2f; 207 | Remove.TextPadding = new RectOffset(0, 4, 0, 0); 208 | Remove.eventClick += (_, _) => OnRemove?.Invoke(this); 209 | }); 210 | } 211 | public void Init(VehicleCategory type, bool deletable = true) 212 | { 213 | Type = type; 214 | Label.text = type.Description(); 215 | Remove.isVisible = deletable; 216 | SetColor(); 217 | } 218 | private void SetColor() 219 | { 220 | if (!IsCorrect) 221 | { 222 | BgColors = CommonColors.GetOverlayColor(CommonColors.Overlay.Red, 255); 223 | ForegroundSprite = string.Empty; 224 | } 225 | else if (!Settings.ColorTags) 226 | { 227 | BgColors = UIStyle.PropertyNormal; 228 | ForegroundSprite = string.Empty; 229 | } 230 | else if (!IsAllCorrect) 231 | { 232 | BgColors = DarkPrimaryColor20; 233 | ForegroundSprite = CommonTextures.BorderLarge; 234 | FgColors = GetColor(); 235 | } 236 | else 237 | { 238 | BgColors = GetColor(); 239 | ForegroundSprite = string.Empty; 240 | } 241 | 242 | if (Color.white.GetContrast(NormalBgColor) >= 4.5) 243 | { 244 | Label.textColor = Color.white; 245 | Remove.TextColors = new ColorSet(Color.white, DarkPrimaryColor90, DarkPrimaryColor80, Color.white, Color.white); 246 | } 247 | else 248 | { 249 | Label.textColor = DarkPrimaryColor15; 250 | Remove.TextColors = new ColorSet(DarkPrimaryColor15, DarkPrimaryColor25, DarkPrimaryColor30, DarkPrimaryColor15, DarkPrimaryColor15); 251 | } 252 | 253 | Color32 GetColor() => Type.GetFunction() switch 254 | { 255 | VehicleFunction.Planes => CommonColors.GetOverlayColor(CommonColors.Overlay.SkyBlue, 255), 256 | VehicleFunction.Copters => CommonColors.GetOverlayColor(CommonColors.Overlay.Purple, 255), 257 | VehicleFunction.Trains => CommonColors.GetOverlayColor(CommonColors.Overlay.Lime, 255), 258 | VehicleFunction.Ships => CommonColors.GetOverlayColor(CommonColors.Overlay.Blue, 255), 259 | VehicleFunction.Trucks or VehicleFunction.Cargo => CommonColors.GetOverlayColor(CommonColors.Overlay.Yellow, 255), 260 | VehicleFunction.Public => CommonColors.GetOverlayColor(CommonColors.Overlay.Green, 255), 261 | VehicleFunction.Emergency => CommonColors.GetOverlayColor(CommonColors.Overlay.Orange, 255), 262 | VehicleFunction.Service => CommonColors.GetOverlayColor(CommonColors.Overlay.Turquoise, 255), 263 | _ => UIStyle.PropertyNormal, 264 | }; 265 | } 266 | 267 | void IReusable.DeInit() 268 | { 269 | Label.text = string.Empty; 270 | OnRemove = null; 271 | OnEnter = null; 272 | OnLeave = null; 273 | isCorrect = true; 274 | isAllCorrect = true; 275 | } 276 | 277 | protected override void OnMouseEnter(UIMouseEventParameter p) 278 | { 279 | base.OnMouseEnter(p); 280 | OnEnter?.Invoke(this); 281 | } 282 | protected override void OnMouseLeave(UIMouseEventParameter p) 283 | { 284 | base.OnMouseLeave(p); 285 | OnLeave?.Invoke(this); 286 | } 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/UI/WarningPanel.cs: -------------------------------------------------------------------------------- 1 | using ModsCommon.UI; 2 | using ModsCommon.Utilities; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using UnityEngine; 8 | 9 | namespace BuildingSpawnPoints.UI 10 | { 11 | public class WarningPanel : PropertyGroupPanel 12 | { 13 | private CustomUILabel Label { get; set; } 14 | private VehicleCategoryPropertyPanel Vehicle { get; set; } 15 | private CustomUILabel LabelContinue { get; set; } 16 | 17 | public WarningPanel() : base() 18 | { 19 | atlas = CommonTextures.Atlas; 20 | backgroundSprite = CommonTextures.PanelLarge; 21 | bgColors = ComponentStyle.WarningColor; 22 | 23 | PauseLayout(() => 24 | { 25 | Label = AddLabel(); 26 | Label.Padding = new RectOffset(10, 10, 10, 0); 27 | 28 | Vehicle = ComponentPool.Get(this); 29 | Vehicle.Deletable = false; 30 | 31 | LabelContinue = AddLabel(); 32 | LabelContinue.Padding = new RectOffset(10, 10, 0, 5); 33 | }); 34 | } 35 | 36 | public void Init(VehicleCategory type) 37 | { 38 | PauseLayout(() => 39 | { 40 | Label.text = BuildingSpawnPoints.Localize.Panel_NoPointWarning; 41 | LabelContinue.text = BuildingSpawnPoints.Localize.Panel_NoPointWarningContinue; 42 | 43 | isVisible = type != VehicleCategory.None; 44 | Vehicle.SetItems(type); 45 | }); 46 | 47 | base.Init(); 48 | } 49 | public override void DeInit() => Vehicle.SetItems(VehicleCategory.None); 50 | 51 | private CustomUILabel AddLabel() 52 | { 53 | var label = AddUIComponent(); 54 | label.textScale = 0.8f; 55 | label.AutoSize = AutoSize.Height; 56 | label.WordWrap = true; 57 | return label; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Utilites/MoveItIntegration.cs: -------------------------------------------------------------------------------- 1 | using ModsCommon; 2 | using MoveItIntegration; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Xml; 9 | using System.Xml.Linq; 10 | 11 | namespace BuildingSpawnPoints.Utilites 12 | { 13 | public class MoveItIntegrationFactory : IMoveItIntegrationFactory 14 | { 15 | public MoveItIntegrationBase GetInstance() => new MoveItIntegration(); 16 | } 17 | 18 | public class MoveItIntegration : MoveItIntegrationBase 19 | { 20 | public override string ID => $"CS.macsergey.{nameof(BuildingSpawnPoints)}"; 21 | 22 | public override Version DataVersion => new Version(1, 0); 23 | 24 | public override object Copy(InstanceID sourceInstanceID) 25 | { 26 | if (SingletonManager.Instance[sourceInstanceID.Building] is BuildingData data) 27 | return data.ToXml(); 28 | else 29 | return null; 30 | } 31 | public override void Paste(InstanceID targetInstanceID, object record, Dictionary sourceMap) 32 | { 33 | if (record is not XElement config || targetInstanceID.Building == 0) 34 | return; 35 | 36 | if (SingletonManager.Instance[targetInstanceID.Building, Options.Create] is BuildingData data) 37 | data.FromXml(SingletonMod.Version, config); 38 | } 39 | 40 | public override string Encode64(object record) => record == null ? null : EncodeUtil.BinaryEncode64(record?.ToString()); 41 | public override object Decode64(string record, Version dataVersion) 42 | { 43 | if (record == null || record.Length == 0) 44 | return null; 45 | 46 | using StringReader input = new StringReader((string)EncodeUtil.BinaryDecode64(record)); 47 | XmlReaderSettings xmlReaderSettings = new XmlReaderSettings 48 | { 49 | IgnoreWhitespace = true, 50 | ProhibitDtd = false, 51 | XmlResolver = null 52 | }; 53 | using XmlReader reader = XmlReader.Create(input, xmlReaderSettings); 54 | return XElement.Load(reader, LoadOptions.None); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /BuildingSpawnPoints/Utilites/ObjectMap.cs: -------------------------------------------------------------------------------- 1 | using ModsCommon.Utilities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace BuildingSpawnPoints.Utilites 8 | { 9 | public class ObjectsMap : BaseObjectsMap 10 | { 11 | public ObjectsMap(bool isSimple = false) : base(isSimple) { } 12 | 13 | public bool TryGetBuilding(ushort buildingIdKey, out ushort buildingIdValue) 14 | { 15 | if (Map.TryGetValue(new ObjectId() { Building = buildingIdKey }, out ObjectId value)) 16 | { 17 | buildingIdValue = value.Building; 18 | return true; 19 | } 20 | else 21 | { 22 | buildingIdValue = default; 23 | return false; 24 | } 25 | } 26 | 27 | public void AddBuilding(ushort source, ushort target) => this[new ObjectId() { Building = source }] = new ObjectId() { Building = target }; 28 | } 29 | public class ObjectId : ModsCommon.Utilities.ObjectId 30 | { 31 | public static long BuildingType = 1L << 32; 32 | 33 | public ushort Building 34 | { 35 | get => (Id & BuildingType) == 0 ? (ushort)0 : (ushort)(Id & DataMask); 36 | set => Id = BuildingType | value; 37 | } 38 | 39 | public override string ToString() 40 | { 41 | if (Type == BuildingType) 42 | return $"{nameof(Building)}: {Building}"; 43 | else 44 | return base.ToString(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Workshop/Banner.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/Workshop/Banner.psd -------------------------------------------------------------------------------- /Workshop/Icon.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/Workshop/Icon.ai -------------------------------------------------------------------------------- /Workshop/Preview.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/Workshop/Preview.psd -------------------------------------------------------------------------------- /Workshop/PreviewImageBeta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/Workshop/PreviewImageBeta.png -------------------------------------------------------------------------------- /Workshop/PreviewImageStable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSergey/BuildingSpawnPoints/313201f013a77cc66b9beea761a41debb13771c3/Workshop/PreviewImageStable.png -------------------------------------------------------------------------------- /Workshop/Workshop BETA description.txt: -------------------------------------------------------------------------------- 1 | [code][h1]WARNING![/h1] 2 | [list][h2]This is BETA version. It is for testing new features and may contain errors. If you subscribed to it by mistake, then switch to the [url=https://steamcommunity.com/sharedfiles/filedetails/?id=2511258910]STABLE VERSION[/url][/h2][/list] 3 | [/code] -------------------------------------------------------------------------------- /Workshop/Workshop description.txt: -------------------------------------------------------------------------------- 1 | [img]https://i.imgur.com/0O9w9Ta.png[/img] 2 | [HR][/HR] 3 | [img]https://i.imgur.com/j5BJcCL.png[/img] 4 | [code][h1]Overview[/h1] 5 | [list][h2]This mod allows you change and add building points where spawn vehicles[/h2][/list] 6 | [/code] 7 | 8 | [HR][/HR] 9 | [h1]What’s Included[/h1] 10 | [list] 11 | [*] Change position of existing spawn points 12 | [*] Add additional spawn points 13 | [*] Spawn vehicles from any side of once building to many different roads 14 | [*] Set point type: spawn, unspawn, spawn&unspawn 15 | [*] Set vehicles types for each point 16 | [*] Apply settings for all building of type 17 | [*] MoveIt integration - points data copied when you copy building 18 | [*] Translation into languages: Chinese, Danish, Dutch, Finnish, French, German, Hungarian, Italian, Japanese, Korean, Polish, Portuguese, Russian, Spanish, Turkish 19 | [/list] 20 | 21 | [HR][/HR] 22 | [h1]How activate[/h1] 23 | [olist] 24 | [*] Press Ctrl+P (You can change binding shortcut in mod settings) 25 | [*] Select building and click button on header of info panel [img]https://i.imgur.com/GPFONM6.png[/img] 26 | [/olist] 27 | 28 | [HR][/HR] 29 | [h1]Support[/h1] 30 | If you have any problems with mod or errors occur, you should describe your problem as much detailed as possible, comments like “mod does not work” will be ignored. 31 | Also, you should provide the game log, comments about errors without game log will be ignored too. Read [url=https://steamcommunity.com/sharedfiles/filedetails/?id=463645931]here[/url] how to share log. 32 | 33 | Although, the best way to solve problems is joining to my discord and write to [b]#Support[/b] channel, unfortunately, steam comments is very useless for conversation. 34 | 35 | [url=https://discord.gg/NnwhuBKMqj][h3]Join discord server[/h3] 36 | [img]https://i.imgur.com/bnDNN2x.png[/img][/url] 37 | 38 | [HR][/HR] 39 | [h1]Source code[/h1] 40 | [url=https://github.com/MacSergey/BuildingSpawnPoints][h3]Get from GitHub[/h3][img]https://i.imgur.com/DczUXYq.png[/img][/url] 41 | 42 | [HR][/HR] 43 | [h1]Translations[/h1] 44 | If you want to help improve existing translations or you want to translate into your own language (ask to add it to the translation project). 45 | [url=https://crowdin.com/project/macsergey-other-mods][h3]Translate on Crowdin[/h3][img]https://i.imgur.com/uG2NKvG.png[/img][/url] 46 | 47 | [HR][/HR] 48 | [h1]Thank you for your help in development and translation:[/h1] 49 | [list] 50 | [*] [url=https://steamcommunity.com/profiles/76561198855893485]Almi[/url] (Spanish translation) 51 | [*] Annyeong1 (Korean translation) 52 | [*] AQZ (Hungarian translation) 53 | [*] [url=https://steamcommunity.com/id/chameleonlifede/]Chamëleon[/url] (German translation) 54 | [*] [url=https://steamcommunity.com/id/citadino/]Citadino[/url] (Spanish translation) 55 | [*] [url=https://steamcommunity.com/id/claude_speed_]Claude_Speed[/url] (Chinese translation) 56 | [*] [url=https://steamcommunity.com/id/Dogg_One]Dogg1[/url] (Finnish translation) 57 | [*] [url=https://steamcommunity.com/profiles/76561198141193559]krzychu124[/url] 58 | [*] [url=https://steamcommunity.com/id/mrlojnat/]MrLojnat[/url] (French translation) 59 | [*] [url=https://steamcommunity.com/profiles/76561198153118551/]PELLQ[/url] (Turkish translation) 60 | [*] raistlin46 (Italian translation) 61 | [*] [url=https://steamcommunity.com/profiles/76561198087011973/]ristrettoridder[/url] (Dutch translation) 62 | [*] [url=https://steamcommunity.com/id/shg166yh/]shg166[/url] (Japanese translation) 63 | [*] Svis (French translation) 64 | [*] Strate (Danish translation) 65 | [*] [url=https://steamcommunity.com/id/Syvies/]Syvies[/url] (French translation) 66 | [*] [url=https://steamcommunity.com/id/teengamer37/]Teengamer 37[/url] (Romanian translation) 67 | [*] [url=https://steamcommunity.com/id/mrwoozie/]Woozie[/url] (Polish translation) 68 | [/list] 69 | 70 | [HR][/HR][i]For full transparency: I am an employee at Colossal Order, however this is my personal account and as such all opinions, content and contributions to the community reflect my own views and interests, and are not created nor maintained as part of my job. Like all user generated content, this is not officially supported content and should be used at your own risk.[/i] -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /BuildingSpawnPoints/Properties/Localize.resx 3 | translation: /BuildingSpawnPoints/Properties/Localize.%locale%.resx 4 | update_option: update_as_unapproved 5 | --------------------------------------------------------------------------------