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); }
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))); }
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; }
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); }
public SpawnOccupant(GameInformation.Player player) { Color = player.Color; ClientIndex = player.ClientIndex; PlayerName = player.Name; Team = player.Team; Country = player.FactionId; SpawnPoint = player.SpawnPoint; }
public SpawnOccupant(Session.Client client) { Color = client.Color; ClientIndex = client.Index; PlayerName = client.Name; Team = client.Team; Country = client.Country; SpawnPoint = client.SpawnPoint; }
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); }
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); }
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); } }
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); }
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); }
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())); }
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); }
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); }
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(); } }
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); }
public void UpdatePalettesForPlayer(string internalName, HSLColor color, bool replaceExisting) { foreach (var pal in World.WorldActor.TraitsImplementing<ILoadsPlayerPalettes>()) pal.LoadPlayerPalettes(this, internalName, color, replaceExisting); }
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; }
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"); }
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); }
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); }