diff --git a/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs b/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs index 4cdbb3036b..36184cf6cc 100644 --- a/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs +++ b/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs @@ -18,24 +18,65 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class MPStartLocationsInfo : ITraitInfo + [Desc("Allows the map to have working spawnpoints. Also controls the 'Separate Team Spawns' checkbox in the lobby options.")] + public class MPStartLocationsInfo : ITraitInfo, ILobbyOptions { public readonly WDist InitialExploreRange = WDist.FromCells(5); + [Translate] + [Desc("Descriptive label for the spawn positions checkbox in the lobby.")] + public readonly string SeparateTeamSpawnsCheckboxLabel = "Separate Team Spawns"; + + [Translate] + [Desc("Tooltip description for the spawn positions checkbox in the lobby.")] + public readonly string SeparateTeamSpawnsCheckboxDescription = "Players without assigned spawn points will start as far as possible from enemy players."; + + [Desc("Default value of the spawn positions checkbox in the lobby.")] + public readonly bool SeparateTeamSpawnsCheckboxEnabled = true; + + [Desc("Prevent the spawn positions state from being changed in the lobby.")] + public readonly bool SeparateTeamSpawnsCheckboxLocked = false; + + [Desc("Whether to display the spawn positions checkbox in the lobby.")] + public readonly bool SeparateTeamSpawnsCheckboxVisible = true; + + [Desc("Display order for the spawn positions checkbox in the lobby.")] + public readonly int SeparateTeamSpawnsCheckboxDisplayOrder = 0; + public virtual object Create(ActorInitializer init) { return new MPStartLocations(this); } + + IEnumerable ILobbyOptions.LobbyOptions(Ruleset rules) + { + yield return new LobbyBooleanOption( + "randomspawnpositions", + SeparateTeamSpawnsCheckboxLabel, + SeparateTeamSpawnsCheckboxDescription, + SeparateTeamSpawnsCheckboxVisible, + SeparateTeamSpawnsCheckboxDisplayOrder, + SeparateTeamSpawnsCheckboxEnabled, + SeparateTeamSpawnsCheckboxLocked); + } } - public class MPStartLocations : IWorldLoaded + public class MPStartLocations : IWorldLoaded, INotifyCreated { readonly MPStartLocationsInfo info; public readonly Dictionary Start = new Dictionary(); + bool separateTeamSpawns; + public MPStartLocations(MPStartLocationsInfo info) { this.info = info; } + void INotifyCreated.Created(Actor self) + { + separateTeamSpawns = self.World.LobbyInfo.GlobalSettings + .OptionOrDefault("separateteamspawns", info.SeparateTeamSpawnsCheckboxEnabled); + } + public void WorldLoaded(World world, WorldRenderer wr) { var spawns = world.Actors.Where(a => a.Info.Name == "mpspawn") @@ -84,12 +125,12 @@ namespace OpenRA.Mods.Common.Traits return world.Players.FirstOrDefault(p => p.PlayerReference.Name == pr); } - static CPos ChooseSpawnPoint(World world, List available, List taken) + CPos ChooseSpawnPoint(World world, List available, List taken) { if (available.Count == 0) throw new InvalidOperationException("No free spawnpoint."); - var n = taken.Count == 0 + var n = taken.Count == 0 || !separateTeamSpawns ? world.SharedRandom.Next(available.Count) : available // pick the most distant spawnpoint from everyone else .Select((k, i) => Pair.New(k, i)) diff --git a/mods/cnc/rules/player.yaml b/mods/cnc/rules/player.yaml index 20a95dba81..8a71fae8cd 100644 --- a/mods/cnc/rules/player.yaml +++ b/mods/cnc/rules/player.yaml @@ -17,7 +17,7 @@ Player: AllyRepair: PlayerResources: DeveloperMode: - CheckboxDisplayOrder: 7 + CheckboxDisplayOrder: 8 BaseAttackNotifier: Shroud: FogCheckboxDisplayOrder: 3 @@ -26,7 +26,7 @@ Player: Label: Redeployable MCVs Description: Allow undeploying Construction Yard. Enabled: True - DisplayOrder: 6 + DisplayOrder: 7 Prerequisites: global-factundeploy PlayerStatistics: FrozenActorLayer: diff --git a/mods/cnc/rules/world.yaml b/mods/cnc/rules/world.yaml index 6e327eb01a..ac83030d9a 100644 --- a/mods/cnc/rules/world.yaml +++ b/mods/cnc/rules/world.yaml @@ -196,6 +196,7 @@ World: TechLevelDropdownDisplayOrder: 2 GameSpeedDropdownDisplayOrder: 3 MPStartLocations: + SeparateTeamSpawnsCheckboxDisplayOrder: 6 CreateMPPlayers: MPStartUnits@mcvonly: Class: none diff --git a/mods/d2k/rules/player.yaml b/mods/d2k/rules/player.yaml index f14be6fc7b..749cde1409 100644 --- a/mods/d2k/rules/player.yaml +++ b/mods/d2k/rules/player.yaml @@ -69,7 +69,7 @@ Player: SelectableCash: 2500, 5000, 7000, 10000, 20000 InsufficientFundsNotification: InsufficientFunds DeveloperMode: - CheckboxDisplayOrder: 6 + CheckboxDisplayOrder: 7 BaseAttackNotifier: Shroud: FogCheckboxDisplayOrder: 3 diff --git a/mods/d2k/rules/world.yaml b/mods/d2k/rules/world.yaml index c457409a33..337fff567d 100644 --- a/mods/d2k/rules/world.yaml +++ b/mods/d2k/rules/world.yaml @@ -167,6 +167,7 @@ World: GameSpeedDropdownDisplayOrder: 3 CreateMPPlayers: MPStartLocations: + SeparateTeamSpawnsCheckboxDisplayOrder: 6 MPStartUnits@mcv: Class: none ClassName: MCV Only diff --git a/mods/ra/rules/player.yaml b/mods/ra/rules/player.yaml index 55e701b459..7d2cbf66ec 100644 --- a/mods/ra/rules/player.yaml +++ b/mods/ra/rules/player.yaml @@ -56,7 +56,7 @@ Player: PlayerResources: InsufficientFundsNotification: InsufficientFunds DeveloperMode: - CheckboxDisplayOrder: 8 + CheckboxDisplayOrder: 9 GpsWatcher: Shroud: FogCheckboxDisplayOrder: 3 @@ -65,7 +65,7 @@ Player: Label: Kill Bounties Description: Players receive cash bonuses when killing enemy units Enabled: False - DisplayOrder: 6 + DisplayOrder: 8 Prerequisites: global-bounty LobbyPrerequisiteCheckbox@GLOBALFACTUNDEPLOY: ID: factundeploy diff --git a/mods/ra/rules/world.yaml b/mods/ra/rules/world.yaml index 586fd28c02..97268325b9 100644 --- a/mods/ra/rules/world.yaml +++ b/mods/ra/rules/world.yaml @@ -252,6 +252,7 @@ World: InnerSupportRadius: 3 OuterSupportRadius: 5 MPStartLocations: + SeparateTeamSpawnsCheckboxDisplayOrder: 6 SpawnMPUnits: DropdownDisplayOrder: 1 PathFinder: diff --git a/mods/ts/rules/player.yaml b/mods/ts/rules/player.yaml index 845005d151..09445b70d4 100644 --- a/mods/ts/rules/player.yaml +++ b/mods/ts/rules/player.yaml @@ -61,7 +61,7 @@ Player: InsufficientFundsNotification: InsufficientFunds DeveloperMode: CheckboxEnabled: true - CheckboxDisplayOrder: 7 + CheckboxDisplayOrder: 8 Shroud: FogCheckboxDisplayOrder: 3 LobbyPrerequisiteCheckbox@GLOBALFACTUNDEPLOY: @@ -69,7 +69,7 @@ Player: Label: Redeployable MCVs Description: Allow undeploying Construction Yard. Enabled: True - DisplayOrder: 6 + DisplayOrder: 7 Prerequisites: global-factundeploy FrozenActorLayer: BaseAttackNotifier: diff --git a/mods/ts/rules/world.yaml b/mods/ts/rules/world.yaml index 3c3201e187..cde22806ce 100644 --- a/mods/ts/rules/world.yaml +++ b/mods/ts/rules/world.yaml @@ -346,6 +346,7 @@ World: InnerSupportRadius: 3 OuterSupportRadius: 5 MPStartLocations: + SeparateTeamSpawnsCheckboxDisplayOrder: 6 SpawnMPUnits: DropdownDisplayOrder: 1 CrateSpawner: