public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd) { if (!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.Map.Players[s]); 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); 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); server.LobbyInfo.ClientPings.Remove(ping); } 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], Country = "random", SpawnPoint = 0, Team = 0, State = Session.ClientState.NotReady, BotControllerClientIndex = controllerClientIndex }; // pick a random color for the bot var hue = (byte)server.Random.Next(255); var sat = (byte)server.Random.Next(255); var lum = (byte)server.Random.Next(51, 255); bot.Color = bot.PreferredColor = new HSLColor(hue, sat, lum); server.LobbyInfo.Clients.Add(bot); } else { // Change the type of the existing bot bot.Name = botType; bot.Bot = botType; } S.SyncClientToPlayerReference(bot, server.Map.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(); int 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.Map.Players[c.Slot].AllowBots) { server.LobbyInfo.Clients.Remove(c); } S.SyncClientToPlayerReference(c, server.Map.Players[c.Slot]); } else if (c.Bot != null) { server.LobbyInfo.Clients.Remove(c); } } server.SyncLobbyInfo(); 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(); 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(); 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(); 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(); 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 players = server.LobbyInfo.Slots .Select(slot => server.LobbyInfo.ClientInSlot(slot.Key)) .Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam); var assigned = 0; var playerCount = players.Count(); foreach (var player in players) { // 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 / playerCount + 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(); 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(); return(true); } }, { "difficulty", s => { 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(); 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); } server.LobbyInfo.GlobalSettings.StartingUnitsClass = s; server.SyncLobbyGlobalSettings(); 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(); 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(); 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 kickConnIP = server.GetClient(kickConn).IpAddress; Log.Write("server", "Kicking client {0} as requested", kickClientID); 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}) as requested", kickClientID, kickConnIP); server.TempBans.Add(kickConnIP); } server.SyncLobbyClients(); server.SyncLobbySlots(); return(true); } }, { "name", s => { Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s); client.Name = s; server.SyncLobbyClients(); return(true); } }, { "race", 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 race changes if (server.LobbyInfo.Slots[targetClient.Slot].LockRace) { return(true); } targetClient.Country = 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.GetSpawnPoints().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 can't be at 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 ci = parts[1].Split(',').Select(cc => Exts.ParseIntegerInvariant(cc)).ToArray(); targetClient.Color = targetClient.PreferredColor = new HSLColor((byte)ci[0], (byte)ci[1], (byte)ci[2]); server.SyncLobbyClients(); 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)); }
public override bool Produce(Actor self, ActorInfo producee, string productionType, TypeDictionary inits, int refundableValue) { if (IsTraitDisabled || IsTraitPaused) { return(false); } var info = (ProductionAirdropInfo)Info; var owner = self.Owner; var map = owner.World.Map; var aircraftInfo = self.World.Map.Rules.Actors[info.ActorType].TraitInfo <AircraftInfo>(); var mpStart = owner.World.WorldActor.TraitOrDefault <MPStartLocations>(); CPos startPos; CPos endPos; WAngle spawnFacing; if (info.BaselineSpawn && mpStart != null) { var spawn = mpStart.Start[owner]; var bounds = map.Bounds; var center = new MPos(bounds.Left + bounds.Width / 2, bounds.Top + bounds.Height / 2).ToCPos(map); var spawnVec = spawn - center; startPos = spawn + spawnVec * (Exts.ISqrt((bounds.Height * bounds.Height + bounds.Width * bounds.Width) / (4 * spawnVec.LengthSquared))); endPos = startPos; var spawnDirection = new WVec((self.Location - startPos).X, (self.Location - startPos).Y, 0); spawnFacing = spawnDirection.Yaw; } else { // Start a fixed distance away: the width of the map. // This makes the production timing independent of spawnpoint var loc = self.Location.ToMPos(map); startPos = new MPos(loc.U + map.Bounds.Width, loc.V).ToCPos(map); endPos = new MPos(map.Bounds.Left, loc.V).ToCPos(map); spawnFacing = info.Facing; } // Assume a single exit point for simplicity var exit = self.Info.TraitInfos <ExitInfo>().First(); foreach (var tower in self.TraitsImplementing <INotifyDelivery>()) { tower.IncomingDelivery(self); } owner.World.AddFrameEndTask(w => { if (!self.IsInWorld || self.IsDead) { owner.PlayerActor.Trait <PlayerResources>().GiveCash(refundableValue); return; } var actor = w.CreateActor(info.ActorType, new TypeDictionary { new CenterPositionInit(w.Map.CenterOfCell(startPos) + new WVec(WDist.Zero, WDist.Zero, aircraftInfo.CruiseAltitude)), new OwnerInit(owner), new FacingInit(spawnFacing) }); var exitCell = self.Location + exit.ExitCell; actor.QueueActivity(new Land(actor, Target.FromActor(self), WDist.Zero, WVec.Zero, info.Facing, clearCells: new CPos[1] { exitCell })); actor.QueueActivity(new CallFunc(() => { if (!self.IsInWorld || self.IsDead) { owner.PlayerActor.Trait <PlayerResources>().GiveCash(refundableValue); return; } foreach (var cargo in self.TraitsImplementing <INotifyDelivery>()) { cargo.Delivered(self); } self.World.AddFrameEndTask(ww => DoProduction(self, producee, exit, productionType, inits)); Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.ReadyAudio, self.Owner.Faction.InternalName); })); actor.QueueActivity(new FlyOffMap(actor, Target.FromCell(w, endPos))); actor.QueueActivity(new RemoveSelf()); }); return(true); }
public override void Draw() { var scaleBy = 100.0f; var provided = GetProvided(); var used = GetUsed(); var max = Math.Max(provided, used); while (max >= scaleBy) { scaleBy *= 2; } var providedFrac = providedLerp.Update(provided / scaleBy); var usedFrac = usedLerp.Update(used / scaleBy); var b = RenderBounds; var indicator = ChromeProvider.GetImage(IndicatorCollection, IndicatorImage); var color = GetBarColor(); if (Orientation == ResourceBarOrientation.Vertical) { if (Style == ResourceBarStyle.Bevelled) { var colorDark = Exts.ColorLerp(0.25f, color, Color.Black); for (var i = 0; i < b.Height; i++) { color = (i - 1 < b.Height / 2) ? color : colorDark; var bottom = new float2(b.Left + i, b.Bottom); var top = new float2(b.Left + i, b.Bottom + providedFrac * b.Height); // Indent corners if ((i == 0 || i == b.Width - 1) && providedFrac * b.Height > 1) { bottom.Y += 1; top.Y -= 1; } Game.Renderer.LineRenderer.DrawLine(bottom, top, color, color); } } else { Game.Renderer.LineRenderer.FillRect(new Rectangle(b.X, (int)float2.Lerp(b.Bottom, b.Top, providedFrac), b.Width, (int)(providedFrac * b.Height)), color); } var x = (b.Left + b.Right - indicator.size.X) / 2; var y = float2.Lerp(b.Bottom, b.Top, usedFrac) - indicator.size.Y / 2; Game.Renderer.RgbaSpriteRenderer.DrawSprite(indicator, new float2(x, y)); } else { if (Style == ResourceBarStyle.Bevelled) { var colorDark = Exts.ColorLerp(0.25f, color, Color.Black); for (var i = 0; i < b.Height; i++) { color = (i - 1 < b.Height / 2) ? color : colorDark; var left = new float2(b.Left, b.Top + i); var right = new float2(b.Left + providedFrac * b.Width, b.Top + i); // Indent corners if ((i == 0 || i == b.Height - 1) && providedFrac * b.Width > 1) { left.X += 1; right.X -= 1; } Game.Renderer.LineRenderer.DrawLine(left, right, color, color); } } else { Game.Renderer.LineRenderer.FillRect(new Rectangle(b.X, b.Y, (int)(providedFrac * b.Width), b.Height), color); } var x = float2.Lerp(b.Left, b.Right, usedFrac) - indicator.size.X / 2; var y = (b.Bottom + b.Top - indicator.size.Y) / 2; Game.Renderer.RgbaSpriteRenderer.DrawSprite(indicator, new float2(x, y)); } }
public override void Draw() { if (video == null) { return; } if (!stopped && !paused) { int nextFrame; if (video.HasAudio && !Game.Sound.DummyEngine) { nextFrame = (int)float2.Lerp(0, video.FrameCount, Game.Sound.VideoSeekPosition * invLength); } else { nextFrame = video.CurrentFrameIndex + 1; } // Without the 2nd check the sound playback sometimes ends before the final frame is displayed which causes the player to be stuck on the first frame if (nextFrame > video.FrameCount || nextFrame < video.CurrentFrameIndex) { Stop(); return; } var skippedFrames = 0; while (nextFrame > video.CurrentFrameIndex) { video.AdvanceFrame(); videoSprite.Sheet.GetTexture().SetData(video.CurrentFrameData, textureSize, textureSize); skippedFrames++; } if (skippedFrames > 1) { Log.Write("perf", $"{nameof(VideoPlayerWidget)}: {cachedVideoFileName} skipped {skippedFrames} frames at position {video.CurrentFrameIndex}"); } } WidgetUtils.DrawSprite(videoSprite, videoOrigin, videoSize); if (DrawOverlay) { // Create the scan line grid to render over the video // To avoid aliasing, this must be an integer number of screen pixels. // A few complications to be aware of: // - The video may have a different aspect ratio to the widget RenderBounds // - The RenderBounds coordinates may be a non-integer scale of the screen pixel size // - The screen pixel size may change while the video is playing back // (user moves a window between displays with different DPI on macOS) var scale = Game.Renderer.WindowScale; if (overlaySheet == null || overlayScale != scale) { overlaySheet?.Dispose(); // Calculate the scan line height by converting the video scale (copied from Open()) to screen // pixels, halving it (scan lines cover half the pixel height), and rounding to the nearest integer. var videoScale = Math.Min((float)RenderBounds.Width / video.Width, RenderBounds.Height / (video.Height * AspectRatio)); var halfRowHeight = (int)(videoScale * scale / 2 + 0.5f); // The overlay can be minimally stored in a 1px column which is stretched to cover the full screen var overlayHeight = (int)(RenderBounds.Height * scale / halfRowHeight); var overlaySheetSize = new Size(1, Exts.NextPowerOf2(overlayHeight)); var overlay = new byte[4 * Exts.NextPowerOf2(overlayHeight)]; overlaySheet = new Sheet(SheetType.BGRA, overlaySheetSize); // Every second pixel is the scan line - set alpha to 128 to make the lines less harsh for (var i = 3; i < 4 * overlayHeight; i += 8) { overlay[i] = 128; } overlaySheet.GetTexture().SetData(overlay, overlaySheetSize.Width, overlaySheetSize.Height); overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, overlayHeight), TextureChannel.RGBA); // Overlay origin must be rounded to the nearest screen pixel to prevent aliasing overlayOrigin = new float2((int)(RenderBounds.X * scale + 0.5f), (int)(RenderBounds.Y * scale + 0.5f)) / scale; overlaySize = new float2(RenderBounds.Width, overlayHeight * halfRowHeight / scale); overlayScale = scale; } WidgetUtils.DrawSprite(overlaySprite, overlayOrigin, overlaySize); } }
public Production(ProductionInfo info, Actor self) { Info = info; rp = Exts.Lazy(() => self.IsDead() ? null : self.TraitOrDefault <RallyPoint>()); }
public TestSampledRegression(double _dnu) { { TestName = "Модель семплированной регрессии"; TestFileName = "SampledRegression"; Vector <double> a = Exts.Vector(0.3, 0.4, 0.7); Vector <double> b = Exts.Vector(1.4, 3.0, 3.0); Vector <double> c = Exts.Vector(0.9, 1.5, 2.5); Vector <double> d = Exts.Vector(0.33, 0.37, 0.3); Vector <double> m = Exts.Vector(b[0] / (1 - a[0]), b[1] / (1 - a[1]), b[2] / (1 - a[2])); Vector <double> S = Exts.Vector(c[0] / Math.Sqrt(1 - a[0] * a[0]), c[1] / Math.Sqrt(1 - a[1] * a[1]), c[2] / Math.Sqrt(1 - a[2] * a[2])); Func <double, int> I = x => { if (x < 3) { return(0); } else if (x < 7) { return(1); } else { return(2); } }; Vector <double> mW = Exts.Vector(0); Matrix <double> dW = Exts.Diag(1.0); Vector <double> mNu = Exts.Vector(0); Matrix <double> dNu = Exts.Diag(_dnu); Vector <double> mEta = Exts.Vector(0); Matrix <double> dEta = Exts.Diag(1.0); Func <int, Vector <double>, Vector <double> > phi1 = (s, x) => Exts.Vector(a[I(x[0])] * x[0] + b[I(x[0])]); Func <int, Vector <double>, Matrix <double> > phi2 = (s, x) => Exts.Matrix(c[I(x[0])]); Func <int, Vector <double>, Vector <double> > psi = (s, x) => Exts.Vector(x[0]); //Phi1_latex = new string[] { @"a^T e(x_t) x_t + b^T e(x_t)" }; //Phi2_latex = new string[][] { new string[] { @"c^T e(x_t)" } }; //Psi1_latex = new string[] { @"x_t" }; //P_W = @"\mathcal{N}\left(" + mW.ToLatex() + ", " + dW.ToLatex() + @"\right)"; //P_Nu = @"\mathcal{N}\left(" + mNu.ToLatex() + ", " + dNu.ToLatex() + @"\right)"; //P_Eta = @"\mathcal{N}\left(" + mEta.ToLatex() + ", " + dEta.ToLatex() + @"\right)"; Normal[] NormalW = new Normal[1] { new Normal(mW[0], Math.Sqrt(dW[0, 0])) }; Normal[] NormalNu = new Normal[1] { new Normal(mNu[0], Math.Sqrt(dNu[0, 0])) }; Normal[] NormalEta = new Normal[1] { new Normal(mEta[0], Math.Sqrt(dEta[0, 0])) }; //Expression<Func<int, Vector<double>, Vector<double>>> expr = (s, x) => Vector(x[0] / (1 + x[0] * x[0]), x[1] / (1 + x[1] * x[1])); ; Phi1 = phi1; Phi2 = phi2; Psi1 = psi; //Xi = (s, x) => phi1(s, x) + phi2(s, x) * mW; Xi = (s, x) => { double num = 0; double den = 0; for (int i = 0; i < a.Count; i++) { num += d[i] * Normal.PDF(m[i], S[i], x[0]) * (a[i] * x[0] + b[i]); den += d[i] * Normal.PDF(m[i], S[i], x[0]); } return(Exts.Vector(num / den)); }; Zeta = (s, x, y, k) => y - psi(s, x) - mNu; W = (s) => Exts.Vector(NormalW[0].Sample()); Nu = (s) => Exts.Vector(NormalNu[0].Sample()); DW = dW; DNu = dNu; X0 = () => Exts.Vector(NormalEta[0].Sample()); X0Hat = mEta; DX0Hat = dEta; } }
int HomingInnerTick(int predClfDist, int diffClfMslHgt, int relTarHorDist, int lastHtChg, int lastHt, int nxtRelTarHorDist, int relTarHgt, int vFacing, bool targetPassedBy) { int desiredVFacing = vFacing; // Incline coming up -> attempt to reach the incline so that after predClfDist // the height above the terrain is positive but as close to 0 as possible // Also, never change horizontal facing and never travel backwards // Possible techniques to avoid close cliffs are deceleration, turning // as sharply as possible to travel directly upwards and then returning // to zero vertical facing as low as possible while still not hitting the // high terrain. A last technique (and the preferred one, normally used when // the missile hasn't been fired near a cliff) is simply finding the smallest // vertical facing that allows for a smooth climb to the new terrain's height // and coming in at predClfDist at exactly zero vertical facing if (info.TerrainHeightAware && diffClfMslHgt >= 0 && !allowPassBy) { desiredVFacing = IncreaseAltitude(predClfDist, diffClfMslHgt, relTarHorDist, vFacing); } else if (relTarHorDist <= 3 * loopRadius || state == States.Hitting) { // No longer travel at cruise altitude state = States.Hitting; if (lastHt >= targetPosition.Z) { allowPassBy = true; } if (!allowPassBy && (lastHt < targetPosition.Z || targetPassedBy)) { // Aim for the target var vDist = new WVec(-relTarHgt, -relTarHorDist, 0); desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing; // Do not accept -1 as valid vertical facing since it is usually a numerical error // and will lead to premature descent and crashing into the ground if (desiredVFacing == -1) { desiredVFacing = 0; } // If the target has been passed by, limit the absolute value of // vertical facing by the maximum vertical rate of turn // Do this because the missile will be looping horizontally // and thus needs smaller vertical facings so as not // to hit the ground prematurely if (targetPassedBy) { desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn.Facing, info.VerticalRateOfTurn.Facing); } else if (lastHt == 0) { // Before the target is passed by, missile speed should be changed // Target's height above loop's center var tarHgt = (loopRadius * WAngle.FromFacing(vFacing).Cos() / 1024 - System.Math.Abs(relTarHgt)).Clamp(0, loopRadius); // Target's horizontal distance from loop's center var tarDist = Exts.ISqrt(loopRadius * loopRadius - tarHgt * tarHgt); // Missile's horizontal distance from loop's center var missDist = loopRadius * WAngle.FromFacing(vFacing).Sin() / 1024; // If the current height does not permit the missile // to hit the target before passing it by, lower speed // Otherwise, increase speed if (relTarHorDist <= tarDist - System.Math.Sign(relTarHgt) * missDist) { ChangeSpeed(-1); } else { ChangeSpeed(); } } } else if (allowPassBy || (lastHt != 0 && relTarHorDist - lastHtChg < loopRadius)) { // Only activate this part if target too close to cliff allowPassBy = true; // Vector from missile's current position pointing to the loop's center var radius = new WVec(loopRadius, 0, 0) .Rotate(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(64 - vFacing))); // Vector from loop's center to incline top hardcoded in height buffer zone var edgeVector = new WVec(lastHtChg, lastHt - pos.Z, 0) - radius; if (!targetPassedBy) { // Climb to critical height if (relTarHorDist > 2 * loopRadius) { // Target's distance from cliff var d1 = relTarHorDist - lastHtChg; if (d1 < 0) { d1 = 0; } if (d1 > 2 * loopRadius) { return(0); } // Find critical height at which the missile must be once it is at one loopRadius // away from the target var h1 = loopRadius - Exts.ISqrt(d1 * (2 * loopRadius - d1)) - (pos.Z - lastHt); if (h1 > loopRadius * (1024 - WAngle.FromFacing(vFacing).Cos()) / 1024) { desiredVFacing = WAngle.ArcTan(Exts.ISqrt(h1 * (2 * loopRadius - h1)), loopRadius - h1).Angle >> 2; } else { desiredVFacing = 0; } // TODO: deceleration checks!!! } else { // Avoid the cliff edge if (info.TerrainHeightAware && edgeVector.Length > loopRadius && lastHt > targetPosition.Z) { int vFac; for (vFac = vFacing + 1; vFac <= vFacing + info.VerticalRateOfTurn.Facing - 1; vFac++) { // Vector from missile's current position pointing to the loop's center radius = new WVec(loopRadius, 0, 0) .Rotate(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(64 - vFac))); // Vector from loop's center to incline top + 64 hardcoded in height buffer zone edgeVector = new WVec(lastHtChg, lastHt - pos.Z, 0) - radius; if (edgeVector.Length <= loopRadius) { break; } } desiredVFacing = vFac; } else { // Aim for the target var vDist = new WVec(-relTarHgt, -relTarHorDist, 0); desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing; if (desiredVFacing < 0 && info.VerticalRateOfTurn.Facing < (sbyte)vFacing) { desiredVFacing = 0; } } } } else { // Aim for the target var vDist = new WVec(-relTarHgt, relTarHorDist, 0); desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing; if (desiredVFacing < 0 && info.VerticalRateOfTurn.Facing < (sbyte)vFacing) { desiredVFacing = 0; } } } else { // Aim to attain cruise altitude as soon as possible while having the absolute value // of vertical facing bound by the maximum vertical rate of turn var vDist = new WVec(-diffClfMslHgt - info.CruiseAltitude.Length, -speed, 0); desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing; // If the missile is launched above CruiseAltitude, it has to descend instead of climbing if (-diffClfMslHgt > info.CruiseAltitude.Length) { desiredVFacing = -desiredVFacing; } desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn.Facing, info.VerticalRateOfTurn.Facing); ChangeSpeed(); } } else { // Aim to attain cruise altitude as soon as possible while having the absolute value // of vertical facing bound by the maximum vertical rate of turn var vDist = new WVec(-diffClfMslHgt - info.CruiseAltitude.Length, -speed, 0); desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing; // If the missile is launched above CruiseAltitude, it has to descend instead of climbing if (-diffClfMslHgt > info.CruiseAltitude.Length) { desiredVFacing = -desiredVFacing; } desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn.Facing, info.VerticalRateOfTurn.Facing); ChangeSpeed(); } return(desiredVFacing); }
public Power(Actor self, PowerInfo info) : base(info) { PlayerPower = self.Owner.PlayerActor.Trait <PowerManager>(); powerModifiers = Exts.Lazy(() => self.TraitsImplementing <IPowerModifier>().ToArray()); }
public LabelForInputWidget() : base() { inputWidget = Exts.Lazy(() => Parent.Get <InputWidget>(For)); textColor = new CachedTransform <bool, Color>(disabled => disabled ? TextDisabledColor : TextColor); }
public LabelWithTooltipWidget(World world) : base() { tooltipContainer = Exts.Lazy(() => Ui.Root.Get <TooltipContainerWidget>(TooltipContainer)); }
public EditorViewportControllerWidget(World world, WorldRenderer worldRenderer) { this.worldRenderer = worldRenderer; tooltipContainer = Exts.Lazy(() => Ui.Root.Get <TooltipContainerWidget>(TooltipContainer)); CurrentBrush = DefaultBrush = new EditorDefaultBrush(this, worldRenderer); }
static bool SlotBot(S server, Connection conn, Session.Client client, string 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); } // Invalid slot if (bot != null && bot.Bot == null) { server.SendOrderTo(conn, "Message", "Can't add bots to a slot with another client."); return(true); } var botType = parts[2]; var botInfo = server.Map.Rules.Actors["player"].TraitInfos <IBotInfo>() .FirstOrDefault(b => b.Type == botType); if (botInfo == null) { server.SendOrderTo(conn, "Message", "Invalid bot type."); return(true); } slot.Closed = false; if (bot == null) { // Create a new bot bot = new Session.Client() { Index = server.ChooseFreePlayerIndex(), Name = botInfo.Name, Bot = botType, Slot = parts[0], Faction = "Random", SpawnPoint = 0, Team = 0, State = Session.ClientState.NotReady, BotControllerClientIndex = controllerClientIndex }; // Pick a random color for the bot var validator = server.ModData.Manifest.Get <ColorValidator>(); var tileset = server.Map.Rules.TileSet; var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color); var playerColors = server.LobbyInfo.Clients.Select(c => c.Color.RGB) .Concat(server.Map.Players.Players.Values.Select(p => p.Color.RGB)); bot.Color = bot.PreferredColor = validator.RandomPresetColor(server.Random, terrainColors, playerColors); server.LobbyInfo.Clients.Add(bot); } else { // Change the type of the existing bot bot.Name = botInfo.Name; bot.Bot = botType; } S.SyncClientToPlayerReference(bot, server.Map.Players.Players[parts[0]]); server.SyncLobbyClients(); server.SyncLobbySlots(); return(true); }
public VqaReader(Stream stream) { this.stream = stream; // Decode FORM chunk if (stream.ReadASCII(4) != "FORM") { throw new InvalidDataException("Invalid vqa (invalid FORM section)"); } /*var length = */ stream.ReadUInt32(); if (stream.ReadASCII(8) != "WVQAVQHD") { throw new InvalidDataException("Invalid vqa (not WVQAVQHD)"); } /* var length = */ stream.ReadUInt32(); /*var version = */ stream.ReadUInt16(); /*var flags = */ stream.ReadUInt16(); Frames = stream.ReadUInt16(); Width = stream.ReadUInt16(); Height = stream.ReadUInt16(); blockWidth = stream.ReadUInt8(); blockHeight = stream.ReadUInt8(); Framerate = stream.ReadUInt8(); cbParts = stream.ReadUInt8(); blocks = new int2(Width / blockWidth, Height / blockHeight); numColors = stream.ReadUInt16(); /*var maxBlocks = */ stream.ReadUInt16(); /*var unknown1 = */ stream.ReadUInt16(); /*var unknown2 = */ stream.ReadUInt32(); // Audio /*var freq = */ stream.ReadUInt16(); /*var channels = */ stream.ReadByte(); /*var bits = */ stream.ReadByte(); /*var unknown3 = */ stream.ReadBytes(14); var frameSize = Exts.NextPowerOf2(Math.Max(Width, Height)); cbf = new byte[Width * Height]; cbp = new byte[Width * Height]; palette = new uint[numColors]; origData = new byte[2 * blocks.X * blocks.Y]; frameData = new uint[frameSize, frameSize]; var type = stream.ReadASCII(4); if (type != "FINF") { stream.Seek(27, SeekOrigin.Current); type = stream.ReadASCII(4); } /*var length = */ stream.ReadUInt16(); /*var unknown4 = */ stream.ReadUInt16(); // Frame offsets offsets = new UInt32[Frames]; for (var i = 0; i < Frames; i++) { offsets[i] = stream.ReadUInt32(); if (offsets[i] > 0x40000000) { offsets[i] -= 0x40000000; } offsets[i] <<= 1; } CollectAudioData(); Reset(); }
public override void Draw() { if (world.LocalPlayer == null) { return; } if (world.LocalPlayer.WinState != WinState.Undefined) { return; } var radarBin = Ui.Root.GetWidget <RadarBinWidget>(RadarBin); powerCollection = "power-" + world.LocalPlayer.Country.Race; // Nothing to draw if (power.PowerProvided == 0 && power.PowerDrained == 0) { return; } // Draw bar horizontally var barStart = powerOrigin + radarBin.RadarOrigin; var barEnd = barStart + new float2(powerSize.Width, 0); float powerScaleBy = 100; var maxPower = Math.Max(power.PowerProvided, power.PowerDrained); while (maxPower >= powerScaleBy) { powerScaleBy *= 2; } // Current power supply var powerLevelTemp = barStart.X + (barEnd.X - barStart.X) * (power.PowerProvided / powerScaleBy); lastPowerProvidedPos = float2.Lerp(lastPowerProvidedPos.GetValueOrDefault(powerLevelTemp), powerLevelTemp, PowerBarLerpFactor); var powerLevel = new float2(lastPowerProvidedPos.Value, barStart.Y); var color = GetPowerColor(power); var colorDark = Exts.ColorLerp(0.25f, color, Color.Black); for (int i = 0; i < powerSize.Height; i++) { color = (i - 1 < powerSize.Height / 2) ? color : colorDark; var leftOffset = new float2(0, i); var rightOffset = new float2(0, i); // Indent corners if ((i == 0 || i == powerSize.Height - 1) && powerLevel.X - barStart.X > 1) { leftOffset.X += 1; rightOffset.X -= 1; } Game.Renderer.LineRenderer.DrawLine(barStart + leftOffset, powerLevel + rightOffset, color, color); } // Power usage indicator var indicator = ChromeProvider.GetImage(powerCollection, "power-indicator"); var powerDrainedTemp = barStart.X + (barEnd.X - barStart.X) * (power.PowerDrained / powerScaleBy); lastPowerDrainedPos = float2.Lerp(lastPowerDrainedPos.GetValueOrDefault(powerDrainedTemp), powerDrainedTemp, PowerBarLerpFactor); var powerDrainLevel = new float2(lastPowerDrainedPos.Value - indicator.size.X / 2, barStart.Y - 1); Game.Renderer.RgbaSpriteRenderer.DrawSprite(indicator, powerDrainLevel); }
public void StartGame(Arguments args) { Launch = new LaunchArguments(args); Ui.ResetAll(); Game.Settings.Save(); if (Launch.Benchmark) { Log.AddChannel("cpu", "cpu.csv"); Log.Write("cpu", "tick;time [ms]"); Log.AddChannel("render", "render.csv"); Log.Write("render", "frame;time [ms]"); Console.WriteLine("Saving benchmark data into {0}".F(Path.Combine(Platform.SupportDir, "Logs"))); Game.BenchmarkMode = true; } // Join a server directly var connect = Launch.GetConnectAddress(); if (!string.IsNullOrEmpty(connect)) { var parts = connect.Split(':'); if (parts.Length == 2) { var host = parts[0]; var port = Exts.ParseIntegerInvariant(parts[1]); Game.LoadShellMap(); Game.RemoteDirectConnect(host, port); return; } } // Load a replay directly if (!string.IsNullOrEmpty(Launch.Replay)) { ReplayMetadata replayMeta = null; try { replayMeta = ReplayMetadata.Read(Launch.Replay); } catch { } if (ReplayUtils.PromptConfirmReplayCompatibility(replayMeta, Game.LoadShellMap)) { Game.JoinReplay(Launch.Replay); } if (replayMeta != null) { var mod = replayMeta.GameInfo.Mod; if (mod != null && mod != Game.ModData.Manifest.Id && Game.Mods.ContainsKey(mod)) { Game.InitializeMod(mod, args); } } return; } Game.LoadShellMap(); Game.Settings.Save(); }
protected LabelForInputWidget(LabelForInputWidget other) : base(other) { inputWidget = Exts.Lazy(() => Parent.Get <InputWidget>(other.For)); textColor = new CachedTransform <bool, Color>(disabled => disabled ? TextDisabledColor : TextColor); }
Action InitDisplayPanel(Widget panel) { var ds = Game.Settings.Graphics; var gs = Game.Settings.Game; BindCheckboxPref(panel, "HARDWARECURSORS_CHECKBOX", ds, "HardwareCursors"); BindCheckboxPref(panel, "PIXELDOUBLE_CHECKBOX", ds, "PixelDouble"); BindCheckboxPref(panel, "CURSORDOUBLE_CHECKBOX", ds, "CursorDouble"); BindCheckboxPref(panel, "FRAME_LIMIT_CHECKBOX", ds, "CapFramerate"); BindCheckboxPref(panel, "SHOW_SHELLMAP", gs, "ShowShellmap"); BindCheckboxPref(panel, "DISPLAY_TARGET_LINES_CHECKBOX", gs, "DrawTargetLine"); BindCheckboxPref(panel, "PLAYER_STANCE_COLORS_CHECKBOX", gs, "UsePlayerStanceColors"); var languageDropDownButton = panel.Get <DropDownButtonWidget>("LANGUAGE_DROPDOWNBUTTON"); languageDropDownButton.OnMouseDown = _ => ShowLanguageDropdown(languageDropDownButton, modData.Languages); languageDropDownButton.GetText = () => FieldLoader.Translate(ds.Language); var windowModeDropdown = panel.Get <DropDownButtonWidget>("MODE_DROPDOWN"); windowModeDropdown.OnMouseDown = _ => ShowWindowModeDropdown(windowModeDropdown, ds); windowModeDropdown.GetText = () => ds.Mode == WindowMode.Windowed ? "Windowed" : ds.Mode == WindowMode.Fullscreen ? "Fullscreen" : "Pseudo-Fullscreen"; var statusBarsDropDown = panel.Get <DropDownButtonWidget>("STATUS_BAR_DROPDOWN"); statusBarsDropDown.OnMouseDown = _ => ShowStatusBarsDropdown(statusBarsDropDown, gs); statusBarsDropDown.GetText = () => gs.StatusBars.ToString() == "Standard" ? "Standard" : gs.StatusBars.ToString() == "DamageShow" ? "Show On Damage" : "Always Show"; // Update zoom immediately var pixelDoubleCheckbox = panel.Get <CheckboxWidget>("PIXELDOUBLE_CHECKBOX"); var pixelDoubleOnClick = pixelDoubleCheckbox.OnClick; pixelDoubleCheckbox.OnClick = () => { pixelDoubleOnClick(); worldRenderer.Viewport.Zoom = ds.PixelDouble ? 2 : 1; }; // Cursor doubling is only supported with software cursors and when pixel doubling is enabled var cursorDoubleCheckbox = panel.Get <CheckboxWidget>("CURSORDOUBLE_CHECKBOX"); cursorDoubleCheckbox.IsDisabled = () => !ds.PixelDouble || Game.Cursor is HardwareCursor; var cursorDoubleIsChecked = cursorDoubleCheckbox.IsChecked; cursorDoubleCheckbox.IsChecked = () => !cursorDoubleCheckbox.IsDisabled() && cursorDoubleIsChecked(); panel.Get("WINDOW_RESOLUTION").IsVisible = () => ds.Mode == WindowMode.Windowed; var windowWidth = panel.Get <TextFieldWidget>("WINDOW_WIDTH"); windowWidth.Text = ds.WindowedSize.X.ToString(); var windowHeight = panel.Get <TextFieldWidget>("WINDOW_HEIGHT"); windowHeight.Text = ds.WindowedSize.Y.ToString(); var frameLimitTextfield = panel.Get <TextFieldWidget>("FRAME_LIMIT_TEXTFIELD"); frameLimitTextfield.Text = ds.MaxFramerate.ToString(); var escPressed = false; frameLimitTextfield.OnLoseFocus = () => { if (escPressed) { escPressed = false; return; } int fps; Exts.TryParseIntegerInvariant(frameLimitTextfield.Text, out fps); ds.MaxFramerate = fps.Clamp(1, 1000); frameLimitTextfield.Text = ds.MaxFramerate.ToString(); }; frameLimitTextfield.OnEnterKey = () => { frameLimitTextfield.YieldKeyboardFocus(); return(true); }; frameLimitTextfield.OnEscKey = () => { frameLimitTextfield.Text = ds.MaxFramerate.ToString(); escPressed = true; frameLimitTextfield.YieldKeyboardFocus(); return(true); }; frameLimitTextfield.IsDisabled = () => !ds.CapFramerate; // Player profile var ps = Game.Settings.Player; var nameTextfield = panel.Get <TextFieldWidget>("PLAYERNAME"); nameTextfield.IsDisabled = () => worldRenderer.World.Type != WorldType.Shellmap; nameTextfield.Text = Settings.SanitizedPlayerName(ps.Name); nameTextfield.OnLoseFocus = () => { if (escPressed) { escPressed = false; return; } nameTextfield.Text = nameTextfield.Text.Trim(); if (nameTextfield.Text.Length == 0) { nameTextfield.Text = Settings.SanitizedPlayerName(ps.Name); } else { nameTextfield.Text = Settings.SanitizedPlayerName(nameTextfield.Text); ps.Name = nameTextfield.Text; } }; nameTextfield.OnEnterKey = () => { nameTextfield.YieldKeyboardFocus(); return(true); }; nameTextfield.OnEscKey = () => { nameTextfield.Text = Settings.SanitizedPlayerName(ps.Name); escPressed = true; nameTextfield.YieldKeyboardFocus(); return(true); }; var colorPreview = panel.Get <ColorPreviewManagerWidget>("COLOR_MANAGER"); colorPreview.Color = ps.Color; var colorDropdown = panel.Get <DropDownButtonWidget>("PLAYERCOLOR"); colorDropdown.IsDisabled = () => worldRenderer.World.Type != WorldType.Shellmap; colorDropdown.OnMouseDown = _ => ColorPickerLogic.ShowColorDropDown(colorDropdown, colorPreview, worldRenderer.World); colorDropdown.Get <ColorBlockWidget>("COLORBLOCK").GetColor = () => ps.Color.RGB; return(() => { int x, y; Exts.TryParseIntegerInvariant(windowWidth.Text, out x); Exts.TryParseIntegerInvariant(windowHeight.Text, out y); ds.WindowedSize = new int2(x, y); frameLimitTextfield.YieldKeyboardFocus(); nameTextfield.YieldKeyboardFocus(); }); }
public DefaultSpriteSequence(ModData modData, TileSet tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info) { Name = animation; Loader = loader; var d = info.ToDictionary(); try { Start = LoadField <int>(d, "Start", 0); ShadowStart = LoadField <int>(d, "ShadowStart", -1); ShadowZOffset = LoadField <WDist>(d, "ShadowZOffset", DefaultShadowSpriteZOffset).Length; ZOffset = LoadField <WDist>(d, "ZOffset", WDist.Zero).Length; Tick = LoadField <int>(d, "Tick", 40); transpose = LoadField <bool>(d, "Transpose", false); Frames = LoadField <int[]>(d, "Frames", null); Facings = LoadField <int>(d, "Facings", 1); if (Facings < 0) { reverseFacings = true; Facings = -Facings; } var offset = LoadField <float2>(d, "Offset", float2.Zero); var blendMode = LoadField <BlendMode>(d, "BlendMode", BlendMode.Alpha); MiniYaml combine; if (d.TryGetValue("Combine", out combine)) { var combined = Enumerable.Empty <Sprite>(); foreach (var sub in combine.Nodes) { var sd = sub.Value.ToDictionary(); // Allow per-sprite offset, start, and length var subStart = LoadField <int>(sd, "Start", 0); var subOffset = LoadField <float2>(sd, "Offset", float2.Zero); var subSrc = GetSpriteSrc(modData, tileSet, sequence, animation, sub.Key, sd); var subSprites = cache[subSrc].Select( s => new Sprite(s.Sheet, s.Bounds, s.Offset + subOffset + offset, s.Channel, blendMode)); var subLength = 0; MiniYaml subLengthYaml; if (sd.TryGetValue("Length", out subLengthYaml) && subLengthYaml.Value == "*") { subLength = subSprites.Count() - subStart; } else { subLength = LoadField <int>(sd, "Length", 1); } combined = combined.Concat(subSprites.Skip(subStart).Take(subLength)); } sprites = combined.ToArray(); } else { // Apply offset to each sprite in the sequence // Different sequences may apply different offsets to the same frame var src = GetSpriteSrc(modData, tileSet, sequence, animation, info.Value, d); sprites = cache[src].Select( s => new Sprite(s.Sheet, s.Bounds, s.Offset + offset, s.Channel, blendMode)).ToArray(); } MiniYaml length; if (d.TryGetValue("Length", out length) && length.Value == "*") { Length = sprites.Length - Start; } else { Length = LoadField <int>(d, "Length", 1); } // Plays the animation forwards, and then in reverse if (LoadField <bool>(d, "Reverses", false)) { var frames = Frames ?? Exts.MakeArray(Length, i => Start + i); Frames = frames.Concat(frames.Skip(1).Take(frames.Length - 2).Reverse()).ToArray(); Length = 2 * Length - 2; } Stride = LoadField <int>(d, "Stride", Length); if (Length > Stride) { throw new InvalidOperationException( "{0}: Sequence {1}.{2}: Length must be <= stride" .F(info.Nodes[0].Location, sequence, animation)); } if (Start < 0 || Start + Facings * Stride > sprites.Length) { throw new InvalidOperationException( "{5}: Sequence {0}.{1} uses frames [{2}..{3}], but only 0..{4} actually exist" .F(sequence, animation, Start, Start + Facings * Stride - 1, sprites.Length - 1, info.Nodes[0].Location)); } if (ShadowStart + Facings * Stride > sprites.Length) { throw new InvalidOperationException( "{5}: Sequence {0}.{1}'s shadow frames use frames [{2}..{3}], but only [0..{4}] actually exist" .F(sequence, animation, ShadowStart, ShadowStart + Facings * Stride - 1, sprites.Length - 1, info.Nodes[0].Location)); } } catch (FormatException f) { throw new FormatException("Failed to parse sequences for {0}.{1} at {2}:\n{3}".F(sequence, animation, info.Nodes[0].Location, f)); } }
int IncreaseAltitude(int predClfDist, int diffClfMslHgt, int relTarHorDist, int vFacing) { var desiredVFacing = vFacing; // If missile is below incline top height and facing downwards, bring back // its vertical facing above zero as soon as possible if ((sbyte)vFacing < 0) { desiredVFacing = info.VerticalRateOfTurn.Facing; } // Missile will climb around incline top if bringing vertical facing // down to zero on an arc of radius loopRadius else if (IsNearInclineTop(vFacing, loopRadius, predClfDist) && WillClimbAroundInclineTop(vFacing, loopRadius, predClfDist, diffClfMslHgt, speed)) { desiredVFacing = 0; } // Missile will not climb terrAltDiff w-units within hHeightChange w-units // all the while ending the ascent with vertical facing 0 else if (!WillClimbWithinDistance(vFacing, loopRadius, predClfDist, diffClfMslHgt)) { // Find smallest vertical facing, attainable in the next tick, // for which the missile will be able to climb terrAltDiff w-units // within hHeightChange w-units all the while ending the ascent // with vertical facing 0 for (var vFac = System.Math.Min(vFacing + info.VerticalRateOfTurn.Facing - 1, 63); vFac >= vFacing; vFac--) { if (!WillClimbWithinDistance(vFac, loopRadius, predClfDist, diffClfMslHgt) && !(predClfDist <= loopRadius * (1024 - WAngle.FromFacing(vFac).Sin()) / 1024 && WillClimbAroundInclineTop(vFac, loopRadius, predClfDist, diffClfMslHgt, speed))) { desiredVFacing = vFac + 1; break; } } } // Attained height after ascent as predicted from upper part of incline surmounting manoeuvre var predAttHght = loopRadius * (1024 - WAngle.FromFacing(vFacing).Cos()) / 1024 - diffClfMslHgt; // Should the missile be slowed down in order to make it more maneuverable var slowDown = info.Acceleration.Length != 0 && // Possible to decelerate ((desiredVFacing != 0 // Lower part of incline surmounting manoeuvre // Incline will be hit before vertical facing attains 64 && (predClfDist <= loopRadius * (1024 - WAngle.FromFacing(vFacing).Sin()) / 1024 // When evaluating this the incline will be *not* be hit before vertical facing attains 64 // At current speed target too close to hit without passing it by || relTarHorDist <= 2 * loopRadius * (2048 - WAngle.FromFacing(vFacing).Sin()) / 1024 - predClfDist)) || (desiredVFacing == 0 && // Upper part of incline surmounting manoeuvre relTarHorDist <= loopRadius * WAngle.FromFacing(vFacing).Sin() / 1024 + Exts.ISqrt(predAttHght * (2 * loopRadius - predAttHght)))); // Target too close to hit at current speed if (slowDown) { ChangeSpeed(-1); } return(desiredVFacing); }
public Theater(TileSet tileset, Action <uint, string> onMissingImage = null) { this.tileset = tileset; var allocated = false; Func <Sheet> allocate = () => { if (allocated) { throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); } allocated = true; return(new Sheet(SheetType.Indexed, new Size(tileset.SheetSize, tileset.SheetSize))); }; random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders); foreach (var t in tileset.Templates) { var variants = new List <Sprite[]>(); foreach (var i in t.Value.Images) { ISpriteFrame[] allFrames; if (onMissingImage != null) { try { allFrames = frameCache[i]; } catch (FileNotFoundException) { onMissingImage(t.Key, i); continue; } } else { allFrames = frameCache[i]; } var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length; var indices = t.Value.Frames != null ? t.Value.Frames : Exts.MakeArray(t.Value.TilesCount, j => j); var start = indices.Min(); var end = indices.Max(); if (start < 0 || end >= frameCount) { throw new YamlException("Template `{0}` uses frames [{1}..{2}] of {3}, but only [0..{4}] actually exist" .F(t.Key, start, end, i, frameCount - 1)); } variants.Add(indices.Select(j => { var f = allFrames[j]; var tile = t.Value.Contains(j) ? t.Value[j] : null; // The internal z axis is inverted from expectation (negative is closer) var zOffset = tile != null ? -tile.ZOffset : 0; var zRamp = tile != null ? tile.ZRamp : 1f; var offset = new float3(f.Offset, zOffset); var type = SheetBuilder.FrameTypeToSheetType(f.Type); // Defer SheetBuilder creation until we know what type of frames we are loading! // TODO: Support mixed indexed and BGRA frames if (sheetBuilder == null) { sheetBuilder = new SheetBuilder(SheetBuilder.FrameTypeToSheetType(f.Type), allocate); } else if (type != sheetBuilder.Type) { throw new YamlException("Sprite type mismatch. Terrain sprites must all be either Indexed or RGBA."); } var s = sheetBuilder.Allocate(f.Size, zRamp, offset); Util.FastCopyIntoChannel(s, f.Data); if (tileset.EnableDepth) { var ss = sheetBuilder.Allocate(f.Size, zRamp, offset); Util.FastCopyIntoChannel(ss, allFrames[j + frameCount].Data); // s and ss are guaranteed to use the same sheet // because of the custom terrain sheet allocation s = new SpriteWithSecondaryData(s, s.Sheet, ss.Bounds, ss.Channel); } return(s); }).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) { allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode)); } if (onMissingImage != null && !variants.Any()) { continue; } templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[sheetBuilder.Type == SheetType.BGRA ? 4 : 1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
public ClientTooltipRegionWidget() { tooltipContainer = Exts.Lazy(() => Ui.Root.Get <TooltipContainerWidget>(TooltipContainer)); }
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); } if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer && server.LobbyInfo.NonBotPlayers.Count() < 2) { server.SendOrderTo(conn, "Message", server.TwoHumansRequiredText); 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); } // If the previous slot had a locked spawn then we must not carry that to the new slot var oldSlot = client.Slot != null ? server.LobbyInfo.Slots[client.Slot] : null; if (oldSlot != null && oldSlot.LockSpawn) { client.SpawnPoint = 0; } client.Slot = s; S.SyncClientToPlayerReference(client, server.Map.Players.Players[s]); if (!slot.LockColor) { client.PreferredColor = client.Color = SanitizePlayerColor(server, client.Color, client.Index, conn); } 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.Team = 0; client.Color = HSLColor.FromRGB(255, 255, 255); server.SyncLobbyClients(); CheckAutoStart(server); 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); } // Invalid slot if (bot != null && bot.Bot == null) { server.SendOrderTo(conn, "Message", "Can't add bots to a slot with another client."); return(true); } var botType = parts[2]; var botInfo = server.Map.Rules.Actors["player"].TraitInfos <IBotInfo>() .FirstOrDefault(b => b.Type == botType); if (botInfo == null) { server.SendOrderTo(conn, "Message", "Invalid bot type."); return(true); } slot.Closed = false; if (bot == null) { // Create a new bot bot = new Session.Client() { Index = server.ChooseFreePlayerIndex(), Name = botInfo.Name, Bot = botType, Slot = parts[0], Faction = "Random", SpawnPoint = 0, Team = 0, State = Session.ClientState.NotReady, BotControllerClientIndex = controllerClientIndex }; // Pick a random color for the bot var validator = server.ModData.Manifest.Get <ColorValidator>(); var tileset = server.Map.Rules.TileSet; var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color); var playerColors = server.LobbyInfo.Clients.Select(c => c.Color.RGB) .Concat(server.Map.Players.Players.Values.Select(p => p.Color.RGB)); bot.Color = bot.PreferredColor = validator.RandomPresetColor(server.Random, terrainColors, playerColors); server.LobbyInfo.Clients.Add(bot); } else { // Change the type of the existing bot bot.Name = botInfo.Name; bot.Bot = botType; } S.SyncClientToPlayerReference(bot, server.Map.Players.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); } var lastMap = server.LobbyInfo.GlobalSettings.Map; Action <MapPreview> selectMap = map => { // Make sure the map hasn't changed in the meantime if (server.LobbyInfo.GlobalSettings.Map != lastMap) { return; } server.LobbyInfo.GlobalSettings.Map = map.Uid; var oldSlots = server.LobbyInfo.Slots.Keys.ToArray(); server.Map = server.ModData.MapCache[server.LobbyInfo.GlobalSettings.Map]; server.LobbyInfo.Slots = server.Map.Players.Players .Select(p => MakeSlotFromPlayerReference(p.Value)) .Where(ss => ss != null) .ToDictionary(ss => ss.PlayerReference, ss => ss); LoadMapSettings(server, server.LobbyInfo.GlobalSettings, server.Map.Rules); // 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 // - Bots who are not defined in the map rules are dropped var botTypes = server.Map.Rules.Actors["player"].TraitInfos <IBotInfo>().Select(t => t.Type); 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.Map.Players.Players[c.Slot].AllowBots || !botTypes.Contains(c.Bot))) { server.LobbyInfo.Clients.Remove(c); } S.SyncClientToPlayerReference(c, server.Map.Players.Players[c.Slot]); } else if (c.Bot != null) { server.LobbyInfo.Clients.Remove(c); } } // Validate if color is allowed and get an alternative if it isn't foreach (var c in server.LobbyInfo.Clients) { if (c.Slot != null && !server.LobbyInfo.Slots[c.Slot].LockColor) { c.Color = c.PreferredColor = SanitizePlayerColor(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.DefinesUnsafeCustomRules) { server.SendMessage("This map contains custom rules. Game experience may change."); } if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer) { server.SendMessage(server.TwoHumansRequiredText); } else if (server.Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots)) { server.SendMessage("Bots have been disabled on this map."); } var briefing = MissionBriefingOrDefault(server); if (briefing != null) { server.SendMessage(briefing); } }; Action queryFailed = () => server.SendOrderTo(conn, "Message", "Map was not found on server."); var m = server.ModData.MapCache[s]; if (m.Status == MapStatus.Available || m.Status == MapStatus.DownloadAvailable) { selectMap(m); } else if (server.Settings.QueryMapRepository) { server.SendOrderTo(conn, "Message", "Searching for map on the Resource Center..."); var mapRepository = server.ModData.Manifest.Get <WebServices>().MapRepository; server.ModData.MapCache.QueryRemoteMapDetails(mapRepository, new[] { s }, selectMap, queryFailed); } else { queryFailed(); } return(true); } }, { "option", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can change the configuration."); return(true); } var allOptions = server.Map.Rules.Actors["player"].TraitInfos <ILobbyOptions>() .Concat(server.Map.Rules.Actors["world"].TraitInfos <ILobbyOptions>()) .SelectMany(t => t.LobbyOptions(server.Map.Rules)); // Overwrite keys with duplicate ids var options = new Dictionary <string, LobbyOption>(); foreach (var o in allOptions) { options[o.Id] = o; } var split = s.Split(' '); LobbyOption option; if (split.Length < 2 || !options.TryGetValue(split[0], out option) || !option.Values.ContainsKey(split[1])) { server.SendOrderTo(conn, "Message", "Invalid configuration command."); return(true); } if (option.IsLocked) { server.SendOrderTo(conn, "Message", "{0} cannot be changed.".F(option.Name)); return(true); } var oo = server.LobbyInfo.GlobalSettings.LobbyOptions[option.Id]; if (oo.Value == split[1]) { return(true); } oo.Value = oo.PreferredValue = split[1]; if (option.Id == "gamespeed") { var speed = server.ModData.Manifest.Get <GameSpeeds>().Speeds[oo.Value]; server.LobbyInfo.GlobalSettings.Timestep = speed.Timestep; server.LobbyInfo.GlobalSettings.OrderLatency = speed.OrderLatency; } server.SyncLobbyGlobalSettings(); server.SendMessage(option.ValueChangedMessage(client.Name, split[1])); 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); } }, { "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", "No-one 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 = 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); } var factions = server.Map.Rules.Actors["world"].TraitInfos <FactionInfo>() .Where(f => f.Selectable).Select(f => f.InternalName); if (!factions.Contains(parts[1])) { server.SendOrderTo(conn, "Message", "Invalid faction selected: {0}".F(parts[1])); server.SendOrderTo(conn, "Message", "Supported values: {0}".F(factions.JoinWith(", "))); 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.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); } // Check if any other slot has locked the requested spawn if (spawnPoint > 0) { var spawnLockedByAnotherSlot = server.LobbyInfo.Slots.Where(ss => ss.Value.LockSpawn).Any(ss => { var pr = PlayerReferenceForSlot(server, ss.Value); return(pr != null && pr.Spawn == spawnPoint); }); if (spawnLockedByAnotherSlot) { server.SendOrderTo(conn, "Message", "The spawn point is locked to another player slot."); 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); } // Validate if color is allowed and get an alternative it isn't var newColor = FieldLoader.GetValue <HSLColor>("(value)", parts[1]); targetClient.Color = SanitizePlayerColor(server, newColor, targetClient.Index, conn); // Only update player's preferred color if new color is valid if (newColor == targetClient.Color) { targetClient.PreferredColor = targetClient.Color; } server.SyncLobbyClients(); return(true); } }, { "sync_lobby", s => { if (!client.IsAdmin) { server.SendOrderTo(conn, "Message", "Only the host can set lobby info"); return(true); } var lobbyInfo = Session.Deserialize(s); if (lobbyInfo == null) { server.SendOrderTo(conn, "Message", "Invalid Lobby Info Sent"); return(true); } server.LobbyInfo = lobbyInfo; server.SyncLobbyInfo(); 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)); }
public ProductionParadrop(ActorInitializer init, ProductionParadropInfo info) : base(init, info) { rp = Exts.Lazy(() => init.Self.IsDead ? null : init.Self.TraitOrDefault <RallyPoint>()); }
enum IniMapFormat { RedAlert = 3 } // otherwise, cnc (2 variants exist, we don't care to differentiate) public void ConvertIniMap(string iniFile) { using (var stream = GlobalFileSystem.Open(iniFile)) { var file = new IniFile(stream); var basic = file.GetSection("Basic"); var mapSection = file.GetSection("Map"); var legacyMapFormat = (IniMapFormat)Exts.ParseIntegerInvariant(basic.GetValue("NewINIFormat", "0")); var offsetX = Exts.ParseIntegerInvariant(mapSection.GetValue("X", "0")); var offsetY = Exts.ParseIntegerInvariant(mapSection.GetValue("Y", "0")); var width = Exts.ParseIntegerInvariant(mapSection.GetValue("Width", "0")); var height = Exts.ParseIntegerInvariant(mapSection.GetValue("Height", "0")); mapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64; var tileset = Truncate(mapSection.GetValue("Theater", "TEMPERAT"), 8); map = new Map(rules.TileSets[tileset], mapSize, mapSize) { Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(iniFile)), Author = "Westwood Studios" }; var tl = new PPos(offsetX, offsetY); var br = new PPos(offsetX + width - 1, offsetY + height - 1); map.SetBounds(tl, br); if (legacyMapFormat == IniMapFormat.RedAlert) { UnpackRATileData(ReadPackedSection(file.GetSection("MapPack"))); UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack"))); ReadRATrees(file); } else { // CnC using (var s = GlobalFileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin")) UnpackCncTileData(s); ReadCncOverlay(file); ReadCncTrees(file); } LoadVideos(file, "BASIC"); LoadActors(file, "STRUCTURES"); LoadActors(file, "UNITS"); LoadActors(file, "INFANTRY"); LoadActors(file, "SHIPS"); LoadSmudges(file, "SMUDGE"); var wps = file.GetSection("Waypoints") .Where(kv => Exts.ParseIntegerInvariant(kv.Value) > 0) .Select(kv => Pair.New(Exts.ParseIntegerInvariant(kv.Key), LocationFromMapOffset(Exts.ParseIntegerInvariant(kv.Value), mapSize))); // Add waypoint actors foreach (var kv in wps) { if (kv.First <= 7) { var ar = new ActorReference("mpspawn") { new LocationInit((CPos)kv.Second), new OwnerInit("Neutral") }; map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, ar.Save())); } else { var ar = new ActorReference("waypoint") { new LocationInit((CPos)kv.Second), new OwnerInit("Neutral") }; map.ActorDefinitions.Add(new MiniYamlNode("waypoint" + kv.First, ar.Save())); } } // Create default player definitions only if there are no players to import mapPlayers = new MapPlayers(map.Rules, (players.Count == 0) ? map.SpawnPoints.Value.Length : 0); foreach (var p in players) { LoadPlayer(file, p, legacyMapFormat == IniMapFormat.RedAlert); } map.PlayerDefinitions = mapPlayers.ToMiniYaml(); } }
public Production(ActorInitializer init, ProductionInfo info) : base(info) { rp = Exts.Lazy(() => init.Self.IsDead ? null : init.Self.TraitOrDefault <RallyPoint>()); Faction = init.Contains <FactionInit>() ? init.Get <FactionInit, string>() : init.Self.Owner.Faction.InternalName; }
void LoadActors(IniFile file, string section) { foreach (var s in file.GetSection(section, true)) { // Structures: num=owner,type,health,location,turret-facing,trigger // Units: num=owner,type,health,location,facing,action,trigger // Infantry: num=owner,type,health,location,subcell,action,facing,trigger try { var parts = s.Value.Split(','); if (parts[0] == "") { parts[0] = "Neutral"; } if (!players.Contains(parts[0])) { players.Add(parts[0]); } var loc = Exts.ParseIntegerInvariant(parts[3]); var health = Exts.ParseIntegerInvariant(parts[2]) * 100 / 256; var facing = (section == "INFANTRY") ? Exts.ParseIntegerInvariant(parts[6]) : Exts.ParseIntegerInvariant(parts[4]); var actor = new ActorReference(parts[1].ToLowerInvariant()) { new LocationInit(new CPos(loc % mapSize, loc / mapSize)), new OwnerInit(parts[0]), }; var initDict = actor.InitDict; if (health != 100) { initDict.Add(new HealthInit(health)); } if (facing != 0) { initDict.Add(new FacingInit(facing)); } if (section == "INFANTRY") { actor.Add(new SubCellInit(Exts.ParseIntegerInvariant(parts[4]))); } if (!rules.Actors.ContainsKey(parts[1].ToLowerInvariant())) { errorHandler("Ignoring unknown actor type: `{0}`".F(parts[1].ToLowerInvariant())); } else { map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, actor.Save())); } } catch (Exception) { errorHandler("Malformed actor definition: `{0}`".F(s)); } } }
public ResourceBarWidget(World world) { tooltipContainer = Exts.Lazy(() => Ui.Root.Get <TooltipContainerWidget>(TooltipContainer)); }
void LoadSmudges(IniFile file, string section) { foreach (var s in file.GetSection(section, true)) { // loc=type,loc,depth var parts = s.Value.Split(','); var loc = Exts.ParseIntegerInvariant(parts[1]); var key = "{0} {1},{2} {3}".F(parts[0].ToLowerInvariant(), loc % mapSize, loc / mapSize, Exts.ParseIntegerInvariant(parts[2])); map.SmudgeDefinitions.Add(new MiniYamlNode(key, "")); } }
public DefaultSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info) { this.sequence = sequence; Name = animation; Loader = loader; var d = info.ToDictionary(); try { Start = LoadField(d, "Start", 0); ShadowStart = LoadField(d, "ShadowStart", -1); ShadowZOffset = LoadField(d, "ShadowZOffset", DefaultShadowSpriteZOffset).Length; ZOffset = LoadField(d, "ZOffset", WDist.Zero).Length; ZRamp = LoadField(d, "ZRamp", 0); Tick = LoadField(d, "Tick", 40); transpose = LoadField(d, "Transpose", false); Frames = LoadField <int[]>(d, "Frames", null); IgnoreWorldTint = LoadField(d, "IgnoreWorldTint", false); var flipX = LoadField(d, "FlipX", false); var flipY = LoadField(d, "FlipY", false); Facings = LoadField(d, "Facings", 1); if (Facings < 0) { reverseFacings = true; Facings = -Facings; } var offset = LoadField(d, "Offset", float3.Zero); var blendMode = LoadField(d, "BlendMode", BlendMode.Alpha); Func <int, IEnumerable <int> > getUsedFrames = frameCount => { if (d.TryGetValue("Length", out var length) && length.Value == "*") { Length = Frames != null ? Frames.Length : frameCount - Start; } else { Length = LoadField(d, "Length", 1); } // Plays the animation forwards, and then in reverse if (LoadField(d, "Reverses", false)) { var frames = Frames != null?Frames.Skip(Start).Take(Length).ToArray() : Exts.MakeArray(Length, i => Start + i); Frames = frames.Concat(frames.Skip(1).Take(Length - 2).Reverse()).ToArray(); Length = 2 * Length - 2; Start = 0; } Stride = LoadField(d, "Stride", Length); if (Length > Stride) { throw new YamlException("Sequence {0}.{1}: Length must be <= stride" .F(sequence, animation)); } if (Frames != null && Length > Frames.Length) { throw new YamlException("Sequence {0}.{1}: Length must be <= Frames.Length" .F(sequence, animation)); } var end = Start + (Facings - 1) * Stride + Length - 1; if (Frames != null) { foreach (var f in Frames) { if (f < 0 || f >= frameCount) { throw new YamlException("Sequence {0}.{1} defines a Frames override that references frame {2}, but only [{3}..{4}] actually exist" .F(sequence, animation, f, Start, end)); } } if (Start < 0 || end >= Frames.Length) { throw new YamlException("Sequence {0}.{1} uses indices [{2}..{3}] of the Frames list, but only {4} frames are defined" .F(sequence, animation, Start, end, Frames.Length)); } } else if (Start < 0 || end >= frameCount) { throw new YamlException("Sequence {0}.{1} uses frames [{2}..{3}], but only [0..{4}] actually exist" .F(sequence, animation, Start, end, frameCount - 1)); } if (ShadowStart >= 0 && ShadowStart + (Facings - 1) * Stride + Length > frameCount) { throw new YamlException("Sequence {0}.{1}'s shadow frames use frames [{2}..{3}], but only [0..{4}] actually exist" .F(sequence, animation, ShadowStart, ShadowStart + (Facings - 1) * Stride + Length - 1, frameCount - 1)); } var usedFrames = new List <int>(); for (var facing = 0; facing < Facings; facing++) { for (var frame = 0; frame < Length; frame++) { var i = transpose ? (frame % Length) * Facings + facing : (facing * Stride) + (frame % Length); usedFrames.Add(Frames != null ? Frames[i] : Start + i); } } if (ShadowStart >= 0) { return(usedFrames.Concat(usedFrames.Select(i => i + ShadowStart - Start))); } return(usedFrames); }; if (d.TryGetValue("Combine", out var combine)) { var combined = Enumerable.Empty <Sprite>(); foreach (var sub in combine.Nodes) { var sd = sub.Value.ToDictionary(); // Allow per-sprite offset, flipping, start, and length var subStart = LoadField(sd, "Start", 0); var subOffset = LoadField(sd, "Offset", float3.Zero); var subFlipX = LoadField(sd, "FlipX", false); var subFlipY = LoadField(sd, "FlipY", false); var subFrames = LoadField <int[]>(sd, "Frames", null); var subLength = 0; Func <int, IEnumerable <int> > subGetUsedFrames = subFrameCount => { if (sd.TryGetValue("Length", out var subLengthYaml) && subLengthYaml.Value == "*") { subLength = subFrames != null ? subFrames.Length : subFrameCount - subStart; } else { subLength = LoadField(sd, "Length", 1); } return(subFrames != null?subFrames.Skip(subStart).Take(subLength) : Enumerable.Range(subStart, subLength)); }; var subSrc = GetSpriteSrc(modData, tileSet, sequence, animation, sub.Key, sd); var subSprites = cache[subSrc, subGetUsedFrames].Select( s => s != null ? new Sprite(s.Sheet, FlipRectangle(s.Bounds, subFlipX, subFlipY), ZRamp, new float3(subFlipX ? -s.Offset.X : s.Offset.X, subFlipY ? -s.Offset.Y : s.Offset.Y, s.Offset.Z) + subOffset + offset, s.Channel, blendMode) : null).ToList(); var frames = subFrames != null?subFrames.Skip(subStart).Take(subLength).ToArray() : Exts.MakeArray(subLength, i => subStart + i); combined = combined.Concat(frames.Select(i => subSprites[i])); } sprites = combined.ToArray(); getUsedFrames(sprites.Length); } else { // Apply offset to each sprite in the sequence // Different sequences may apply different offsets to the same frame var src = GetSpriteSrc(modData, tileSet, sequence, animation, info.Value, d); sprites = cache[src, getUsedFrames].Select( s => s != null ? new Sprite(s.Sheet, FlipRectangle(s.Bounds, flipX, flipY), ZRamp, new float3(flipX ? -s.Offset.X : s.Offset.X, flipY ? -s.Offset.Y : s.Offset.Y, s.Offset.Z) + offset, s.Channel, blendMode) : null).ToArray(); } var depthSprite = LoadField <string>(d, "DepthSprite", null); if (!string.IsNullOrEmpty(depthSprite)) { var depthSpriteFrame = LoadField(d, "DepthSpriteFrame", 0); var depthOffset = LoadField(d, "DepthSpriteOffset", float2.Zero); Func <int, IEnumerable <int> > getDepthFrame = _ => new int[] { depthSpriteFrame }; var ds = cache[depthSprite, getDepthFrame][depthSpriteFrame]; sprites = sprites.Select(s => { if (s == null) { return(null); } var cw = (ds.Bounds.Left + ds.Bounds.Right) / 2 + (int)(s.Offset.X + depthOffset.X); var ch = (ds.Bounds.Top + ds.Bounds.Bottom) / 2 + (int)(s.Offset.Y + depthOffset.Y); var w = s.Bounds.Width / 2; var h = s.Bounds.Height / 2; var r = Rectangle.FromLTRB(cw - w, ch - h, cw + w, ch + h); return(new SpriteWithSecondaryData(s, ds.Sheet, r, ds.Channel)); }).ToArray(); } var exportPalette = LoadField <string>(d, "EmbeddedPalette", null); if (exportPalette != null) { var src = GetSpriteSrc(modData, tileSet, sequence, animation, info.Value, d); var metadata = cache.FrameMetadata(src); var i = Frames != null ? Frames[0] : Start; var palettes = metadata != null?metadata.GetOrDefault <EmbeddedSpritePalette>() : null; if (palettes == null || !palettes.TryGetPaletteForFrame(i, out EmbeddedPalette)) { throw new YamlException("Cannot export palettes from {0}: frame {1} does not define an embedded palette".F(src, i)); } } var boundSprites = SpriteBounds(sprites, Frames, Start, Facings, Length, Stride, transpose); if (ShadowStart > 0) { boundSprites = boundSprites.Concat(SpriteBounds(sprites, Frames, ShadowStart, Facings, Length, Stride, transpose)); } Bounds = boundSprites.Union(); } catch (FormatException f) { throw new FormatException("Failed to parse sequences for {0}.{1} at {2}:\n{3}".F(sequence, animation, info.Nodes[0].Location, f)); } }
public SequenceProvider(SequenceCache cache, Map map) { this.sequences = Exts.Lazy(() => cache.LoadSequences(map)); this.SpriteCache = cache.SpriteCache; }