예제 #1
0
        public ColorPickerLogic(Widget widget, HSLColor initialColor, Action<HSLColor> onChange, WorldRenderer worldRenderer)
        {
            var ticker = widget.GetOrNull<LogicTickerWidget>("ANIMATE_PREVIEW");
            if (ticker != null)
            {
                var preview = widget.Get<SpriteSequenceWidget>("PREVIEW");
                var anim = preview.GetAnimation();
                anim.PlayRepeating(anim.CurrentSequence.Name);
                ticker.OnTick = anim.Tick;
            }

            var hueSlider = widget.Get<SliderWidget>("HUE");
            var mixer = widget.Get<ColorMixerWidget>("MIXER");
            var randomButton = widget.GetOrNull<ButtonWidget>("RANDOM_BUTTON");

            hueSlider.OnChange += _ => mixer.Set(hueSlider.Value);
            mixer.OnChange += () => onChange(mixer.Color);

            if (randomButton != null)
                randomButton.OnClick = () =>
                {
                    // Avoid colors with low sat or lum
                    var hue = (byte)Game.CosmeticRandom.Next(255);
                    var sat = (byte)Game.CosmeticRandom.Next(70, 255);
                    var lum = (byte)Game.CosmeticRandom.Next(70, 255);

                    mixer.Set(new HSLColor(hue, sat, lum));
                    hueSlider.Value = hue / 255f;
                };

            // Set the initial state
            mixer.Set(initialColor);
            hueSlider.Value = initialColor.H / 255f;
            onChange(mixer.Color);
        }
예제 #2
0
        public void FloatingText(string text, WPos position, int duration = 30, HSLColor? color = null)
        {
            if (string.IsNullOrEmpty(text) || !world.Map.Contains(world.Map.CellContaining(position)))
                return;

            Color c = color.HasValue ? HSLColor.RGBFromHSL(color.Value.H / 255f, color.Value.S / 255f, color.Value.L / 255f) : Color.White;
            world.AddFrameEndTask(w => w.Add(new FloatingText(position, c, text, duration)));
        }
예제 #3
0
        public void SetMissionText(string text, HSLColor? color = null)
        {
            var luaLabel = Ui.Root.Get("INGAME_ROOT").Get<LabelWidget>("MISSION_TEXT");
            luaLabel.GetText = () => text;

            Color c = color.HasValue ? HSLColor.RGBFromHSL(color.Value.H / 255f, color.Value.S / 255f, color.Value.L / 255f) : Color.White;
            luaLabel.GetColor = () => c;
        }
예제 #4
0
        public void DisplayMessage(string text, string prefix = "Mission", HSLColor? color = null)
        {
            if (string.IsNullOrEmpty(text))
                return;

            Color c = color.HasValue ? HSLColor.RGBFromHSL(color.Value.H / 255f, color.Value.S / 255f, color.Value.L / 255f) : Color.White;
            Game.AddChatLine(c, prefix, text);
        }
예제 #5
0
		public SpawnOccupant(GameInformation.Player player)
		{
			Color = player.Color;
			ClientIndex = player.ClientIndex;
			PlayerName = player.Name;
			Team = player.Team;
			Country = player.FactionId;
			SpawnPoint = player.SpawnPoint;
		}
예제 #6
0
		public SpawnOccupant(Session.Client client)
		{
			Color = client.Color;
			ClientIndex = client.Index;
			PlayerName = client.Name;
			Team = client.Team;
			Country = client.Country;
			SpawnPoint = client.SpawnPoint;
		}
예제 #7
0
		public override void Tick()
		{
			if (cachedColor == Color)
				return;
			cachedColor = Color;

			var newPalette = new MutablePalette(preview);
			newPalette.ApplyRemap(new PlayerColorRemap(RemapIndices, Color, Ramp));
			worldRenderer.ReplacePalette(PaletteName, newPalette);
		}
예제 #8
0
        public void LoadPlayerPalettes(WorldRenderer wr, string playerName, HSLColor color, bool replaceExisting)
        {
            var basePalette = wr.Palette(info.BasePalette).Palette;
            ImmutablePalette pal;
            int[] remap;

            if (info.PlayerIndex.TryGetValue(playerName, out remap))
                pal = new ImmutablePalette(basePalette, new IndexedColorRemap(basePalette, info.RemapIndex, remap));
            else
                pal = new ImmutablePalette(basePalette);

            wr.AddPalette(info.BaseName + playerName, pal, info.AllowModifiers, replaceExisting);
        }
예제 #9
0
파일: Player.cs 프로젝트: ushardul/OpenRA
        public Player(World world, Session.Client client, Session.Slot slot, PlayerReference pr)
        {
            World = world;
            InternalName = pr.Name;
            PlayerReference = pr;
            string botType = null;

            // Real player or host-created bot
            if (client != null)
            {
                ClientIndex = client.Index;
                Color = client.Color;
                PlayerName = client.Name;
                botType = client.Bot;
                Country = ChooseCountry(world, client.Race, !pr.LockRace);
                DisplayCountry = ChooseDisplayCountry(world, client.Race);
            }
            else
            {
                // Map player
                ClientIndex = 0; // Owned by the host (TODO: fix this)
                Color = pr.Color;
                PlayerName = pr.Name;
                NonCombatant = pr.NonCombatant;
                Playable = pr.Playable;
                Spectating = pr.Spectating;
                botType = pr.Bot;
                Country = ChooseCountry(world, pr.Race, false);
                DisplayCountry = ChooseDisplayCountry(world, pr.Race);
            }

            PlayerActor = world.CreateActor("Player", new TypeDictionary { new OwnerInit(this) });
            Shroud = PlayerActor.Trait<Shroud>();

            // Enable the bot logic on the host
            IsBot = botType != null;
            if (IsBot && Game.IsHost)
            {
                var logic = PlayerActor.TraitsImplementing<IBot>()
                            .FirstOrDefault(b => b.Info.Name == botType);
                if (logic == null)
                    Log.Write("debug", "Invalid bot type: {0}", botType);
                else
                    logic.Activate(this);
            }
        }
예제 #10
0
        public ColorPickerLogic(Widget widget, ModData modData, World world, HSLColor initialColor, Action<HSLColor> onChange, WorldRenderer worldRenderer)
        {
            string actorType;
            if (!ChromeMetrics.TryGet("ColorPickerActorType", out actorType))
                actorType = "mcv";

            var preview = widget.GetOrNull<ActorPreviewWidget>("PREVIEW");
            var actor = world.Map.Rules.Actors[actorType];

            var td = new TypeDictionary();
            td.Add(new HideBibPreviewInit());
            td.Add(new OwnerInit(world.WorldActor.Owner));
            td.Add(new FactionInit(world.WorldActor.Owner.PlayerReference.Faction));

            if (preview != null)
                preview.SetPreview(actor, td);

            var hueSlider = widget.Get<SliderWidget>("HUE");
            var mixer = widget.Get<ColorMixerWidget>("MIXER");
            var randomButton = widget.GetOrNull<ButtonWidget>("RANDOM_BUTTON");

            hueSlider.OnChange += _ => mixer.Set(hueSlider.Value);
            mixer.OnChange += () => onChange(mixer.Color);

            if (randomButton != null)
                randomButton.OnClick = () =>
                {
                    // Avoid colors with low sat or lum
                    var hue = (byte)Game.CosmeticRandom.Next(255);
                    var sat = (byte)Game.CosmeticRandom.Next(70, 255);
                    var lum = (byte)Game.CosmeticRandom.Next(70, 255);

                    mixer.Set(new HSLColor(hue, sat, lum));
                    hueSlider.Value = hue / 255f;
                };

            // Set the initial state
            var validator = modData.Manifest.Get<ColorValidator>();
            mixer.SetPaletteRange(validator.HsvSaturationRange[0], validator.HsvSaturationRange[1], validator.HsvValueRange[0], validator.HsvValueRange[1]);
            mixer.Set(initialColor);

            hueSlider.Value = initialColor.H / 255f;
            onChange(mixer.Color);
        }
예제 #11
0
		public PlayerColorRemap(int[] ramp, HSLColor c, float rampFraction)
		{
			// Increase luminosity if required to represent the full ramp
			var rampRange = (byte)((1 - rampFraction) * c.L);
			var c1 = new HSLColor(c.H, c.S, (byte)Math.Max(rampRange, c.L)).RGB;
			var c2 = new HSLColor(c.H, c.S, (byte)Math.Max(0, c.L - rampRange)).RGB;
			var baseIndex = ramp[0];
			var remapRamp = ramp.Select(r => r - ramp[0]).ToArray();

			// reversed remapping
			if (ramp[0] > ramp[15])
			{
				baseIndex = ramp[15];
				for (var i = 15; i > 0; i--)
					remapRamp = ramp.Select(r => r - ramp[15]).ToArray();
			}

			remapColors = remapRamp.Select((x, i) => Pair.New(baseIndex + i, Exts.ColorLerp(x / 16f, c1, c2)))
				.ToDictionary(u => u.First, u => u.Second);
		}
예제 #12
0
        internal static void UpgradeMapFormat(ModData modData, IReadWritePackage package)
        {
            if (package == null)
                return;

            var yamlStream = package.GetStream("map.yaml");
            if (yamlStream == null)
                return;

            var yaml = new MiniYaml(null, MiniYaml.FromStream(yamlStream, package.Name));
            var nd = yaml.ToDictionary();
            var mapFormat = FieldLoader.GetValue<int>("MapFormat", nd["MapFormat"].Value);
            if (mapFormat < 6)
                throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(mapFormat, package.Name));

            // Format 6 -> 7 combined the Selectable and UseAsShellmap flags into the Class enum
            if (mapFormat < 7)
            {
                MiniYaml useAsShellmap;
                if (nd.TryGetValue("UseAsShellmap", out useAsShellmap) && bool.Parse(useAsShellmap.Value))
                    yaml.Nodes.Add(new MiniYamlNode("Visibility", new MiniYaml("Shellmap")));
                else if (nd["Type"].Value == "Mission" || nd["Type"].Value == "Campaign")
                    yaml.Nodes.Add(new MiniYamlNode("Visibility", new MiniYaml("MissionSelector")));
            }

            // Format 7 -> 8 replaced normalized HSL triples with rgb(a) hex colors
            if (mapFormat < 8)
            {
                var players = yaml.Nodes.FirstOrDefault(n => n.Key == "Players");
                if (players != null)
                {
                    bool noteHexColors = false;
                    bool noteColorRamp = false;
                    foreach (var player in players.Value.Nodes)
                    {
                        var colorRampNode = player.Value.Nodes.FirstOrDefault(n => n.Key == "ColorRamp");
                        if (colorRampNode != null)
                        {
                            Color dummy;
                            var parts = colorRampNode.Value.Value.Split(',');
                            if (parts.Length == 3 || parts.Length == 4)
                            {
                                // Try to convert old normalized HSL value to a rgb hex color
                                try
                                {
                                    HSLColor color = new HSLColor(
                                        (byte)Exts.ParseIntegerInvariant(parts[0].Trim()).Clamp(0, 255),
                                        (byte)Exts.ParseIntegerInvariant(parts[1].Trim()).Clamp(0, 255),
                                        (byte)Exts.ParseIntegerInvariant(parts[2].Trim()).Clamp(0, 255));
                                    colorRampNode.Value.Value = FieldSaver.FormatValue(color);
                                    noteHexColors = true;
                                }
                                catch (Exception)
                                {
                                    throw new InvalidDataException("Invalid ColorRamp value.\n File: " + package.Name);
                                }
                            }
                            else if (parts.Length != 1 || !HSLColor.TryParseRGB(parts[0], out dummy))
                                throw new InvalidDataException("Invalid ColorRamp value.\n File: " + package.Name);

                            colorRampNode.Key = "Color";
                            noteColorRamp = true;
                        }
                    }

                    if (noteHexColors)
                        Console.WriteLine("ColorRamp is now called Color and uses rgb(a) hex value - rrggbb[aa].");
                    else if (noteColorRamp)
                        Console.WriteLine("ColorRamp is now called Color.");
                }
            }

            // Format 8 -> 9 moved map options and videos from the map file itself to traits
            if (mapFormat < 9)
            {
                var rules = yaml.Nodes.FirstOrDefault(n => n.Key == "Rules");
                var worldNode = rules.Value.Nodes.FirstOrDefault(n => n.Key == "World");
                if (worldNode == null)
                    worldNode = new MiniYamlNode("World", new MiniYaml("", new List<MiniYamlNode>()));

                var playerNode = rules.Value.Nodes.FirstOrDefault(n => n.Key == "Player");
                if (playerNode == null)
                    playerNode = new MiniYamlNode("Player", new MiniYaml("", new List<MiniYamlNode>()));

                var visibilityNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Visibility");
                if (visibilityNode != null)
                {
                    var visibility = FieldLoader.GetValue<MapVisibility>("Visibility", visibilityNode.Value.Value);
                    if (visibility.HasFlag(MapVisibility.MissionSelector))
                    {
                        var missionData = new MiniYamlNode("MissionData", new MiniYaml("", new List<MiniYamlNode>()));
                        worldNode.Value.Nodes.Add(missionData);

                        var description = yaml.Nodes.FirstOrDefault(n => n.Key == "Description");
                        if (description != null)
                            missionData.Value.Nodes.Add(new MiniYamlNode("Briefing", description.Value.Value));

                        var videos = yaml.Nodes.FirstOrDefault(n => n.Key == "Videos");
                        if (videos != null && videos.Value.Nodes.Any())
                        {
                            var backgroundVideo = videos.Value.Nodes.FirstOrDefault(n => n.Key == "BackgroundInfo");
                            if (backgroundVideo != null)
                                missionData.Value.Nodes.Add(new MiniYamlNode("BackgroundVideo", backgroundVideo.Value.Value));

                            var briefingVideo = videos.Value.Nodes.FirstOrDefault(n => n.Key == "Briefing");
                            if (briefingVideo != null)
                                missionData.Value.Nodes.Add(new MiniYamlNode("BriefingVideo", briefingVideo.Value.Value));

                            var startVideo = videos.Value.Nodes.FirstOrDefault(n => n.Key == "GameStart");
                            if (startVideo != null)
                                missionData.Value.Nodes.Add(new MiniYamlNode("StartVideo", startVideo.Value.Value));

                            var winVideo = videos.Value.Nodes.FirstOrDefault(n => n.Key == "GameWon");
                            if (winVideo != null)
                                missionData.Value.Nodes.Add(new MiniYamlNode("WinVideo", winVideo.Value.Value));

                            var lossVideo = videos.Value.Nodes.FirstOrDefault(n => n.Key == "GameLost");
                            if (lossVideo != null)
                                missionData.Value.Nodes.Add(new MiniYamlNode("LossVideo", lossVideo.Value.Value));
                        }
                    }
                }

                var mapOptions = yaml.Nodes.FirstOrDefault(n => n.Key == "Options");
                if (mapOptions != null)
                {
                    var cheats = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Cheats");
                    if (cheats != null)
                    {
                        worldNode.Value.Nodes.Add(new MiniYamlNode("DeveloperMode", new MiniYaml("", new List<MiniYamlNode>()
                        {
                            new MiniYamlNode("Locked", "True"),
                            new MiniYamlNode("Enabled", cheats.Value.Value)
                        })));
                    }

                    var crates = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Crates");
                    if (crates != null && !worldNode.Value.Nodes.Any(n => n.Key == "-CrateSpawner"))
                    {
                        if (!FieldLoader.GetValue<bool>("crates", crates.Value.Value))
                            worldNode.Value.Nodes.Add(new MiniYamlNode("-CrateSpawner", new MiniYaml("")));
                    }

                    var creeps = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Creeps");
                    if (creeps != null)
                    {
                        worldNode.Value.Nodes.Add(new MiniYamlNode("MapCreeps", new MiniYaml("", new List<MiniYamlNode>()
                        {
                            new MiniYamlNode("Locked", "True"),
                            new MiniYamlNode("Enabled", creeps.Value.Value)
                        })));
                    }

                    var fog = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Fog");
                    var shroud = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Shroud");
                    if (fog != null || shroud != null)
                    {
                        var shroudNode = new MiniYamlNode("Shroud", new MiniYaml("", new List<MiniYamlNode>()));
                        playerNode.Value.Nodes.Add(shroudNode);

                        if (fog != null)
                        {
                            shroudNode.Value.Nodes.Add(new MiniYamlNode("FogLocked", "True"));
                            shroudNode.Value.Nodes.Add(new MiniYamlNode("FogEnabled", fog.Value.Value));
                        }

                        if (shroud != null)
                        {
                            var enabled = FieldLoader.GetValue<bool>("shroud", shroud.Value.Value);
                            shroudNode.Value.Nodes.Add(new MiniYamlNode("ExploredMapLocked", "True"));
                            shroudNode.Value.Nodes.Add(new MiniYamlNode("ExploredMapEnabled", FieldSaver.FormatValue(!enabled)));
                        }
                    }

                    var allyBuildRadius = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "AllyBuildRadius");
                    if (allyBuildRadius != null)
                    {
                        worldNode.Value.Nodes.Add(new MiniYamlNode("MapBuildRadius", new MiniYaml("", new List<MiniYamlNode>()
                        {
                            new MiniYamlNode("AllyBuildRadiusLocked", "True"),
                            new MiniYamlNode("AllyBuildRadiusEnabled", allyBuildRadius.Value.Value)
                        })));
                    }

                    var startingCash = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "StartingCash");
                    if (startingCash != null)
                    {
                        playerNode.Value.Nodes.Add(new MiniYamlNode("PlayerResources", new MiniYaml("", new List<MiniYamlNode>()
                        {
                            new MiniYamlNode("DefaultCashLocked", "True"),
                            new MiniYamlNode("DefaultCash", startingCash.Value.Value)
                        })));
                    }

                    var startingUnits = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "ConfigurableStartingUnits");
                    if (startingUnits != null && !worldNode.Value.Nodes.Any(n => n.Key == "-SpawnMPUnits"))
                    {
                        worldNode.Value.Nodes.Add(new MiniYamlNode("SpawnMPUnits", new MiniYaml("", new List<MiniYamlNode>()
                        {
                            new MiniYamlNode("Locked", "True"),
                        })));
                    }

                    var techLevel = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "TechLevel");
                    var difficulties = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "Difficulties");
                    var shortGame = mapOptions.Value.Nodes.FirstOrDefault(n => n.Key == "ShortGame");
                    if (techLevel != null || difficulties != null || shortGame != null)
                    {
                        var optionsNode = new MiniYamlNode("MapOptions", new MiniYaml("", new List<MiniYamlNode>()));
                        worldNode.Value.Nodes.Add(optionsNode);

                        if (techLevel != null)
                        {
                            optionsNode.Value.Nodes.Add(new MiniYamlNode("TechLevelLocked", "True"));
                            optionsNode.Value.Nodes.Add(new MiniYamlNode("TechLevel", techLevel.Value.Value));
                        }

                        if (difficulties != null)
                            optionsNode.Value.Nodes.Add(new MiniYamlNode("Difficulties", difficulties.Value.Value));

                        if (shortGame != null)
                        {
                            optionsNode.Value.Nodes.Add(new MiniYamlNode("ShortGameLocked", "True"));
                            optionsNode.Value.Nodes.Add(new MiniYamlNode("ShortGameEnabled", shortGame.Value.Value));
                        }
                    }
                }

                if (worldNode.Value.Nodes.Any() && !rules.Value.Nodes.Contains(worldNode))
                    rules.Value.Nodes.Add(worldNode);

                if (playerNode.Value.Nodes.Any() && !rules.Value.Nodes.Contains(playerNode))
                    rules.Value.Nodes.Add(playerNode);
            }

            // Format 9 -> 10 moved smudges to SmudgeLayer, and uses map.png for all maps
            if (mapFormat < 10)
            {
                ExtractSmudges(yaml);
                if (package.Contains("map.png"))
                    yaml.Nodes.Add(new MiniYamlNode("LockPreview", new MiniYaml("True")));
            }

            // Format 10 -> 11 replaced the single map type field with a list of categories
            if (mapFormat < 11)
            {
                var type = yaml.Nodes.First(n => n.Key == "Type");
                yaml.Nodes.Add(new MiniYamlNode("Categories", type.Value));
                yaml.Nodes.Remove(type);
            }

            if (mapFormat < Map.SupportedMapFormat)
            {
                yaml.Nodes.First(n => n.Key == "MapFormat").Value = new MiniYaml(Map.SupportedMapFormat.ToString());
                Console.WriteLine("Converted {0} to MapFormat {1}.", package.Name, Map.SupportedMapFormat);
            }

            package.Update("map.yaml", Encoding.UTF8.GetBytes(yaml.Nodes.WriteToString()));
        }
예제 #13
0
        static HSLColor SanitizePlayerColor(S server, HSLColor askedColor, int playerIndex, Connection connectionToEcho = null)
        {
            var validator = server.ModData.Manifest.Get<ColorValidator>();
            var askColor = askedColor;

            Action<string> onError = message =>
            {
                if (connectionToEcho != null)
                    server.SendOrderTo(connectionToEcho, "Message", message);
            };

            var tileset = server.Map.Rules.TileSet;
            var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color).ToList();
            var playerColors = server.LobbyInfo.Clients.Where(c => c.Index != playerIndex).Select(c => c.Color.RGB)
                .Concat(server.Map.Players.Players.Values.Select(p => p.Color.RGB)).ToList();

            return validator.MakeValid(askColor.RGB, server.Random, terrainColors, playerColors, onError);
        }
예제 #14
0
		public static HSLColor ValidatePlayerColorAndGetAlternative(S server, HSLColor askedColor, int playerIndex, Connection connectionToEcho = null)
		{
			var askColor = askedColor;

			Color invalidColor;
			if (!ValidatePlayerNewColor(server, askColor.RGB, playerIndex, out invalidColor, connectionToEcho))
			{
				var altColor = GetColorAlternative(askColor.RGB, invalidColor);
				if (altColor == null || !ValidatePlayerNewColor(server, altColor.Value, playerIndex))
				{
					// Pick a random color
					do
					{
						var hue = (byte)server.Random.Next(255);
						var sat = (byte)server.Random.Next(255);
						var lum = (byte)server.Random.Next(129, 255);
						askColor = new HSLColor(hue, sat, lum);
					} while (!ValidatePlayerNewColor(server, askColor.RGB, playerIndex));
				}
				else
					askColor = HSLColor.FromRGB(altColor.Value.R, altColor.Value.G, altColor.Value.B);
			}

			return askColor;
		}
 public void LoadPlayerPalettes(WorldRenderer wr, string playerName, HSLColor color, bool replaceExisting)
 {
     var remap = new AlphaPaletteRemap(info.Alpha, info.Premultiply);
     var pal = new ImmutablePalette(wr.Palette(info.BasePalette + playerName).Palette, remap);
     wr.AddPalette(info.BaseName + playerName, pal, info.AllowModifiers, replaceExisting);
 }
예제 #16
0
		public void Set(HSLColor color)
		{
			float h, s, v;
			color.ToHSV(out h, out s, out v);

			if (H != h || S != s || V != v)
			{
				if (H != h)
				{
					H = h;
					GenerateBitmap();
				}

				S = s.Clamp(SRange[0], SRange[1]);
				V = v.Clamp(VRange[0], VRange[1]);
				OnChange();
			}
		}
예제 #17
0
 public void LoadPlayerPalettes(WorldRenderer wr, string playerName, HSLColor color, bool replaceExisting)
 {
     var argb = (uint)Color.FromArgb(128, color.RGB).ToArgb();
     var pal = new ImmutablePalette(Enumerable.Range(0, Palette.Size).Select(i => i == 0 ? 0 : argb));
     wr.AddPalette(info.BaseName + playerName, pal, false, replaceExisting);
 }
예제 #18
0
		public void UpdatePalettesForPlayer(string internalName, HSLColor color, bool replaceExisting)
		{
			foreach (var pal in World.WorldActor.TraitsImplementing<ILoadsPlayerPalettes>())
				pal.LoadPlayerPalettes(this, internalName, color, replaceExisting);
		}
예제 #19
0
        public HSLColor MakeValid(Color askedColor, MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors, Action<string> onError)
        {
            Color forbiddenColor;
            if (IsValid(askedColor, out forbiddenColor, terrainColors, playerColors, onError))
                return new HSLColor(askedColor);

            // Vector between the 2 colors
            var vector = new double[]
            {
                askedColor.R - forbiddenColor.R,
                askedColor.G - forbiddenColor.G,
                askedColor.B - forbiddenColor.B
            };

            // Reduce vector by it's biggest value (more calculations, but more accuracy too)
            var vectorMax = vector.Max(vv => Math.Abs(vv));
            if (vectorMax == 0)
                vectorMax = 1;	// Avoid division by 0

            vector[0] /= vectorMax;
            vector[1] /= vectorMax;
            vector[2] /= vectorMax;

            // Color weights
            var rmean = (double)(askedColor.R + forbiddenColor.R) / 2;
            var weightVector = new[]
            {
                2.0 + rmean / 256,
                4.0,
                2.0 + (255 - rmean) / 256,
            };

            var attempt = 1;
            var allForbidden = terrainColors.Concat(playerColors);
            HSLColor color;
            do
            {
                // If we reached the limit (The ii >= 255 prevents too much calculations)
                if (attempt >= 255)
                {
                    color = RandomValidColor(random, terrainColors, playerColors);
                    break;
                }

                // Apply vector to forbidden color
                var r = (forbiddenColor.R + (int)(vector[0] * weightVector[0] * attempt)).Clamp(0, 255);
                var g = (forbiddenColor.G + (int)(vector[1] * weightVector[1] * attempt)).Clamp(0, 255);
                var b = (forbiddenColor.B + (int)(vector[2] * weightVector[2] * attempt)).Clamp(0, 255);

                // Get the alternative color attempt
                color = new HSLColor(Color.FromArgb(r, g, b));

                attempt++;
            } while (!IsValid(color.RGB, allForbidden, out forbiddenColor));

            return color;
        }
예제 #20
0
파일: Player.cs 프로젝트: CH4Code/OpenRA
        public Player(World world, Session.Client client, PlayerReference pr)
        {
            string botType;

            World = world;
            InternalName = pr.Name;
            PlayerReference = pr;

            // Real player or host-created bot
            if (client != null)
            {
                ClientIndex = client.Index;
                Color = client.Color;
                PlayerName = client.Name;
                botType = client.Bot;
                Faction = ChooseFaction(world, client.Faction, !pr.LockFaction);
                DisplayFaction = ChooseDisplayFaction(world, client.Faction);
            }
            else
            {
                // Map player
                ClientIndex = 0; // Owned by the host (TODO: fix this)
                Color = pr.Color;
                PlayerName = pr.Name;
                NonCombatant = pr.NonCombatant;
                Playable = pr.Playable;
                Spectating = pr.Spectating;
                botType = pr.Bot;
                Faction = ChooseFaction(world, pr.Faction, false);
                DisplayFaction = ChooseDisplayFaction(world, pr.Faction);
            }

            PlayerActor = world.CreateActor("Player", new TypeDictionary { new OwnerInit(this) });
            Shroud = PlayerActor.Trait<Shroud>();

            fogVisibilities = PlayerActor.TraitsImplementing<IFogVisibilityModifier>().ToArray();

            // Enable the bot logic on the host
            IsBot = botType != null;
            if (IsBot && Game.IsHost)
            {
                var logic = PlayerActor.TraitsImplementing<IBot>().FirstOrDefault(b => b.Info.Name == botType);
                if (logic == null)
                    Log.Write("debug", "Invalid bot type: {0}", botType);
                else
                    logic.Activate(this);
            }

            stanceColors.Self = ChromeMetrics.Get<Color>("PlayerStanceColorSelf");
            stanceColors.Allies = ChromeMetrics.Get<Color>("PlayerStanceColorAllies");
            stanceColors.Enemies = ChromeMetrics.Get<Color>("PlayerStanceColorEnemies");
            stanceColors.Neutrals = ChromeMetrics.Get<Color>("PlayerStanceColorNeutrals");
        }
예제 #21
0
 public void LoadPlayerPalettes(WorldRenderer wr, string playerName, HSLColor color, bool replaceExisting)
 {
     var remap = new PlayerColorRemap(info.RemapIndex, color, info.Ramp);
     var pal = new ImmutablePalette(wr.Palette(info.BasePalette).Palette, remap);
     wr.AddPalette(info.BaseName + playerName, pal, info.AllowModifiers, replaceExisting);
 }
예제 #22
0
		public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd)
		{
			if (server == null || conn == null || client == null || !ValidateCommand(server, conn, client, cmd))
				return false;

			var dict = new Dictionary<string, Func<string, bool>>
			{
				{ "state",
					s =>
					{
						var state = Session.ClientState.Invalid;
						if (!Enum<Session.ClientState>.TryParse(s, false, out state))
						{
							server.SendOrderTo(conn, "Message", "Malformed state command");
							return true;
						}

						client.State = state;

						Log.Write("server", "Player @{0} is {1}",
							conn.Socket.RemoteEndPoint, client.State);

						server.SyncLobbyClients();

						CheckAutoStart(server);

						return true;
					}
				},
				{ "startgame",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can start the game.");
							return true;
						}

						if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required &&
							server.LobbyInfo.ClientInSlot(sl.Key) == null))
						{
							server.SendOrderTo(conn, "Message", "Unable to start the game until required slots are full.");
							return true;
						}

						server.StartGame();
						return true;
					}
				},
				{ "slot",
					s =>
					{
						if (!server.LobbyInfo.Slots.ContainsKey(s))
						{
							Log.Write("server", "Invalid slot: {0}", s);
							return false;
						}

						var slot = server.LobbyInfo.Slots[s];

						if (slot.Closed || server.LobbyInfo.ClientInSlot(s) != null)
							return false;

						client.Slot = s;
						S.SyncClientToPlayerReference(client, server.MapPlayers.Players[s]);

						var validatedColor = ColorValidator.ValidatePlayerColorAndGetAlternative(server, client.Color, client.Index, conn);
						client.PreferredColor = client.Color = validatedColor;

						server.SyncLobbyClients();
						CheckAutoStart(server);

						return true;
					}
				},
				{ "allow_spectators",
					s =>
					{
						if (bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowSpectators))
						{
							server.SyncLobbyGlobalSettings();
							return true;
						}
						else
						{
							server.SendOrderTo(conn, "Message", "Malformed allow_spectate command");
							return true;
						}
					}
				},
				{ "spectate",
					s =>
					{
						if (server.LobbyInfo.GlobalSettings.AllowSpectators || client.IsAdmin)
						{
							client.Slot = null;
							client.SpawnPoint = 0;
							client.Color = HSLColor.FromRGB(255, 255, 255);
							server.SyncLobbyClients();
							return true;
						}
						else
							return false;
					}
				},
				{ "slot_close",
					s =>
					{
						if (!ValidateSlotCommand(server, conn, client, s, true))
							return false;

						// kick any player that's in the slot
						var occupant = server.LobbyInfo.ClientInSlot(s);
						if (occupant != null)
						{
							if (occupant.Bot != null)
							{
								server.LobbyInfo.Clients.Remove(occupant);
								server.SyncLobbyClients();
								var ping = server.LobbyInfo.PingFromClient(occupant);
								if (ping != null)
								{
									server.LobbyInfo.ClientPings.Remove(ping);
									server.SyncClientPing();
								}
							}
							else
							{
								var occupantConn = server.Conns.FirstOrDefault(c => c.PlayerIndex == occupant.Index);
								if (occupantConn != null)
								{
									server.SendOrderTo(occupantConn, "ServerError", "Your slot was closed by the host.");
									server.DropClient(occupantConn);
								}
							}
						}

						server.LobbyInfo.Slots[s].Closed = true;
						server.SyncLobbySlots();
						return true;
					}
				},
				{ "slot_open",
					s =>
					{
						if (!ValidateSlotCommand(server, conn, client, s, true))
							return false;

						var slot = server.LobbyInfo.Slots[s];
						slot.Closed = false;
						server.SyncLobbySlots();

						// Slot may have a bot in it
						var occupant = server.LobbyInfo.ClientInSlot(s);
						if (occupant != null && occupant.Bot != null)
						{
							server.LobbyInfo.Clients.Remove(occupant);
							var ping = server.LobbyInfo.PingFromClient(occupant);
							if (ping != null)
							{
								server.LobbyInfo.ClientPings.Remove(ping);
								server.SyncClientPing();
							}
						}

						server.SyncLobbyClients();
						return true;
					}
				},
				{ "slot_bot",
					s =>
					{
						var parts = s.Split(' ');

						if (parts.Length < 3)
						{
							server.SendOrderTo(conn, "Message", "Malformed slot_bot command");
							return true;
						}

						if (!ValidateSlotCommand(server, conn, client, parts[0], true))
							return false;

						var slot = server.LobbyInfo.Slots[parts[0]];
						var bot = server.LobbyInfo.ClientInSlot(parts[0]);
						int controllerClientIndex;
						if (!Exts.TryParseIntegerInvariant(parts[1], out controllerClientIndex))
						{
							Log.Write("server", "Invalid bot controller client index: {0}", parts[1]);
							return false;
						}

						var botType = parts.Skip(2).JoinWith(" ");

						// Invalid slot
						if (bot != null && bot.Bot == null)
						{
							server.SendOrderTo(conn, "Message", "Can't add bots to a slot with another client.");
							return true;
						}

						slot.Closed = false;
						if (bot == null)
						{
							// Create a new bot
							bot = new Session.Client()
							{
								Index = server.ChooseFreePlayerIndex(),
								Name = botType,
								Bot = botType,
								Slot = parts[0],
								Faction = "Random",
								SpawnPoint = 0,
								Team = 0,
								State = Session.ClientState.NotReady,
								BotControllerClientIndex = controllerClientIndex
							};

							// Pick a random color for the bot
							HSLColor botColor;
							do
							{
								var hue = (byte)server.Random.Next(255);
								var sat = (byte)server.Random.Next(255);
								var lum = (byte)server.Random.Next(51, 255);
								botColor = new HSLColor(hue, sat, lum);
							} while (!ColorValidator.ValidatePlayerNewColor(server, botColor.RGB, bot.Index));

							bot.Color = bot.PreferredColor = botColor;

							server.LobbyInfo.Clients.Add(bot);
						}
						else
						{
							// Change the type of the existing bot
							bot.Name = botType;
							bot.Bot = botType;
						}

						S.SyncClientToPlayerReference(bot, server.MapPlayers.Players[parts[0]]);
						server.SyncLobbyClients();
						server.SyncLobbySlots();
						return true;
					}
				},
				{ "map",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can change the map.");
							return true;
						}

						if (server.ModData.MapCache[s].Status != MapStatus.Available)
						{
							server.SendOrderTo(conn, "Message", "Map was not found on server.");
							return true;
						}

						server.LobbyInfo.GlobalSettings.Map = s;

						var oldSlots = server.LobbyInfo.Slots.Keys.ToArray();
						LoadMap(server);
						SetDefaultDifficulty(server);

						// Reset client states
						foreach (var c in server.LobbyInfo.Clients)
							c.State = Session.ClientState.Invalid;

						// Reassign players into new slots based on their old slots:
						//  - Observers remain as observers
						//  - Players who now lack a slot are made observers
						//  - Bots who now lack a slot are dropped
						var slots = server.LobbyInfo.Slots.Keys.ToArray();
						var i = 0;
						foreach (var os in oldSlots)
						{
							var c = server.LobbyInfo.ClientInSlot(os);
							if (c == null)
								continue;

							c.SpawnPoint = 0;
							c.Slot = i < slots.Length ? slots[i++] : null;
							if (c.Slot != null)
							{
								// Remove Bot from slot if slot forbids bots
								if (c.Bot != null && !server.MapPlayers.Players[c.Slot].AllowBots)
									server.LobbyInfo.Clients.Remove(c);
								S.SyncClientToPlayerReference(c, server.MapPlayers.Players[c.Slot]);
							}
							else if (c.Bot != null)
								server.LobbyInfo.Clients.Remove(c);
						}

						foreach (var c in server.LobbyInfo.Clients)
						{
							// Validate if color is allowed and get an alternative it it isn't
							c.Color = c.PreferredColor = ColorValidator.ValidatePlayerColorAndGetAlternative(server, c.Color, c.Index, conn);
						}

						server.SyncLobbyInfo();

						server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title));

						if (server.Map.RuleDefinitions.Any())
							server.SendMessage("This map contains custom rules. Game experience may change.");

						return true;
					}
				},
				{ "fragilealliance",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (server.Map.Options.FragileAlliances.HasValue)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled alliance configuration.");
							return true;
						}

						bool.TryParse(s, out server.LobbyInfo.GlobalSettings.FragileAlliances);
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} {1} Diplomacy Changes."
							.F(client.Name, server.LobbyInfo.GlobalSettings.FragileAlliances ? "enabled" : "disabled"));

						return true;
					}
				},
				{ "allowcheats",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (server.Map.Options.Cheats.HasValue)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled cheat configuration.");
							return true;
						}

						bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowCheats);
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} {1} the Debug Menu."
							.F(client.Name, server.LobbyInfo.GlobalSettings.AllowCheats ? "enabled" : "disabled"));

						return true;
					}
				},
				{ "shroud",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (server.Map.Options.Shroud.HasValue)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled shroud configuration.");
							return true;
						}

						bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Shroud);
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} {1} Explored map."
							.F(client.Name, server.LobbyInfo.GlobalSettings.Shroud ? "disabled" : "enabled"));

						return true;
					}
				},
				{ "fog",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (server.Map.Options.Fog.HasValue)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled fog configuration.");
							return true;
						}

						bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Fog);
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} {1} Fog of War."
							.F(client.Name, server.LobbyInfo.GlobalSettings.Fog ? "enabled" : "disabled"));

						return true;
					}
				},
				{ "assignteams",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						int teamCount;
						if (!Exts.TryParseIntegerInvariant(s, out teamCount))
						{
							server.SendOrderTo(conn, "Message", "Number of teams could not be parsed: {0}".F(s));
							return true;
						}

						var maxTeams = (server.LobbyInfo.Clients.Count(c => c.Slot != null) + 1) / 2;
						teamCount = teamCount.Clamp(0, maxTeams);
						var clients = server.LobbyInfo.Slots
							.Select(slot => server.LobbyInfo.ClientInSlot(slot.Key))
							.Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam);

						var assigned = 0;
						var clientCount = clients.Count();
						foreach (var player in clients)
						{
							// Free for all
							if (teamCount == 0)
								player.Team = 0;

							// Humans vs Bots
							else if (teamCount == 1)
								player.Team = player.Bot == null ? 1 : 2;
							else
								player.Team = assigned++ * teamCount / clientCount + 1;
						}

						server.SyncLobbyClients();
						return true;
					}
				},
				{ "crates",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (server.Map.Options.Crates.HasValue)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled crate configuration.");
							return true;
						}

						bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Crates);
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} {1} Crates."
							.F(client.Name, server.LobbyInfo.GlobalSettings.Crates ? "enabled" : "disabled"));

						return true;
					}
				},
				{ "creeps",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (server.Map.Options.Creeps.HasValue)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled Creeps spawning configuration.");
							return true;
						}

						bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Creeps);
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} {1} Creeps spawning."
							.F(client.Name, server.LobbyInfo.GlobalSettings.Creeps ? "enabled" : "disabled"));

						return true;
					}
				},
				{ "allybuildradius",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (server.Map.Options.AllyBuildRadius.HasValue)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled ally build radius configuration.");
							return true;
						}

						bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllyBuildRadius);
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} {1} Build off Allies' ConYards."
							.F(client.Name, server.LobbyInfo.GlobalSettings.AllyBuildRadius ? "enabled" : "disabled"));

						return true;
					}
				},
				{ "difficulty",
					s =>
					{
						if (!server.Map.Options.Difficulties.Any())
							return true;

						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (s != null && !server.Map.Options.Difficulties.Contains(s))
						{
							server.SendOrderTo(conn, "Message", "Unsupported difficulty selected: {0}".F(s));
							server.SendOrderTo(conn, "Message", "Supported difficulties: {0}".F(server.Map.Options.Difficulties.JoinWith(",")));
							return true;
						}

						server.LobbyInfo.GlobalSettings.Difficulty = s;
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} changed difficulty to {1}.".F(client.Name, s));

						return true;
					}
				},
				{ "startingunits",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (!server.Map.Options.ConfigurableStartingUnits)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled start unit configuration.");
							return true;
						}

						var startUnitsInfo = server.Map.Rules.Actors["world"].TraitInfos<MPStartUnitsInfo>();
						var selectedClass = startUnitsInfo.Where(u => u.Class == s).Select(u => u.ClassName).FirstOrDefault();
						var className = selectedClass != null ? selectedClass : s;

						server.LobbyInfo.GlobalSettings.StartingUnitsClass = s;
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} changed Starting Units to {1}.".F(client.Name, className));

						return true;
					}
				},
				{ "startingcash",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (server.Map.Options.StartingCash.HasValue)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled cash configuration.");
							return true;
						}

						server.LobbyInfo.GlobalSettings.StartingCash = Exts.ParseIntegerInvariant(s);
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} changed Starting Cash to ${1}.".F(client.Name, s));

						return true;
					}
				},
				{ "techlevel",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (server.Map.Options.TechLevel != null)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled Tech configuration.");
							return true;
						}

						server.LobbyInfo.GlobalSettings.TechLevel = s;
						server.SyncLobbyInfo();
						server.SendMessage("{0} changed Tech Level to {1}.".F(client.Name, s));

						return true;
					}
				},
				{ "gamespeed",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						var gameSpeeds = Game.ModData.Manifest.Get<GameSpeeds>();

						GameSpeed speed;
						if (!gameSpeeds.Speeds.TryGetValue(s, out speed))
						{
							server.SendOrderTo(conn, "Message", "Invalid game speed selected.");
							return true;
						}

						server.LobbyInfo.GlobalSettings.GameSpeedType = s;
						server.LobbyInfo.GlobalSettings.Timestep = speed.Timestep;
						server.LobbyInfo.GlobalSettings.OrderLatency =
							server.LobbyInfo.IsSinglePlayer ? 1 : speed.OrderLatency;

						server.SyncLobbyInfo();
						server.SendMessage("{0} changed Game Speed to {1}.".F(client.Name, speed.Name));

						return true;
					}
				},
				{ "kick",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can kick players.");
							return true;
						}

						var split = s.Split(' ');
						if (split.Length < 2)
						{
							server.SendOrderTo(conn, "Message", "Malformed kick command");
							return true;
						}

						int kickClientID;
						Exts.TryParseIntegerInvariant(split[0], out kickClientID);

						var kickConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == kickClientID);
						if (kickConn == null)
						{
							server.SendOrderTo(conn, "Message", "Noone in that slot.");
							return true;
						}

						var kickClient = server.GetClient(kickConn);

						Log.Write("server", "Kicking client {0}.", kickClientID);
						server.SendMessage("{0} kicked {1} from the server.".F(client.Name, kickClient.Name));
						server.SendOrderTo(kickConn, "ServerError", "You have been kicked from the server.");
						server.DropClient(kickConn);

						bool tempBan;
						bool.TryParse(split[1], out tempBan);

						if (tempBan)
						{
							Log.Write("server", "Temporarily banning client {0} ({1}).", kickClientID, kickClient.IpAddress);
							server.SendMessage("{0} temporarily banned {1} from the server.".F(client.Name, kickClient.Name));
							server.TempBans.Add(kickClient.IpAddress);
						}

						server.SyncLobbyClients();
						server.SyncLobbySlots();

						return true;
					}
				},
				{ "name",
					s =>
					{
						var sanitizedName = OpenRA.Settings.SanitizedPlayerName(s);
						if (sanitizedName == client.Name)
							return true;

						Log.Write("server", "Player@{0} is now known as {1}.", conn.Socket.RemoteEndPoint, sanitizedName);
						server.SendMessage("{0} is now known as {1}.".F(client.Name, sanitizedName));
						client.Name = sanitizedName;
						server.SyncLobbyClients();
						return true;
					}
				},
				{ "faction",
					s =>
					{
						var parts = s.Split(' ');
						var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

						// Only the host can change other client's info
						if (targetClient.Index != client.Index && !client.IsAdmin)
							return true;

						// Map has disabled faction changes
						if (server.LobbyInfo.Slots[targetClient.Slot].LockFaction)
							return true;

						targetClient.Faction = parts[1];
						server.SyncLobbyClients();
						return true;
					}
				},
				{ "team",
					s =>
					{
						var parts = s.Split(' ');
						var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

						// Only the host can change other client's info
						if (targetClient.Index != client.Index && !client.IsAdmin)
							return true;

						// Map has disabled team changes
						if (server.LobbyInfo.Slots[targetClient.Slot].LockTeam)
							return true;

						int team;
						if (!Exts.TryParseIntegerInvariant(parts[1], out team))
						{
							Log.Write("server", "Invalid team: {0}", s);
							return false;
						}

						targetClient.Team = team;
						server.SyncLobbyClients();
						return true;
					}
				},
				{ "spawn",
					s =>
					{
						var parts = s.Split(' ');
						var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

						// Only the host can change other client's info
						if (targetClient.Index != client.Index && !client.IsAdmin)
							return true;

						// Spectators don't need a spawnpoint
						if (targetClient.Slot == null)
							return true;

						// Map has disabled spawn changes
						if (server.LobbyInfo.Slots[targetClient.Slot].LockSpawn)
							return true;

						int spawnPoint;
						if (!Exts.TryParseIntegerInvariant(parts[1], out spawnPoint)
							|| spawnPoint < 0 || spawnPoint > server.Map.SpawnPoints.Value.Length)
						{
							Log.Write("server", "Invalid spawn point: {0}", parts[1]);
							return true;
						}

						if (server.LobbyInfo.Clients.Where(cc => cc != client).Any(cc => (cc.SpawnPoint == spawnPoint) && (cc.SpawnPoint != 0)))
						{
							server.SendOrderTo(conn, "Message", "You cannot occupy the same spawn point as another player.");
							return true;
						}

						targetClient.SpawnPoint = spawnPoint;
						server.SyncLobbyClients();
						return true;
					}
				},
				{ "color",
					s =>
					{
						var parts = s.Split(' ');
						var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

						// Only the host can change other client's info
						if (targetClient.Index != client.Index && !client.IsAdmin)
							return true;

						// Spectator or map has disabled color changes
						if (targetClient.Slot == null || server.LobbyInfo.Slots[targetClient.Slot].LockColor)
							return true;

						var newHslColor = FieldLoader.GetValue<HSLColor>("(value)", parts[1]);

						// Validate if color is allowed and get an alternative it it isn't
						var altHslColor = ColorValidator.ValidatePlayerColorAndGetAlternative(server, newHslColor, targetClient.Index, conn);

						targetClient.Color = altHslColor;

						// Only update player's preferred color if new color is valid
						if (newHslColor == altHslColor)
							targetClient.PreferredColor = altHslColor;

						server.SyncLobbyClients();
						return true;
					}
				},
				{ "shortgame",
					s =>
					{
						if (!client.IsAdmin)
						{
							server.SendOrderTo(conn, "Message", "Only the host can set that option.");
							return true;
						}

						if (server.Map.Options.ShortGame.HasValue)
						{
							server.SendOrderTo(conn, "Message", "Map has disabled short game configuration.");
							return true;
						}

						bool.TryParse(s, out server.LobbyInfo.GlobalSettings.ShortGame);
						server.SyncLobbyGlobalSettings();
						server.SendMessage("{0} {1} Short Game."
							.F(client.Name, server.LobbyInfo.GlobalSettings.ShortGame ? "enabled" : "disabled"));

						return true;
					}
				}
			};

			var cmdName = cmd.Split(' ').First();
			var cmdValue = cmd.Split(' ').Skip(1).JoinWith(" ");

			Func<string, bool> a;
			if (!dict.TryGetValue(cmdName, out a))
				return false;

			return a(cmdValue);
		}