diff --git a/INSTALL b/INSTALL index a59def98d5..109dfc1cac 100644 --- a/INSTALL +++ b/INSTALL @@ -1,103 +1,103 @@ -Copyright 2007-2010 The OpenRA Developers (see AUTHORS) -This file is part of OpenRA, which is free software. It is made -available to you under the terms of the GNU General Public License -as published by the Free Software Foundation. For more information, -see LICENSE. - -To run OpenRA, several files are needed from the original game disks. - -The required files for the Red Alert mod are: -EITHER: - * conquer.mix - * temperat.mix - * interior.mix - * snow.mix - * sounds.mix - * allies.mix - * russian.mix -OR: - * main.mix -AND: - * redalert.mix - -These need to be copied into the mods/ra/packages/ directory. - - -The required files for the Command and Conquer mod are: - * cclocal.mix - * speech.mix - * conquer.mix - * sounds.mix - * tempicnh.mix - * temperat.mix - * winter.mix - * desert.mix - -These need to be copied into the mods/cnc/packages/ directory. -If you have a case-sensitive filesystem you must change the filenames to -lower case. - -The files can be downloaded from: -http://open-ra.org/get-dependency.php?file=ra-packages for the Red Alert files and -http://open-ra.org/get-dependency.php?file=cnc-packages for the Command & Conquer files. - -Alternatively: -Red Alert and C&C have been released by EA Games as freeware. They can be -downloaded from http://www.commandandconquer.com/classic -Unfortunately the installer is 16-bit and so won’t run on 64-bit operating -systems. This can be worked around by using the Red Alert Setup Manager - (http://ra.afraid.org/html/downloads/utilities-3.html). -Make sure you apply the no-CD protection fix so all the files needed -are installed to the hard drive. - -Dependencies - Make sure you have these installed, or you'll -have very strange errors. - - -WINDOWS: - -* .NET Framework >= 3.5-SP1 - (http://www.microsoft.com/downloads/details.aspx?FamilyID=AB99342F-5D1A-413D-8319-81DA479AB0D7&displaylang=en) -* Tao Framework >= 2.1.0 - This is now bundled with OpenRA, copy the files in thirdparty/Tao to the game root directory. -* OpenAL >= 1.1 - (http://connect.creativelabs.com/openal/Downloads/oalinst.zip) -* Cg Toolkit >= 2.2 - (http://developer.download.nvidia.com/cg/Cg_2.2/Cg-2.2_October2009_Setup.exe) - -To compile OpenRA, open the OpenRA.sln solution in the main folder, -or build it from the command-line with MSBuild. - -Run the game with `OpenRA.Game.exe Game.Mods=ra` for Red Alert -or `OpenRA.Game.exe Game.Mods=cnc` for Command & Conquer - - -UBUNTU (substitute comparable packages for other linux distros): - -* mono-gmcs -* freetype -* libmono-corlib1.0-cil -* libmono-winforms2.0-cil -* libopenal1 -* libsdl1.2-dev -* nvidia-cg-toolkit (download the latest version from - http://developer.nvidia.com/object/cg_download.html) - -OpenRA is incompatible with Compiz, please disable desktop effects when trying -to run OpenRA or the game will crash. - -You will need to copy the third party dependencies (.dll and .config) from the -thirdparty and thirdparty/Tao directories into the game root, or install them permanently into -your GAC with the following script - -#!/bin/sh -gacutil -i thirdparty/Tao/Tao.Cg.dll -gacutil -i thirdparty/Tao/Tao.OpenGl.dll -gacutil -i thirdparty/Tao/Tao.OpenAl.dll -gacutil -i thirdparty/Tao/Tao.Sdl.dll -gacutil -i thirdparty/Tao/Tao.FreeType.dll -gacutil -i thirdparty/ICSharpCode.SharpZipLib.dll - -To compile OpenRA, run `make' from the command line. -Run the game with `mono OpenRA.Game.exe Game.Mods=ra` for Red Alert -or `mono OpenRA.Game.exe Game.Mods=cnc` for Command & Conquer +Copyright 2007-2011 The OpenRA Developers (see AUTHORS) +This file is part of OpenRA, which is free software. It is made +available to you under the terms of the GNU General Public License +as published by the Free Software Foundation. For more information, +see COPYING. + +To run OpenRA, several files are needed from the original game disks. + +The required files for the Red Alert mod are: +EITHER: + * conquer.mix + * temperat.mix + * interior.mix + * snow.mix + * sounds.mix + * allies.mix + * russian.mix +OR: + * main.mix +AND: + * redalert.mix + +These need to be copied into the mods/ra/packages/ directory. + + +The required files for the Command and Conquer mod are: + * cclocal.mix + * speech.mix + * conquer.mix + * sounds.mix + * tempicnh.mix + * temperat.mix + * winter.mix + * desert.mix + +These need to be copied into the mods/cnc/packages/ directory. +If you have a case-sensitive filesystem you must change the filenames to +lower case. + +The files can be downloaded from: +http://open-ra.org/get-dependency.php?file=ra-packages for the Red Alert files and +http://open-ra.org/get-dependency.php?file=cnc-packages for the Command & Conquer files. + +Alternatively: +Red Alert and C&C have been released by EA Games as freeware. They can be +downloaded from http://www.commandandconquer.com/classic +Unfortunately the installer is 16-bit and so won’t run on 64-bit operating +systems. This can be worked around by using the Red Alert Setup Manager + (http://ra.afraid.org/html/downloads/utilities-3.html). +Make sure you apply the no-CD protection fix so all the files needed +are installed to the hard drive. + +Dependencies - Make sure you have these installed, or you'll +have very strange errors. + + +WINDOWS: + +* .NET Framework >= 3.5-SP1 + (http://www.microsoft.com/downloads/details.aspx?FamilyID=AB99342F-5D1A-413D-8319-81DA479AB0D7&displaylang=en) +* Tao Framework >= 2.1.0 + This is now bundled with OpenRA, copy the files in thirdparty/Tao to the game root directory. +* OpenAL >= 1.1 + (http://connect.creativelabs.com/openal/Downloads/oalinst.zip) +* Cg Toolkit >= 2.2 + (http://developer.download.nvidia.com/cg/Cg_2.2/Cg-2.2_October2009_Setup.exe) + +To compile OpenRA, open the OpenRA.sln solution in the main folder, +or build it from the command-line with MSBuild. + +Run the game with `OpenRA.Game.exe Game.Mods=ra` for Red Alert +or `OpenRA.Game.exe Game.Mods=cnc` for Command & Conquer + + +UBUNTU (substitute comparable packages for other linux distros): + +* mono-gmcs +* freetype +* libmono-corlib1.0-cil +* libmono-winforms2.0-cil +* libopenal1 +* libsdl1.2-dev +* nvidia-cg-toolkit (download the latest version from + http://developer.nvidia.com/object/cg_download.html) + +OpenRA is incompatible with Compiz, please disable desktop effects when trying +to run OpenRA or the game will crash. + +You will need to copy the third party dependencies (.dll and .config) from the +thirdparty and thirdparty/Tao directories into the game root, or install them permanently into +your GAC with the following script + +#!/bin/sh +gacutil -i thirdparty/Tao/Tao.Cg.dll +gacutil -i thirdparty/Tao/Tao.OpenGl.dll +gacutil -i thirdparty/Tao/Tao.OpenAl.dll +gacutil -i thirdparty/Tao/Tao.Sdl.dll +gacutil -i thirdparty/Tao/Tao.FreeType.dll +gacutil -i thirdparty/ICSharpCode.SharpZipLib.dll + +To compile OpenRA, run `make' from the command line. +Run the game with `mono OpenRA.Game.exe Game.Mods=ra` for Red Alert +or `mono OpenRA.Game.exe Game.Mods=cnc` for Command & Conquer diff --git a/OpenRA.Editor/ActorTemplate.cs b/OpenRA.Editor/ActorTemplate.cs index 5ad09e4d8c..d988a23cfd 100644 --- a/OpenRA.Editor/ActorTemplate.cs +++ b/OpenRA.Editor/ActorTemplate.cs @@ -1,36 +1,36 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.GameRules; -using OpenRA.Traits; - -namespace OpenRA.Editor -{ - class ActorTemplate - { - public Bitmap Bitmap; - public ActorInfo Info; - public EditorAppearanceInfo Appearance; - } - - class BrushTemplate - { - public Bitmap Bitmap; - public ushort N; - } - - class ResourceTemplate - { - public Bitmap Bitmap; - public ResourceTypeInfo Info; - public int Value; - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Editor +{ + class ActorTemplate + { + public Bitmap Bitmap; + public ActorInfo Info; + public EditorAppearanceInfo Appearance; + } + + class BrushTemplate + { + public Bitmap Bitmap; + public ushort N; + } + + class ResourceTemplate + { + public Bitmap Bitmap; + public ResourceTypeInfo Info; + public int Value; + } +} diff --git a/OpenRA.Editor/ActorTool.cs b/OpenRA.Editor/ActorTool.cs index 5c17b2ff78..854dfcf7a7 100644 --- a/OpenRA.Editor/ActorTool.cs +++ b/OpenRA.Editor/ActorTool.cs @@ -1,55 +1,55 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.FileFormats; - -using SGraphics = System.Drawing.Graphics; - -namespace OpenRA.Editor -{ - class ActorTool : ITool - { - ActorTemplate Actor; - public ActorTool(ActorTemplate actor) { this.Actor = actor; } - - public void Preview(Surface surface, SGraphics g) - { - /* todo: include the player - * in the brush so we can color new buildings too */ - - surface.DrawActor(g, surface.GetBrushLocation(), Actor, null); - } - - public void Apply(Surface surface) - { - if (surface.Map.Actors.Value.Any(a => a.Value.Location() == surface.GetBrushLocation())) - return; - - var owner = "Neutral"; - var id = NextActorName(surface); - surface.Map.Actors.Value[id] = new ActorReference(Actor.Info.Name.ToLowerInvariant()) - { - new LocationInit( surface.GetBrushLocation() ), - new OwnerInit( owner) - }; - } - - string NextActorName(Surface surface) - { - var id = 0; - for (; ; ) - { - var possible = "Actor{0}".F(id++); - if (!surface.Map.Actors.Value.ContainsKey(possible)) return possible; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.FileFormats; + +using SGraphics = System.Drawing.Graphics; + +namespace OpenRA.Editor +{ + class ActorTool : ITool + { + ActorTemplate Actor; + public ActorTool(ActorTemplate actor) { this.Actor = actor; } + + public void Preview(Surface surface, SGraphics g) + { + /* todo: include the player + * in the brush so we can color new buildings too */ + + surface.DrawActor(g, surface.GetBrushLocation(), Actor, null); + } + + public void Apply(Surface surface) + { + if (surface.Map.Actors.Value.Any(a => a.Value.Location() == surface.GetBrushLocation())) + return; + + var owner = "Neutral"; + var id = NextActorName(surface); + surface.Map.Actors.Value[id] = new ActorReference(Actor.Info.Name.ToLowerInvariant()) + { + new LocationInit( surface.GetBrushLocation() ), + new OwnerInit( owner) + }; + } + + string NextActorName(Surface surface) + { + var id = 0; + for (; ; ) + { + var possible = "Actor{0}".F(id++); + if (!surface.Map.Actors.Value.ContainsKey(possible)) return possible; + } + } + } +} diff --git a/OpenRA.Editor/BrushTool.cs b/OpenRA.Editor/BrushTool.cs index f5b0dcc3b1..a9702b0cd3 100644 --- a/OpenRA.Editor/BrushTool.cs +++ b/OpenRA.Editor/BrushTool.cs @@ -1,123 +1,123 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Windows.Forms; -using OpenRA.FileFormats; - -using SGraphics = System.Drawing.Graphics; - -namespace OpenRA.Editor -{ - class BrushTool : ITool - { - BrushTemplate Brush; - - public BrushTool(BrushTemplate brush) { this.Brush = brush; } - - public void Apply(Surface surface) - { - // change the bits in the map - var tile = surface.TileSet.Tiles[Brush.N]; - var template = surface.TileSet.Templates[Brush.N]; - var pos = surface.GetBrushLocation(); - - if (surface.GetModifiers() == Keys.Shift) - { - FloodFillWithBrush(surface, pos); - return; - } - - for (var u = 0; u < template.Size.X; u++) - for (var v = 0; v < template.Size.Y; v++) - { - if (surface.Map.IsInMap(new int2(u, v) + pos)) - { - var z = u + v * template.Size.X; - if (tile.TileBitmapBytes[z] != null) - surface.Map.MapTiles.Value[u + pos.X, v + pos.Y] = - new TileReference - { - type = Brush.N, - index = template.PickAny ? (byte)((u + pos.X) % 4 + ((v + pos.Y) % 4) * 4) : (byte)z, - }; - - var ch = new int2((pos.X + u) / Surface.ChunkSize, (pos.Y + v) / Surface.ChunkSize); - if (surface.Chunks.ContainsKey(ch)) - { - surface.Chunks[ch].Dispose(); - surface.Chunks.Remove(ch); - } - } - } - } - - public void Preview(Surface surface, SGraphics g) - { - g.DrawImage(Brush.Bitmap, - surface.TileSet.TileSize * surface.GetBrushLocation().X * surface.Zoom + surface.GetOffset().X, - surface.TileSet.TileSize * surface.GetBrushLocation().Y * surface.Zoom + surface.GetOffset().Y, - Brush.Bitmap.Width * surface.Zoom, - Brush.Bitmap.Height * surface.Zoom); - } - - void FloodFillWithBrush(Surface s, int2 pos) - { - var queue = new Queue(); - var replace = s.Map.MapTiles.Value[pos.X, pos.Y]; - var touched = new bool[s.Map.MapSize.X, s.Map.MapSize.Y]; - - Action MaybeEnqueue = (x, y) => - { - if (s.Map.IsInMap(x, y) && !touched[x, y]) - { - queue.Enqueue(new int2(x, y)); - touched[x, y] = true; - } - }; - - queue.Enqueue(pos); - while (queue.Count > 0) - { - var p = queue.Dequeue(); - if (!s.Map.MapTiles.Value[p.X, p.Y].Equals(replace)) - continue; - - var a = FindEdge(s, p, new int2(-1, 0), replace); - var b = FindEdge(s, p, new int2(1, 0), replace); - - for (var x = a.X; x <= b.X; x++) - { - s.Map.MapTiles.Value[x, p.Y] = new TileReference { type = Brush.N, index = (byte)0 }; - if (s.Map.MapTiles.Value[x, p.Y - 1].Equals(replace)) - MaybeEnqueue(x, p.Y - 1); - if (s.Map.MapTiles.Value[x, p.Y + 1].Equals(replace)) - MaybeEnqueue(x, p.Y + 1); - } - } - - /* todo: optimize */ - foreach (var ch in s.Chunks.Values) ch.Dispose(); - s.Chunks.Clear(); - } - - int2 FindEdge(Surface s, int2 p, int2 d, TileReference replace) - { - for (; ; ) - { - var q = p + d; - if (!s.Map.IsInMap(q)) return p; - if (!s.Map.MapTiles.Value[q.X, q.Y].Equals(replace)) return p; - p = q; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using OpenRA.FileFormats; + +using SGraphics = System.Drawing.Graphics; + +namespace OpenRA.Editor +{ + class BrushTool : ITool + { + BrushTemplate Brush; + + public BrushTool(BrushTemplate brush) { this.Brush = brush; } + + public void Apply(Surface surface) + { + // change the bits in the map + var tile = surface.TileSet.Tiles[Brush.N]; + var template = surface.TileSet.Templates[Brush.N]; + var pos = surface.GetBrushLocation(); + + if (surface.GetModifiers() == Keys.Shift) + { + FloodFillWithBrush(surface, pos); + return; + } + + for (var u = 0; u < template.Size.X; u++) + for (var v = 0; v < template.Size.Y; v++) + { + if (surface.Map.IsInMap(new int2(u, v) + pos)) + { + var z = u + v * template.Size.X; + if (tile.TileBitmapBytes[z] != null) + surface.Map.MapTiles.Value[u + pos.X, v + pos.Y] = + new TileReference + { + type = Brush.N, + index = template.PickAny ? (byte)((u + pos.X) % 4 + ((v + pos.Y) % 4) * 4) : (byte)z, + }; + + var ch = new int2((pos.X + u) / Surface.ChunkSize, (pos.Y + v) / Surface.ChunkSize); + if (surface.Chunks.ContainsKey(ch)) + { + surface.Chunks[ch].Dispose(); + surface.Chunks.Remove(ch); + } + } + } + } + + public void Preview(Surface surface, SGraphics g) + { + g.DrawImage(Brush.Bitmap, + surface.TileSet.TileSize * surface.GetBrushLocation().X * surface.Zoom + surface.GetOffset().X, + surface.TileSet.TileSize * surface.GetBrushLocation().Y * surface.Zoom + surface.GetOffset().Y, + Brush.Bitmap.Width * surface.Zoom, + Brush.Bitmap.Height * surface.Zoom); + } + + void FloodFillWithBrush(Surface s, int2 pos) + { + var queue = new Queue(); + var replace = s.Map.MapTiles.Value[pos.X, pos.Y]; + var touched = new bool[s.Map.MapSize.X, s.Map.MapSize.Y]; + + Action MaybeEnqueue = (x, y) => + { + if (s.Map.IsInMap(x, y) && !touched[x, y]) + { + queue.Enqueue(new int2(x, y)); + touched[x, y] = true; + } + }; + + queue.Enqueue(pos); + while (queue.Count > 0) + { + var p = queue.Dequeue(); + if (!s.Map.MapTiles.Value[p.X, p.Y].Equals(replace)) + continue; + + var a = FindEdge(s, p, new int2(-1, 0), replace); + var b = FindEdge(s, p, new int2(1, 0), replace); + + for (var x = a.X; x <= b.X; x++) + { + s.Map.MapTiles.Value[x, p.Y] = new TileReference { type = Brush.N, index = (byte)0 }; + if (s.Map.MapTiles.Value[x, p.Y - 1].Equals(replace)) + MaybeEnqueue(x, p.Y - 1); + if (s.Map.MapTiles.Value[x, p.Y + 1].Equals(replace)) + MaybeEnqueue(x, p.Y + 1); + } + } + + /* todo: optimize */ + foreach (var ch in s.Chunks.Values) ch.Dispose(); + s.Chunks.Clear(); + } + + int2 FindEdge(Surface s, int2 p, int2 d, TileReference replace) + { + for (; ; ) + { + var q = p + d; + if (!s.Map.IsInMap(q)) return p; + if (!s.Map.MapTiles.Value[q.X, q.Y].Equals(replace)) return p; + p = q; + } + } + } +} diff --git a/OpenRA.Editor/Form1.cs b/OpenRA.Editor/Form1.cs index f2646b0c06..82cf732c60 100755 --- a/OpenRA.Editor/Form1.cs +++ b/OpenRA.Editor/Form1.cs @@ -1,415 +1,415 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Windows.Forms; -using OpenRA.FileFormats; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Editor -{ - public partial class Form1 : Form - { - public Form1(string[] mods) - { - InitializeComponent(); - AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly; - - currentMod = mods.FirstOrDefault() ?? "ra"; - - toolStripComboBox1.Items.AddRange(Mod.AllMods.Keys.ToArray()); - - toolStripComboBox1.SelectedIndexChanged += (_, e) => - { - tilePalette.SuspendLayout(); - actorPalette.SuspendLayout(); - resourcePalette.SuspendLayout(); - tilePalette.Controls.Clear(); - actorPalette.Controls.Clear(); - resourcePalette.Controls.Clear(); - tilePalette.ResumeLayout(); - actorPalette.ResumeLayout(); - resourcePalette.ResumeLayout(); - surface1.Bind(null, null, null); - pmMiniMap.Image = null; - currentMod = toolStripComboBox1.SelectedItem as string; - - Text = "OpenRA Editor (mod:{0})".F(currentMod); - Game.modData = new ModData(currentMod); - FileSystem.LoadFromManifest(Game.modData.Manifest); - Rules.LoadRules(Game.modData.Manifest, new Map()); - loadedMapName = null; - }; - - toolStripComboBox1.SelectedItem = currentMod; - - surface1.AfterChange += OnMapChanged; - surface1.MousePositionChanged += s => toolStripStatusLabelMousePosition.Text = s; - } - - void OnMapChanged() - { - MakeDirty(); - pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true)); - } - - void MakeDirty() { dirty = true; } - string loadedMapName; - string currentMod = "ra"; - TileSet tileset; - bool dirty = false; - - void LoadMap(string mapname) - { - tilePalette.Controls.Clear(); - actorPalette.Controls.Clear(); - resourcePalette.Controls.Clear(); - - loadedMapName = mapname; - - // load the map - var map = new Map(mapname); - - // upgrade maps that have no player definitions. editor doesnt care, - // but this breaks the game pretty badly. - if (map.Players.Count == 0) - map.Players.Add("Neutral", new PlayerReference("Neutral", - Rules.Info["world"].Traits.WithInterface().First().Race, true, true)); - - PrepareMapResources(Game.modData.Manifest, map); - - dirty = false; - } - - void NewMap(Map map) - { - tilePalette.Controls.Clear(); - actorPalette.Controls.Clear(); - resourcePalette.Controls.Clear(); - - loadedMapName = null; - PrepareMapResources(Game.modData.Manifest, map); - - MakeDirty(); - } - - // this code is insanely stupid, and mostly my fault -- chrisf - void PrepareMapResources(Manifest manifest, Map map) - { - Rules.LoadRules(manifest, map); - tileset = Rules.TileSets[map.Tileset]; - tileset.LoadTiles(); - var palette = new Palette(FileSystem.Open(tileset.Palette), true); - - - surface1.Bind(map, tileset, palette); - // construct the palette of tiles - var palettes = new[] { tilePalette, actorPalette, resourcePalette }; - foreach (var p in palettes) { p.Visible = false; p.SuspendLayout(); } - foreach (var t in tileset.Templates) - { - try - { - var bitmap = RenderUtils.RenderTemplate(tileset, (ushort)t.Key, palette); - var ibox = new PictureBox - { - Image = bitmap, - Width = bitmap.Width / 2, - Height = bitmap.Height / 2, - SizeMode = PictureBoxSizeMode.StretchImage - }; - - var brushTemplate = new BrushTemplate { Bitmap = bitmap, N = t.Key }; - ibox.Click += (_, e) => surface1.SetTool(new BrushTool(brushTemplate)); - - var template = t.Value; - tilePalette.Controls.Add(ibox); - tt.SetToolTip(ibox, - "{1}:{0} ({2}x{3})".F( - template.Image, - template.Id, - template.Size.X, - template.Size.Y)); - } - catch { } - } - - var actorTemplates = new List(); - - foreach (var a in Rules.Info.Keys) - { - try - { - var info = Rules.Info[a]; - if (!info.Traits.Contains()) continue; - var template = RenderUtils.RenderActor(info, tileset, palette); - var ibox = new PictureBox - { - Image = template.Bitmap, - Width = 32, - Height = 32, - SizeMode = PictureBoxSizeMode.Zoom, - BorderStyle = BorderStyle.FixedSingle - }; - - - ibox.Click += (_, e) => surface1.SetTool(new ActorTool(template)); - - actorPalette.Controls.Add(ibox); - - tt.SetToolTip(ibox, - "{0}".F( - info.Name)); - - actorTemplates.Add(template); - } - catch { } - } - - surface1.BindActorTemplates(actorTemplates); - - var resourceTemplates = new List(); - - foreach (var a in Rules.Info["world"].Traits.WithInterface()) - { - try - { - var template = RenderUtils.RenderResourceType(a, tileset.Extensions, palette); - var ibox = new PictureBox - { - Image = template.Bitmap, - Width = 32, - Height = 32, - SizeMode = PictureBoxSizeMode.Zoom, - BorderStyle = BorderStyle.FixedSingle - }; - - - - ibox.Click += (_, e) => surface1.SetTool(new ResourceTool(template)); - - resourcePalette.Controls.Add(ibox); - - tt.SetToolTip(ibox, - "{0}:{1}cr".F( - template.Info.Name, - template.Info.ValuePerUnit)); - - resourceTemplates.Add(template); - } - catch { } - } - - surface1.BindResourceTemplates(resourceTemplates); - - foreach (var p in palettes) - { - p.Visible = true; - p.ResumeLayout(); - } - - pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true)); - - propertiesToolStripMenuItem.Enabled = true; - resizeToolStripMenuItem.Enabled = true; - spawnpointsToolStripMenuItem.Enabled = true; - saveToolStripMenuItem.Enabled = true; - saveAsToolStripMenuItem.Enabled = true; - mnuMinimapToPNG.Enabled = true; // todo: what is this VB naming bullshit doing here? - } - - void ResizeClicked(object sender, EventArgs e) - { - using (var rd = new ResizeDialog()) - { - rd.width.Value = surface1.Map.MapSize.X; - rd.height.Value = surface1.Map.MapSize.Y; - rd.cordonLeft.Value = surface1.Map.Bounds.Left; - rd.cordonTop.Value = surface1.Map.Bounds.Top; - rd.cordonRight.Value = surface1.Map.Bounds.Right; - rd.cordonBottom.Value = surface1.Map.Bounds.Bottom; - - if (DialogResult.OK != rd.ShowDialog()) - return; - - surface1.Map.ResizeCordon((int)rd.cordonLeft.Value, - (int)rd.cordonTop.Value, - (int)rd.cordonRight.Value, - (int)rd.cordonBottom.Value); - - if ((int)rd.width.Value != surface1.Map.MapSize.X || (int)rd.height.Value != surface1.Map.MapSize.Y) - { - surface1.Map.Resize((int)rd.width.Value, (int)rd.height.Value); - surface1.Bind(surface1.Map, surface1.TileSet, surface1.Palette); // rebind it to invalidate all caches - } - - surface1.Invalidate(); - } - } - - void SaveClicked(object sender, EventArgs e) - { - if (loadedMapName == null) - SaveAsClicked(sender, e); - else - { - surface1.Map.Save(loadedMapName); - dirty = false; - } - - } - - void SaveAsClicked(object sender, EventArgs e) - { - using (var nms = new MapSelect(currentMod)) - { - nms.txtNew.ReadOnly = false; - nms.btnOk.Text = "Save"; - nms.txtNew.Text = "unnamed"; - nms.txtPathOut.ReadOnly = false; - - if (DialogResult.OK == nms.ShowDialog()) - { - if (nms.txtNew.Text == "") - nms.txtNew.Text = "unnamed"; - - // TODO: Allow the user to choose map format (directory vs oramap) - loadedMapName = Path.Combine(nms.MapFolderPath, nms.txtNew.Text + ".oramap"); - SaveClicked(sender, e); - } - } - } - - void OpenClicked(object sender, EventArgs e) - { - using (var nms = new MapSelect(currentMod)) - { - nms.txtNew.ReadOnly = true; - nms.txtPathOut.ReadOnly = true; - nms.btnOk.Text = "Open"; - - if (DialogResult.OK == nms.ShowDialog()) - LoadMap(nms.txtNew.Tag as string); - } - } - - void NewClicked(object sender, EventArgs e) - { - using (var nmd = new NewMapDialog()) - { - nmd.theater.Items.Clear(); - nmd.theater.Items.AddRange(Rules.TileSets.Select(a => a.Value.Id).ToArray()); - nmd.theater.SelectedIndex = 0; - - if (DialogResult.OK == nmd.ShowDialog()) - { - var map = Map.FromTileset(nmd.theater.SelectedItem as string); - - map.Resize((int)nmd.width.Value, (int)nmd.height.Value); - map.ResizeCordon((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value, - (int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value); - map.Players.Add("Neutral", new PlayerReference("Neutral", Rules.Info["world"].Traits.WithInterface().First().Race, true, true)); - map.Players.Add("Creeps", new PlayerReference("Creeps", Rules.Info["world"].Traits.WithInterface().First().Race, true, true)); - NewMap(map); - } - } - } - - void PropertiesClicked(object sender, EventArgs e) - { - using (var pd = new PropertiesDialog()) - { - pd.title.Text = surface1.Map.Title; - pd.desc.Text = surface1.Map.Description; - pd.author.Text = surface1.Map.Author; - pd.selectable.Checked = surface1.Map.Selectable; - pd.useAsShellmap.Checked = surface1.Map.UseAsShellmap; - - if (DialogResult.OK != pd.ShowDialog()) - return; - - surface1.Map.Title = pd.title.Text; - surface1.Map.Description = pd.desc.Text; - surface1.Map.Author = pd.author.Text; - surface1.Map.Selectable = pd.selectable.Checked; - surface1.Map.UseAsShellmap = pd.useAsShellmap.Checked; - } - } - - void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = true; } - void Form1_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = false; } - - void CloseClicked(object sender, EventArgs e) - { - Close(); - } - - void ImportLegacyMapClicked(object sender, EventArgs e) - { - var currentDirectory = Directory.GetCurrentDirectory(); - using (var ofd = new OpenFileDialog { Filter = "Legacy maps (*.ini;*.mpr)|*.ini;*.mpr" }) - if (DialogResult.OK == ofd.ShowDialog()) - { - Directory.SetCurrentDirectory(currentDirectory); - /* massive hack: we should be able to call NewMap() with the imported Map object, - * but something's not right internally in it, unless loaded via the real maploader */ - - var savePath = Path.Combine(Path.GetTempPath(), "OpenRA.Import"); - Directory.CreateDirectory(savePath); - - var map = LegacyMapImporter.Import(ofd.FileName); - map.Players.Add("Neutral", new PlayerReference("Neutral", - Rules.Info["world"].Traits.WithInterface().First().Race, true, true)); - - map.Players.Add("Creeps", new PlayerReference("Creeps", - Rules.Info["world"].Traits.WithInterface().First().Race, true, true)); - - map.Save(savePath); - LoadMap(savePath); - loadedMapName = null; /* editor needs to think this hasnt been saved */ - - Directory.Delete(savePath, true); - MakeDirty(); - } - } - - void OnFormClosing(object sender, FormClosingEventArgs e) - { - if (!dirty) return; - - switch (MessageBox.Show("The map has been modified since it was last saved. " + "\r\n" + "Save changes now?", - "Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation)) - { - case DialogResult.Yes: SaveClicked(null, EventArgs.Empty); break; - case DialogResult.No: break; - case DialogResult.Cancel: e.Cancel = true; break; - } - } - - private void layersFloaterToolStripMenuItem_Click(object sender, EventArgs e) - { - var pb = new PaletteBox(); - pb.Show(); - } - - void ExportMinimap(object sender, EventArgs e) - { - saveFileDialog.InitialDirectory = Path.Combine(Environment.CurrentDirectory, "maps"); - saveFileDialog.FileName = Path.ChangeExtension(loadedMapName, ".png"); - - if (DialogResult.OK == saveFileDialog.ShowDialog()) - pmMiniMap.Image.Save(saveFileDialog.FileName); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Editor +{ + public partial class Form1 : Form + { + public Form1(string[] mods) + { + InitializeComponent(); + AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly; + + currentMod = mods.FirstOrDefault() ?? "ra"; + + toolStripComboBox1.Items.AddRange(Mod.AllMods.Keys.ToArray()); + + toolStripComboBox1.SelectedIndexChanged += (_, e) => + { + tilePalette.SuspendLayout(); + actorPalette.SuspendLayout(); + resourcePalette.SuspendLayout(); + tilePalette.Controls.Clear(); + actorPalette.Controls.Clear(); + resourcePalette.Controls.Clear(); + tilePalette.ResumeLayout(); + actorPalette.ResumeLayout(); + resourcePalette.ResumeLayout(); + surface1.Bind(null, null, null); + pmMiniMap.Image = null; + currentMod = toolStripComboBox1.SelectedItem as string; + + Text = "OpenRA Editor (mod:{0})".F(currentMod); + Game.modData = new ModData(currentMod); + FileSystem.LoadFromManifest(Game.modData.Manifest); + Rules.LoadRules(Game.modData.Manifest, new Map()); + loadedMapName = null; + }; + + toolStripComboBox1.SelectedItem = currentMod; + + surface1.AfterChange += OnMapChanged; + surface1.MousePositionChanged += s => toolStripStatusLabelMousePosition.Text = s; + } + + void OnMapChanged() + { + MakeDirty(); + pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true)); + } + + void MakeDirty() { dirty = true; } + string loadedMapName; + string currentMod = "ra"; + TileSet tileset; + bool dirty = false; + + void LoadMap(string mapname) + { + tilePalette.Controls.Clear(); + actorPalette.Controls.Clear(); + resourcePalette.Controls.Clear(); + + loadedMapName = mapname; + + // load the map + var map = new Map(mapname); + + // upgrade maps that have no player definitions. editor doesnt care, + // but this breaks the game pretty badly. + if (map.Players.Count == 0) + map.Players.Add("Neutral", new PlayerReference("Neutral", + Rules.Info["world"].Traits.WithInterface().First().Race, true, true)); + + PrepareMapResources(Game.modData.Manifest, map); + + dirty = false; + } + + void NewMap(Map map) + { + tilePalette.Controls.Clear(); + actorPalette.Controls.Clear(); + resourcePalette.Controls.Clear(); + + loadedMapName = null; + PrepareMapResources(Game.modData.Manifest, map); + + MakeDirty(); + } + + // this code is insanely stupid, and mostly my fault -- chrisf + void PrepareMapResources(Manifest manifest, Map map) + { + Rules.LoadRules(manifest, map); + tileset = Rules.TileSets[map.Tileset]; + tileset.LoadTiles(); + var palette = new Palette(FileSystem.Open(tileset.Palette), true); + + + surface1.Bind(map, tileset, palette); + // construct the palette of tiles + var palettes = new[] { tilePalette, actorPalette, resourcePalette }; + foreach (var p in palettes) { p.Visible = false; p.SuspendLayout(); } + foreach (var t in tileset.Templates) + { + try + { + var bitmap = RenderUtils.RenderTemplate(tileset, (ushort)t.Key, palette); + var ibox = new PictureBox + { + Image = bitmap, + Width = bitmap.Width / 2, + Height = bitmap.Height / 2, + SizeMode = PictureBoxSizeMode.StretchImage + }; + + var brushTemplate = new BrushTemplate { Bitmap = bitmap, N = t.Key }; + ibox.Click += (_, e) => surface1.SetTool(new BrushTool(brushTemplate)); + + var template = t.Value; + tilePalette.Controls.Add(ibox); + tt.SetToolTip(ibox, + "{1}:{0} ({2}x{3})".F( + template.Image, + template.Id, + template.Size.X, + template.Size.Y)); + } + catch { } + } + + var actorTemplates = new List(); + + foreach (var a in Rules.Info.Keys) + { + try + { + var info = Rules.Info[a]; + if (!info.Traits.Contains()) continue; + var template = RenderUtils.RenderActor(info, tileset, palette); + var ibox = new PictureBox + { + Image = template.Bitmap, + Width = 32, + Height = 32, + SizeMode = PictureBoxSizeMode.Zoom, + BorderStyle = BorderStyle.FixedSingle + }; + + + ibox.Click += (_, e) => surface1.SetTool(new ActorTool(template)); + + actorPalette.Controls.Add(ibox); + + tt.SetToolTip(ibox, + "{0}".F( + info.Name)); + + actorTemplates.Add(template); + } + catch { } + } + + surface1.BindActorTemplates(actorTemplates); + + var resourceTemplates = new List(); + + foreach (var a in Rules.Info["world"].Traits.WithInterface()) + { + try + { + var template = RenderUtils.RenderResourceType(a, tileset.Extensions, palette); + var ibox = new PictureBox + { + Image = template.Bitmap, + Width = 32, + Height = 32, + SizeMode = PictureBoxSizeMode.Zoom, + BorderStyle = BorderStyle.FixedSingle + }; + + + + ibox.Click += (_, e) => surface1.SetTool(new ResourceTool(template)); + + resourcePalette.Controls.Add(ibox); + + tt.SetToolTip(ibox, + "{0}:{1}cr".F( + template.Info.Name, + template.Info.ValuePerUnit)); + + resourceTemplates.Add(template); + } + catch { } + } + + surface1.BindResourceTemplates(resourceTemplates); + + foreach (var p in palettes) + { + p.Visible = true; + p.ResumeLayout(); + } + + pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true)); + + propertiesToolStripMenuItem.Enabled = true; + resizeToolStripMenuItem.Enabled = true; + spawnpointsToolStripMenuItem.Enabled = true; + saveToolStripMenuItem.Enabled = true; + saveAsToolStripMenuItem.Enabled = true; + mnuMinimapToPNG.Enabled = true; // todo: what is this VB naming bullshit doing here? + } + + void ResizeClicked(object sender, EventArgs e) + { + using (var rd = new ResizeDialog()) + { + rd.width.Value = surface1.Map.MapSize.X; + rd.height.Value = surface1.Map.MapSize.Y; + rd.cordonLeft.Value = surface1.Map.Bounds.Left; + rd.cordonTop.Value = surface1.Map.Bounds.Top; + rd.cordonRight.Value = surface1.Map.Bounds.Right; + rd.cordonBottom.Value = surface1.Map.Bounds.Bottom; + + if (DialogResult.OK != rd.ShowDialog()) + return; + + surface1.Map.ResizeCordon((int)rd.cordonLeft.Value, + (int)rd.cordonTop.Value, + (int)rd.cordonRight.Value, + (int)rd.cordonBottom.Value); + + if ((int)rd.width.Value != surface1.Map.MapSize.X || (int)rd.height.Value != surface1.Map.MapSize.Y) + { + surface1.Map.Resize((int)rd.width.Value, (int)rd.height.Value); + surface1.Bind(surface1.Map, surface1.TileSet, surface1.Palette); // rebind it to invalidate all caches + } + + surface1.Invalidate(); + } + } + + void SaveClicked(object sender, EventArgs e) + { + if (loadedMapName == null) + SaveAsClicked(sender, e); + else + { + surface1.Map.Save(loadedMapName); + dirty = false; + } + + } + + void SaveAsClicked(object sender, EventArgs e) + { + using (var nms = new MapSelect(currentMod)) + { + nms.txtNew.ReadOnly = false; + nms.btnOk.Text = "Save"; + nms.txtNew.Text = "unnamed"; + nms.txtPathOut.ReadOnly = false; + + if (DialogResult.OK == nms.ShowDialog()) + { + if (nms.txtNew.Text == "") + nms.txtNew.Text = "unnamed"; + + // TODO: Allow the user to choose map format (directory vs oramap) + loadedMapName = Path.Combine(nms.MapFolderPath, nms.txtNew.Text + ".oramap"); + SaveClicked(sender, e); + } + } + } + + void OpenClicked(object sender, EventArgs e) + { + using (var nms = new MapSelect(currentMod)) + { + nms.txtNew.ReadOnly = true; + nms.txtPathOut.ReadOnly = true; + nms.btnOk.Text = "Open"; + + if (DialogResult.OK == nms.ShowDialog()) + LoadMap(nms.txtNew.Tag as string); + } + } + + void NewClicked(object sender, EventArgs e) + { + using (var nmd = new NewMapDialog()) + { + nmd.theater.Items.Clear(); + nmd.theater.Items.AddRange(Rules.TileSets.Select(a => a.Value.Id).ToArray()); + nmd.theater.SelectedIndex = 0; + + if (DialogResult.OK == nmd.ShowDialog()) + { + var map = Map.FromTileset(nmd.theater.SelectedItem as string); + + map.Resize((int)nmd.width.Value, (int)nmd.height.Value); + map.ResizeCordon((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value, + (int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value); + map.Players.Add("Neutral", new PlayerReference("Neutral", Rules.Info["world"].Traits.WithInterface().First().Race, true, true)); + map.Players.Add("Creeps", new PlayerReference("Creeps", Rules.Info["world"].Traits.WithInterface().First().Race, true, true)); + NewMap(map); + } + } + } + + void PropertiesClicked(object sender, EventArgs e) + { + using (var pd = new PropertiesDialog()) + { + pd.title.Text = surface1.Map.Title; + pd.desc.Text = surface1.Map.Description; + pd.author.Text = surface1.Map.Author; + pd.selectable.Checked = surface1.Map.Selectable; + pd.useAsShellmap.Checked = surface1.Map.UseAsShellmap; + + if (DialogResult.OK != pd.ShowDialog()) + return; + + surface1.Map.Title = pd.title.Text; + surface1.Map.Description = pd.desc.Text; + surface1.Map.Author = pd.author.Text; + surface1.Map.Selectable = pd.selectable.Checked; + surface1.Map.UseAsShellmap = pd.useAsShellmap.Checked; + } + } + + void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = true; } + void Form1_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = false; } + + void CloseClicked(object sender, EventArgs e) + { + Close(); + } + + void ImportLegacyMapClicked(object sender, EventArgs e) + { + var currentDirectory = Directory.GetCurrentDirectory(); + using (var ofd = new OpenFileDialog { Filter = "Legacy maps (*.ini;*.mpr)|*.ini;*.mpr" }) + if (DialogResult.OK == ofd.ShowDialog()) + { + Directory.SetCurrentDirectory(currentDirectory); + /* massive hack: we should be able to call NewMap() with the imported Map object, + * but something's not right internally in it, unless loaded via the real maploader */ + + var savePath = Path.Combine(Path.GetTempPath(), "OpenRA.Import"); + Directory.CreateDirectory(savePath); + + var map = LegacyMapImporter.Import(ofd.FileName); + map.Players.Add("Neutral", new PlayerReference("Neutral", + Rules.Info["world"].Traits.WithInterface().First().Race, true, true)); + + map.Players.Add("Creeps", new PlayerReference("Creeps", + Rules.Info["world"].Traits.WithInterface().First().Race, true, true)); + + map.Save(savePath); + LoadMap(savePath); + loadedMapName = null; /* editor needs to think this hasnt been saved */ + + Directory.Delete(savePath, true); + MakeDirty(); + } + } + + void OnFormClosing(object sender, FormClosingEventArgs e) + { + if (!dirty) return; + + switch (MessageBox.Show("The map has been modified since it was last saved. " + "\r\n" + "Save changes now?", + "Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation)) + { + case DialogResult.Yes: SaveClicked(null, EventArgs.Empty); break; + case DialogResult.No: break; + case DialogResult.Cancel: e.Cancel = true; break; + } + } + + private void layersFloaterToolStripMenuItem_Click(object sender, EventArgs e) + { + var pb = new PaletteBox(); + pb.Show(); + } + + void ExportMinimap(object sender, EventArgs e) + { + saveFileDialog.InitialDirectory = Path.Combine(Environment.CurrentDirectory, "maps"); + saveFileDialog.FileName = Path.ChangeExtension(loadedMapName, ".png"); + + if (DialogResult.OK == saveFileDialog.ShowDialog()) + pmMiniMap.Image.Save(saveFileDialog.FileName); + } + } +} diff --git a/OpenRA.Editor/ITool.cs b/OpenRA.Editor/ITool.cs index 7d0199bbd0..e03083098f 100644 --- a/OpenRA.Editor/ITool.cs +++ b/OpenRA.Editor/ITool.cs @@ -1,20 +1,20 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using SGraphics = System.Drawing.Graphics; - -namespace OpenRA.Editor -{ - interface ITool - { - void Apply(Surface surface); - void Preview(Surface surface, SGraphics g); - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using SGraphics = System.Drawing.Graphics; + +namespace OpenRA.Editor +{ + interface ITool + { + void Apply(Surface surface); + void Preview(Surface surface, SGraphics g); + } +} diff --git a/OpenRA.Editor/LegacyMapImporter.cs b/OpenRA.Editor/LegacyMapImporter.cs index 2a90e6f556..856b82ca0b 100644 --- a/OpenRA.Editor/LegacyMapImporter.cs +++ b/OpenRA.Editor/LegacyMapImporter.cs @@ -1,472 +1,472 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Editor -{ - public class LegacyMapImporter - { - // Mapping from ra overlay index to type string - static string[] raOverlayNames = - { - "sbag", "cycl", "brik", "fenc", "wood", - "gold01", "gold02", "gold03", "gold04", - "gem01", "gem02", "gem03", "gem04", - "v12", "v13", "v14", "v15", "v16", "v17", "v18", - "fpls", "wcrate", "scrate", "barb", "sbag", - }; - - static Dictionary> overlayResourceMapping = new Dictionary>() - { - // RA Gems, Gold - { "gold01", new Pair(1,0) }, - { "gold02", new Pair(1,1) }, - { "gold03", new Pair(1,2) }, - { "gold04", new Pair(1,3) }, - - { "gem01", new Pair(2,0) }, - { "gem02", new Pair(2,1) }, - { "gem03", new Pair(2,2) }, - { "gem04", new Pair(2,3) }, - - // cnc tiberium - { "ti1", new Pair(1,0) }, - { "ti2", new Pair(1,1) }, - { "ti3", new Pair(1,2) }, - { "ti4", new Pair(1,3) }, - { "ti5", new Pair(1,4) }, - { "ti6", new Pair(1,5) }, - { "ti7", new Pair(1,6) }, - { "ti8", new Pair(1,7) }, - { "ti9", new Pair(1,8) }, - { "ti10", new Pair(1,9) }, - { "ti11", new Pair(1,10) }, - { "ti12", new Pair(1,11) }, - }; - - static Dictionary overlayActorMapping = new Dictionary() { - // Fences - {"sbag","sbag"}, - {"cycl","cycl"}, - {"brik","brik"}, - {"fenc","fenc"}, - {"wood","wood"}, - - // Fields - {"v12","v12"}, - {"v13","v13"}, - {"v14","v14"}, - {"v15","v15"}, - {"v16","v16"}, - {"v17","v17"}, - {"v18","v18"}, - - // Crates -// {"wcrate","crate"}, -// {"scrate","crate"}, - }; - - // todo: fix this -- will have bitrotted pretty badly. - static Dictionary> namedColorMapping = new Dictionary>() - { - {"gold",Pair.New(Color.FromArgb(246,214,121),Color.FromArgb(40,32,8))}, - {"blue",Pair.New(Color.FromArgb(226,230,246),Color.FromArgb(8,20,52))}, - {"red",Pair.New(Color.FromArgb(255,20,0),Color.FromArgb(56,0,0))}, - {"neutral",Pair.New(Color.FromArgb(238,238,238),Color.FromArgb(44,28,24))}, - {"orange",Pair.New(Color.FromArgb(255,230,149),Color.FromArgb(56,0,0))}, - {"teal",Pair.New(Color.FromArgb(93,194,165),Color.FromArgb(0,32,32))}, - {"salmon",Pair.New(Color.FromArgb(210,153,125),Color.FromArgb(56,0,0))}, - {"green",Pair.New(Color.FromArgb(160,240,140),Color.FromArgb(20,20,20))}, - {"white",Pair.New(Color.FromArgb(255,255,255),Color.FromArgb(75,75,75))}, - {"black",Pair.New(Color.FromArgb(80,80,80),Color.FromArgb(5,5,5))}, - }; - - int MapSize; - int ActorCount = 0; - Map Map = new Map(); - List Players = new List(); - - LegacyMapImporter(string filename) - { - ConvertIniMap(filename); - } - - public static Map Import(string filename) - { - var converter = new LegacyMapImporter(filename); - return converter.Map; - } - - enum IniMapFormat { RedAlert = 3, /* otherwise, cnc (2 variants exist, we don't care to differentiate) */ }; - - public void ConvertIniMap(string iniFile) - { - - var file = new IniFile(FileSystem.Open(iniFile)); - var basic = file.GetSection("Basic"); - var map = file.GetSection("Map"); - var legacyMapFormat = (IniMapFormat)int.Parse(basic.GetValue("NewINIFormat", "0")); - var XOffset = int.Parse(map.GetValue("X", "0")); - var YOffset = int.Parse(map.GetValue("Y", "0")); - var Width = int.Parse(map.GetValue("Width", "0")); - var Height = int.Parse(map.GetValue("Height", "0")); - MapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64; - - Map.Title = basic.GetValue("Name", "(null)"); - Map.Author = "Westwood Studios"; - Map.Tileset = Truncate(map.GetValue("Theater", "TEMPERAT"), 8); - Map.MapSize.X = MapSize; - Map.MapSize.Y = MapSize; - Map.Bounds = Rectangle.FromLTRB(XOffset, YOffset, XOffset + Width, YOffset + Height); - Map.Selectable = true; - - Map.Smudges = Lazy.New(() => new List()); - Map.Actors = Lazy.New(() => new Dictionary()); - Map.MapResources = Lazy.New(() => new TileReference[MapSize, MapSize]); - Map.MapTiles = Lazy.New(() => new TileReference[MapSize, MapSize]); - - if (legacyMapFormat == IniMapFormat.RedAlert) - { - UnpackRATileData(ReadPackedSection(file.GetSection("MapPack"))); - UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack"))); - ReadRATrees(file); - } - else // CNC - { - UnpackCncTileData(FileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin")); - ReadCncOverlay(file); - ReadCncTrees(file); - } - - LoadActors(file, "STRUCTURES"); - LoadActors(file, "UNITS"); - LoadActors(file, "INFANTRY"); - LoadSmudges(file, "SMUDGE"); - - foreach (var p in Players) - LoadPlayer(file, p, (legacyMapFormat == IniMapFormat.RedAlert)); - - var wps = file.GetSection("Waypoints") - .Where(kv => int.Parse(kv.Value) > 0) - .Select(kv => Pair.New(int.Parse(kv.Key), - LocationFromMapOffset(int.Parse(kv.Value), MapSize))) - .ToArray(); - - - // Add waypoint actors - foreach( var kv in wps ) - { - var a = new ActorReference("mpspawn"); - a.Add(new LocationInit(kv.Second)); - Map.Actors.Value.Add("spawn" + kv.First, a); - } - - } - - static int2 LocationFromMapOffset(int offset, int mapSize) - { - return new int2(offset % mapSize, offset / mapSize); - } - - static MemoryStream ReadPackedSection(IniSection mapPackSection) - { - StringBuilder sb = new StringBuilder(); - for (int i = 1; ; i++) - { - string line = mapPackSection.GetValue(i.ToString(), null); - if (line == null) - break; - - sb.Append(line.Trim()); - } - - byte[] data = Convert.FromBase64String(sb.ToString()); - List chunks = new List(); - BinaryReader reader = new BinaryReader(new MemoryStream(data)); - - try - { - while (true) - { - uint length = reader.ReadUInt32() & 0xdfffffff; - byte[] dest = new byte[8192]; - byte[] src = reader.ReadBytes((int)length); - - /*int actualLength =*/ - Format80.DecodeInto(src, dest); - - chunks.Add(dest); - } - } - catch (EndOfStreamException) { } - - MemoryStream ms = new MemoryStream(); - foreach (byte[] chunk in chunks) - ms.Write(chunk, 0, chunk.Length); - - ms.Position = 0; - - return ms; - } - - static byte ReadByte(Stream s) - { - int ret = s.ReadByte(); - if (ret == -1) - throw new NotImplementedException(); - return (byte)ret; - } - - static ushort ReadWord(Stream s) - { - ushort ret = ReadByte(s); - ret |= (ushort)(ReadByte(s) << 8); - - return ret; - } - - void UnpackRATileData(MemoryStream ms) - { - for (int i = 0; i < MapSize; i++) - for (int j = 0; j < MapSize; j++) - Map.MapTiles.Value[i, j] = new TileReference(); - - for (int j = 0; j < MapSize; j++) - for (int i = 0; i < MapSize; i++) - Map.MapTiles.Value[i, j].type = ReadWord(ms); - - for (int j = 0; j < MapSize; j++) - for (int i = 0; i < MapSize; i++) - Map.MapTiles.Value[i, j].index = ReadByte(ms); - } - - void UnpackRAOverlayData(MemoryStream ms) - { - for (int j = 0; j < MapSize; j++) - for (int i = 0; i < MapSize; i++) - { - byte o = ReadByte(ms); - var res = Pair.New((byte)0, (byte)0); - - if (o != 255 && overlayResourceMapping.ContainsKey(raOverlayNames[o])) - res = overlayResourceMapping[raOverlayNames[o]]; - - Map.MapResources.Value[i, j] = new TileReference(res.First, res.Second); - - if (o != 255 && overlayActorMapping.ContainsKey(raOverlayNames[o])) - Map.Actors.Value.Add("Actor" + ActorCount++, - new ActorReference(overlayActorMapping[raOverlayNames[o]]) - { - new LocationInit( new int2(i, j) ), - new OwnerInit( "Neutral" ) - }); - } - } - - void ReadRATrees(IniFile file) - { - IniSection terrain = file.GetSection("TERRAIN", true); - if (terrain == null) - return; - - foreach (KeyValuePair kv in terrain) - { - var loc = int.Parse(kv.Key); - Map.Actors.Value.Add("Actor" + ActorCount++, - new ActorReference(kv.Value.ToLowerInvariant()) - { - new LocationInit(new int2(loc % MapSize, loc / MapSize)), - new OwnerInit("Neutral") - }); - } - } - - void UnpackCncTileData(Stream ms) - { - for (int i = 0; i < MapSize; i++) - for (int j = 0; j < MapSize; j++) - Map.MapTiles.Value[i, j] = new TileReference(); - - for (int j = 0; j < MapSize; j++) - for (int i = 0; i < MapSize; i++) - { - Map.MapTiles.Value[i, j].type = ReadByte(ms); - Map.MapTiles.Value[i, j].index = ReadByte(ms); - } - } - - void ReadCncOverlay(IniFile file) - { - IniSection overlay = file.GetSection("OVERLAY", true); - if (overlay == null) - return; - - foreach (KeyValuePair kv in overlay) - { - var loc = int.Parse(kv.Key); - int2 cell = new int2(loc % MapSize, loc / MapSize); - - var res = Pair.New((byte)0, (byte)0); - if (overlayResourceMapping.ContainsKey(kv.Value.ToLower())) - res = overlayResourceMapping[kv.Value.ToLower()]; - - Map.MapResources.Value[cell.X, cell.Y] = new TileReference(res.First, res.Second); - - if (overlayActorMapping.ContainsKey(kv.Value.ToLower())) - Map.Actors.Value.Add("Actor" + ActorCount++, - new ActorReference(overlayActorMapping[kv.Value.ToLower()]) - { - new LocationInit(cell), - new OwnerInit("Neutral") - }); - } - } - - void ReadCncTrees(IniFile file) - { - IniSection terrain = file.GetSection("TERRAIN", true); - if (terrain == null) - return; - - foreach (KeyValuePair kv in terrain) - { - var loc = int.Parse(kv.Key); - Map.Actors.Value.Add("Actor" + ActorCount++, - new ActorReference(kv.Value.Split(',')[0].ToLowerInvariant()) - { - new LocationInit(new int2(loc % MapSize, loc / MapSize)), - new OwnerInit("Neutral") - }); - } - } - - 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 - var parts = s.Value.Split(','); - var loc = int.Parse(parts[3]); - if (parts[0] == "") - parts[0] = "Neutral"; - - - if (!Players.Contains(parts[0])) - Players.Add(parts[0]); - - var stance = ActorStance.Stance.None; - switch(parts[5]) - { - case "Area Guard": - case "Guard": - stance = ActorStance.Stance.Guard; - break; - case "Defend Base": - stance = ActorStance.Stance.Defend; - break; - case "Hunt": - case "Rampage": - case "Attack Base": - case "Attack Units": - case "Attack Civil.": - case "Attack Tarcom": - stance = ActorStance.Stance.Hunt; - break; - case "Retreat": - case "Return": - stance = ActorStance.Stance.Retreat; - break; - // do we care about `Harvest' and `Sticky'? - } - - var actor = new ActorReference(parts[1].ToLowerInvariant()) - { - new LocationInit(new int2(loc % MapSize, loc / MapSize)), - new OwnerInit(parts[0]), - new HealthInit(float.Parse(parts[2], NumberFormatInfo.InvariantInfo)/256), - new FacingInit((section == "INFANTRY") ? int.Parse(parts[6]) : int.Parse(parts[4])), - new ActorStanceInit(stance), - }; - - if (section == "INFANTRY") - actor.Add(new SubCellInit(int.Parse(parts[4]))); - - Map.Actors.Value.Add("Actor" + ActorCount++,actor); - - } - } - - 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 = int.Parse(parts[1]); - Map.Smudges.Value.Add(new SmudgeReference(parts[0].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), int.Parse(parts[2]))); - } - } - - void LoadPlayer(IniFile file, string section, bool isRA) - { - var c = (section == "BadGuy") ? "red" : - (isRA) ? "blue" : "gold"; - - var color = namedColorMapping[c]; - - var pr = new PlayerReference - { - Name = section, - OwnsWorld = (section == "Neutral"), - NonCombatant = (section == "Neutral"), - Race = (isRA) ? ((section == "BadGuy") ? "soviet" : "allies") : ((section == "BadGuy") ? "nod" : "gdi"), - ColorRamp = new ColorRamp( - (byte)((color.First.GetHue() / 360.0f) * 255), - (byte)(color.First.GetSaturation() * 255), - (byte)(color.First.GetBrightness() * 255), - (byte)(color.Second.GetBrightness() * 255)) - }; - - var Neutral = new List(){"Neutral"}; - foreach (var s in file.GetSection(section, true)) - { - Console.WriteLine(s.Key); - switch(s.Key) - { - case "Credits": - pr.InitialCash = int.Parse(s.Value); - break; - case "Allies": - pr.Allies = s.Value.Split(',').Intersect(Players).Except(Neutral).ToArray(); - pr.Enemies = s.Value.Split(',').SymmetricDifference(Players).Except(Neutral).ToArray(); - break; - } - } - - Map.Players.Add(section, pr); - } - - static string Truncate(string s, int maxLength) - { - return s.Length <= maxLength ? s : s.Substring(0, maxLength); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Editor +{ + public class LegacyMapImporter + { + // Mapping from ra overlay index to type string + static string[] raOverlayNames = + { + "sbag", "cycl", "brik", "fenc", "wood", + "gold01", "gold02", "gold03", "gold04", + "gem01", "gem02", "gem03", "gem04", + "v12", "v13", "v14", "v15", "v16", "v17", "v18", + "fpls", "wcrate", "scrate", "barb", "sbag", + }; + + static Dictionary> overlayResourceMapping = new Dictionary>() + { + // RA Gems, Gold + { "gold01", new Pair(1,0) }, + { "gold02", new Pair(1,1) }, + { "gold03", new Pair(1,2) }, + { "gold04", new Pair(1,3) }, + + { "gem01", new Pair(2,0) }, + { "gem02", new Pair(2,1) }, + { "gem03", new Pair(2,2) }, + { "gem04", new Pair(2,3) }, + + // cnc tiberium + { "ti1", new Pair(1,0) }, + { "ti2", new Pair(1,1) }, + { "ti3", new Pair(1,2) }, + { "ti4", new Pair(1,3) }, + { "ti5", new Pair(1,4) }, + { "ti6", new Pair(1,5) }, + { "ti7", new Pair(1,6) }, + { "ti8", new Pair(1,7) }, + { "ti9", new Pair(1,8) }, + { "ti10", new Pair(1,9) }, + { "ti11", new Pair(1,10) }, + { "ti12", new Pair(1,11) }, + }; + + static Dictionary overlayActorMapping = new Dictionary() { + // Fences + {"sbag","sbag"}, + {"cycl","cycl"}, + {"brik","brik"}, + {"fenc","fenc"}, + {"wood","wood"}, + + // Fields + {"v12","v12"}, + {"v13","v13"}, + {"v14","v14"}, + {"v15","v15"}, + {"v16","v16"}, + {"v17","v17"}, + {"v18","v18"}, + + // Crates +// {"wcrate","crate"}, +// {"scrate","crate"}, + }; + + // todo: fix this -- will have bitrotted pretty badly. + static Dictionary> namedColorMapping = new Dictionary>() + { + {"gold",Pair.New(Color.FromArgb(246,214,121),Color.FromArgb(40,32,8))}, + {"blue",Pair.New(Color.FromArgb(226,230,246),Color.FromArgb(8,20,52))}, + {"red",Pair.New(Color.FromArgb(255,20,0),Color.FromArgb(56,0,0))}, + {"neutral",Pair.New(Color.FromArgb(238,238,238),Color.FromArgb(44,28,24))}, + {"orange",Pair.New(Color.FromArgb(255,230,149),Color.FromArgb(56,0,0))}, + {"teal",Pair.New(Color.FromArgb(93,194,165),Color.FromArgb(0,32,32))}, + {"salmon",Pair.New(Color.FromArgb(210,153,125),Color.FromArgb(56,0,0))}, + {"green",Pair.New(Color.FromArgb(160,240,140),Color.FromArgb(20,20,20))}, + {"white",Pair.New(Color.FromArgb(255,255,255),Color.FromArgb(75,75,75))}, + {"black",Pair.New(Color.FromArgb(80,80,80),Color.FromArgb(5,5,5))}, + }; + + int MapSize; + int ActorCount = 0; + Map Map = new Map(); + List Players = new List(); + + LegacyMapImporter(string filename) + { + ConvertIniMap(filename); + } + + public static Map Import(string filename) + { + var converter = new LegacyMapImporter(filename); + return converter.Map; + } + + enum IniMapFormat { RedAlert = 3, /* otherwise, cnc (2 variants exist, we don't care to differentiate) */ }; + + public void ConvertIniMap(string iniFile) + { + + var file = new IniFile(FileSystem.Open(iniFile)); + var basic = file.GetSection("Basic"); + var map = file.GetSection("Map"); + var legacyMapFormat = (IniMapFormat)int.Parse(basic.GetValue("NewINIFormat", "0")); + var XOffset = int.Parse(map.GetValue("X", "0")); + var YOffset = int.Parse(map.GetValue("Y", "0")); + var Width = int.Parse(map.GetValue("Width", "0")); + var Height = int.Parse(map.GetValue("Height", "0")); + MapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64; + + Map.Title = basic.GetValue("Name", "(null)"); + Map.Author = "Westwood Studios"; + Map.Tileset = Truncate(map.GetValue("Theater", "TEMPERAT"), 8); + Map.MapSize.X = MapSize; + Map.MapSize.Y = MapSize; + Map.Bounds = Rectangle.FromLTRB(XOffset, YOffset, XOffset + Width, YOffset + Height); + Map.Selectable = true; + + Map.Smudges = Lazy.New(() => new List()); + Map.Actors = Lazy.New(() => new Dictionary()); + Map.MapResources = Lazy.New(() => new TileReference[MapSize, MapSize]); + Map.MapTiles = Lazy.New(() => new TileReference[MapSize, MapSize]); + + if (legacyMapFormat == IniMapFormat.RedAlert) + { + UnpackRATileData(ReadPackedSection(file.GetSection("MapPack"))); + UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack"))); + ReadRATrees(file); + } + else // CNC + { + UnpackCncTileData(FileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin")); + ReadCncOverlay(file); + ReadCncTrees(file); + } + + LoadActors(file, "STRUCTURES"); + LoadActors(file, "UNITS"); + LoadActors(file, "INFANTRY"); + LoadSmudges(file, "SMUDGE"); + + foreach (var p in Players) + LoadPlayer(file, p, (legacyMapFormat == IniMapFormat.RedAlert)); + + var wps = file.GetSection("Waypoints") + .Where(kv => int.Parse(kv.Value) > 0) + .Select(kv => Pair.New(int.Parse(kv.Key), + LocationFromMapOffset(int.Parse(kv.Value), MapSize))) + .ToArray(); + + + // Add waypoint actors + foreach( var kv in wps ) + { + var a = new ActorReference("mpspawn"); + a.Add(new LocationInit(kv.Second)); + Map.Actors.Value.Add("spawn" + kv.First, a); + } + + } + + static int2 LocationFromMapOffset(int offset, int mapSize) + { + return new int2(offset % mapSize, offset / mapSize); + } + + static MemoryStream ReadPackedSection(IniSection mapPackSection) + { + StringBuilder sb = new StringBuilder(); + for (int i = 1; ; i++) + { + string line = mapPackSection.GetValue(i.ToString(), null); + if (line == null) + break; + + sb.Append(line.Trim()); + } + + byte[] data = Convert.FromBase64String(sb.ToString()); + List chunks = new List(); + BinaryReader reader = new BinaryReader(new MemoryStream(data)); + + try + { + while (true) + { + uint length = reader.ReadUInt32() & 0xdfffffff; + byte[] dest = new byte[8192]; + byte[] src = reader.ReadBytes((int)length); + + /*int actualLength =*/ + Format80.DecodeInto(src, dest); + + chunks.Add(dest); + } + } + catch (EndOfStreamException) { } + + MemoryStream ms = new MemoryStream(); + foreach (byte[] chunk in chunks) + ms.Write(chunk, 0, chunk.Length); + + ms.Position = 0; + + return ms; + } + + static byte ReadByte(Stream s) + { + int ret = s.ReadByte(); + if (ret == -1) + throw new NotImplementedException(); + return (byte)ret; + } + + static ushort ReadWord(Stream s) + { + ushort ret = ReadByte(s); + ret |= (ushort)(ReadByte(s) << 8); + + return ret; + } + + void UnpackRATileData(MemoryStream ms) + { + for (int i = 0; i < MapSize; i++) + for (int j = 0; j < MapSize; j++) + Map.MapTiles.Value[i, j] = new TileReference(); + + for (int j = 0; j < MapSize; j++) + for (int i = 0; i < MapSize; i++) + Map.MapTiles.Value[i, j].type = ReadWord(ms); + + for (int j = 0; j < MapSize; j++) + for (int i = 0; i < MapSize; i++) + Map.MapTiles.Value[i, j].index = ReadByte(ms); + } + + void UnpackRAOverlayData(MemoryStream ms) + { + for (int j = 0; j < MapSize; j++) + for (int i = 0; i < MapSize; i++) + { + byte o = ReadByte(ms); + var res = Pair.New((byte)0, (byte)0); + + if (o != 255 && overlayResourceMapping.ContainsKey(raOverlayNames[o])) + res = overlayResourceMapping[raOverlayNames[o]]; + + Map.MapResources.Value[i, j] = new TileReference(res.First, res.Second); + + if (o != 255 && overlayActorMapping.ContainsKey(raOverlayNames[o])) + Map.Actors.Value.Add("Actor" + ActorCount++, + new ActorReference(overlayActorMapping[raOverlayNames[o]]) + { + new LocationInit( new int2(i, j) ), + new OwnerInit( "Neutral" ) + }); + } + } + + void ReadRATrees(IniFile file) + { + IniSection terrain = file.GetSection("TERRAIN", true); + if (terrain == null) + return; + + foreach (KeyValuePair kv in terrain) + { + var loc = int.Parse(kv.Key); + Map.Actors.Value.Add("Actor" + ActorCount++, + new ActorReference(kv.Value.ToLowerInvariant()) + { + new LocationInit(new int2(loc % MapSize, loc / MapSize)), + new OwnerInit("Neutral") + }); + } + } + + void UnpackCncTileData(Stream ms) + { + for (int i = 0; i < MapSize; i++) + for (int j = 0; j < MapSize; j++) + Map.MapTiles.Value[i, j] = new TileReference(); + + for (int j = 0; j < MapSize; j++) + for (int i = 0; i < MapSize; i++) + { + Map.MapTiles.Value[i, j].type = ReadByte(ms); + Map.MapTiles.Value[i, j].index = ReadByte(ms); + } + } + + void ReadCncOverlay(IniFile file) + { + IniSection overlay = file.GetSection("OVERLAY", true); + if (overlay == null) + return; + + foreach (KeyValuePair kv in overlay) + { + var loc = int.Parse(kv.Key); + int2 cell = new int2(loc % MapSize, loc / MapSize); + + var res = Pair.New((byte)0, (byte)0); + if (overlayResourceMapping.ContainsKey(kv.Value.ToLower())) + res = overlayResourceMapping[kv.Value.ToLower()]; + + Map.MapResources.Value[cell.X, cell.Y] = new TileReference(res.First, res.Second); + + if (overlayActorMapping.ContainsKey(kv.Value.ToLower())) + Map.Actors.Value.Add("Actor" + ActorCount++, + new ActorReference(overlayActorMapping[kv.Value.ToLower()]) + { + new LocationInit(cell), + new OwnerInit("Neutral") + }); + } + } + + void ReadCncTrees(IniFile file) + { + IniSection terrain = file.GetSection("TERRAIN", true); + if (terrain == null) + return; + + foreach (KeyValuePair kv in terrain) + { + var loc = int.Parse(kv.Key); + Map.Actors.Value.Add("Actor" + ActorCount++, + new ActorReference(kv.Value.Split(',')[0].ToLowerInvariant()) + { + new LocationInit(new int2(loc % MapSize, loc / MapSize)), + new OwnerInit("Neutral") + }); + } + } + + 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 + var parts = s.Value.Split(','); + var loc = int.Parse(parts[3]); + if (parts[0] == "") + parts[0] = "Neutral"; + + + if (!Players.Contains(parts[0])) + Players.Add(parts[0]); + + var stance = ActorStance.Stance.None; + switch(parts[5]) + { + case "Area Guard": + case "Guard": + stance = ActorStance.Stance.Guard; + break; + case "Defend Base": + stance = ActorStance.Stance.Defend; + break; + case "Hunt": + case "Rampage": + case "Attack Base": + case "Attack Units": + case "Attack Civil.": + case "Attack Tarcom": + stance = ActorStance.Stance.Hunt; + break; + case "Retreat": + case "Return": + stance = ActorStance.Stance.Retreat; + break; + // do we care about `Harvest' and `Sticky'? + } + + var actor = new ActorReference(parts[1].ToLowerInvariant()) + { + new LocationInit(new int2(loc % MapSize, loc / MapSize)), + new OwnerInit(parts[0]), + new HealthInit(float.Parse(parts[2], NumberFormatInfo.InvariantInfo)/256), + new FacingInit((section == "INFANTRY") ? int.Parse(parts[6]) : int.Parse(parts[4])), + new ActorStanceInit(stance), + }; + + if (section == "INFANTRY") + actor.Add(new SubCellInit(int.Parse(parts[4]))); + + Map.Actors.Value.Add("Actor" + ActorCount++,actor); + + } + } + + 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 = int.Parse(parts[1]); + Map.Smudges.Value.Add(new SmudgeReference(parts[0].ToLowerInvariant(), new int2(loc % MapSize, loc / MapSize), int.Parse(parts[2]))); + } + } + + void LoadPlayer(IniFile file, string section, bool isRA) + { + var c = (section == "BadGuy") ? "red" : + (isRA) ? "blue" : "gold"; + + var color = namedColorMapping[c]; + + var pr = new PlayerReference + { + Name = section, + OwnsWorld = (section == "Neutral"), + NonCombatant = (section == "Neutral"), + Race = (isRA) ? ((section == "BadGuy") ? "soviet" : "allies") : ((section == "BadGuy") ? "nod" : "gdi"), + ColorRamp = new ColorRamp( + (byte)((color.First.GetHue() / 360.0f) * 255), + (byte)(color.First.GetSaturation() * 255), + (byte)(color.First.GetBrightness() * 255), + (byte)(color.Second.GetBrightness() * 255)) + }; + + var Neutral = new List(){"Neutral"}; + foreach (var s in file.GetSection(section, true)) + { + Console.WriteLine(s.Key); + switch(s.Key) + { + case "Credits": + pr.InitialCash = int.Parse(s.Value); + break; + case "Allies": + pr.Allies = s.Value.Split(',').Intersect(Players).Except(Neutral).ToArray(); + pr.Enemies = s.Value.Split(',').SymmetricDifference(Players).Except(Neutral).ToArray(); + break; + } + } + + Map.Players.Add(section, pr); + } + + static string Truncate(string s, int maxLength) + { + return s.Length <= maxLength ? s : s.Substring(0, maxLength); + } + } +} diff --git a/OpenRA.Editor/NewMapDialog.cs b/OpenRA.Editor/NewMapDialog.cs index 8ab3aedbd9..199790474c 100755 --- a/OpenRA.Editor/NewMapDialog.cs +++ b/OpenRA.Editor/NewMapDialog.cs @@ -1,27 +1,27 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Windows.Forms; - -namespace OpenRA.Editor -{ - public partial class NewMapDialog : Form - { - public NewMapDialog() - { - InitializeComponent(); - } - - private void SelectText(object sender, System.EventArgs e) - { - (sender as NumericUpDown).Select(0, (sender as NumericUpDown).ToString().Length); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Windows.Forms; + +namespace OpenRA.Editor +{ + public partial class NewMapDialog : Form + { + public NewMapDialog() + { + InitializeComponent(); + } + + private void SelectText(object sender, System.EventArgs e) + { + (sender as NumericUpDown).Select(0, (sender as NumericUpDown).ToString().Length); + } + } +} diff --git a/OpenRA.Editor/Program.cs b/OpenRA.Editor/Program.cs index ac34b1c65a..7c4b90af5d 100644 --- a/OpenRA.Editor/Program.cs +++ b/OpenRA.Editor/Program.cs @@ -1,54 +1,54 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Globalization; -using System.Windows.Forms; -using System.Linq; -using System.IO; -using OpenRA.FileFormats; - -namespace OpenRA.Editor -{ - static class Program - { - [STAThread] - static void Main( string[] args ) - { - if (args.Length >= 2 && args[0] == "--convert") - { - Game.modData = new ModData(args[1]); - FileSystem.LoadFromManifest(Game.modData.Manifest); - Rules.LoadRules(Game.modData.Manifest, new Map()); - UpgradeMaps(args[1]); - return; - } - - Application.CurrentCulture = CultureInfo.InvariantCulture; - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - - Application.Run(new Form1(args)); - } - - static void UpgradeMaps(string mod) - { - var MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", mod, "maps" } - .Aggregate(Path.Combine); - - foreach (var path in ModData.FindMapsIn(MapFolderPath)) - { - var map = new Map(path); - map.Save(path); - } - } - - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Globalization; +using System.Windows.Forms; +using System.Linq; +using System.IO; +using OpenRA.FileFormats; + +namespace OpenRA.Editor +{ + static class Program + { + [STAThread] + static void Main( string[] args ) + { + if (args.Length >= 2 && args[0] == "--convert") + { + Game.modData = new ModData(args[1]); + FileSystem.LoadFromManifest(Game.modData.Manifest); + Rules.LoadRules(Game.modData.Manifest, new Map()); + UpgradeMaps(args[1]); + return; + } + + Application.CurrentCulture = CultureInfo.InvariantCulture; + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + Application.Run(new Form1(args)); + } + + static void UpgradeMaps(string mod) + { + var MapFolderPath = new string[] { Environment.CurrentDirectory, "mods", mod, "maps" } + .Aggregate(Path.Combine); + + foreach (var path in ModData.FindMapsIn(MapFolderPath)) + { + var map = new Map(path); + map.Save(path); + } + } + + } +} diff --git a/OpenRA.Editor/PropertiesDialog.cs b/OpenRA.Editor/PropertiesDialog.cs index f003553cc8..875c92c54b 100644 --- a/OpenRA.Editor/PropertiesDialog.cs +++ b/OpenRA.Editor/PropertiesDialog.cs @@ -1,22 +1,22 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Windows.Forms; - -namespace OpenRA.Editor -{ - public partial class PropertiesDialog : Form - { - public PropertiesDialog() - { - InitializeComponent(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Windows.Forms; + +namespace OpenRA.Editor +{ + public partial class PropertiesDialog : Form + { + public PropertiesDialog() + { + InitializeComponent(); + } + } +} diff --git a/OpenRA.Editor/RenderUtils.cs b/OpenRA.Editor/RenderUtils.cs index 62116aa760..472bdf430d 100644 --- a/OpenRA.Editor/RenderUtils.cs +++ b/OpenRA.Editor/RenderUtils.cs @@ -1,156 +1,156 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using System.Drawing.Imaging; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Editor -{ - static class RenderUtils - { - public static ColorPalette MakeSystemPalette(Palette p) - { - ColorPalette pal; - using (var b = new Bitmap(1, 1, PixelFormat.Format8bppIndexed)) - pal = b.Palette; - - for (var i = 0; i < 256; i++) - pal.Entries[i] = p.GetColor(i); - return pal; - } - - public static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p) - { - var template = ts.Templates[n]; - var tile = ts.Tiles[n]; - - var bitmap = new Bitmap(ts.TileSize * template.Size.X, ts.TileSize * template.Size.Y, - PixelFormat.Format8bppIndexed); - - bitmap.Palette = MakeSystemPalette(p); - - var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), - ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - - unsafe - { - byte* q = (byte*)data.Scan0.ToPointer(); - var stride = data.Stride; - - for (var u = 0; u < template.Size.X; u++) - for (var v = 0; v < template.Size.Y; v++) - if (tile.TileBitmapBytes[u + v * template.Size.X] != null) - { - var rawImage = tile.TileBitmapBytes[u + v * template.Size.X]; - for (var i = 0; i < ts.TileSize; i++) - for (var j = 0; j < ts.TileSize; j++) - q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = rawImage[i + ts.TileSize * j]; - } - else - { - for (var i = 0; i < ts.TileSize; i++) - for (var j = 0; j < ts.TileSize; j++) - q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = 0; - } - } - - bitmap.UnlockBits(data); - return bitmap; - } - - static Bitmap RenderShp(ShpReader shp, Palette p) - { - var frame = shp[0]; - - var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed); - - bitmap.Palette = MakeSystemPalette(p); - - var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), - ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - - unsafe - { - byte* q = (byte*)data.Scan0.ToPointer(); - var stride2 = data.Stride; - - for (var i = 0; i < shp.Width; i++) - for (var j = 0; j < shp.Height; j++) - q[j * stride2 + i] = frame.Image[i + shp.Width * j]; - } - - bitmap.UnlockBits(data); - return bitmap; - } - - public static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p) - { - var ri = info.Traits.Get(); - var image = RenderSimple.GetImage(info, tileset.Id); - - using (var s = FileSystem.OpenWithExts(image, tileset.Extensions)) - { - var shp = new ShpReader(s); - var bitmap = RenderShp(shp, p); - - try - { - using (var s2 = FileSystem.OpenWithExts(image + "2", tileset.Extensions)) - { - var shp2 = new ShpReader(s2); - var roofBitmap = RenderShp(shp2, p); - - using (var g = System.Drawing.Graphics.FromImage(bitmap)) - g.DrawImage(roofBitmap, 0, 0); - } - } - catch { } - - return new ActorTemplate - { - Bitmap = bitmap, - Info = info, - Appearance = info.Traits.GetOrDefault() - }; - } - } - - public static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p) - { - var image = info.SpriteNames[0]; - using (var s = FileSystem.OpenWithExts(image, exts)) - { - var shp = new ShpReader(s); - var frame = shp[shp.ImageCount - 1]; - - var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed); - bitmap.Palette = MakeSystemPalette(p); - var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), - ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - - unsafe - { - byte* q = (byte*)data.Scan0.ToPointer(); - var stride = data.Stride; - - for (var i = 0; i < shp.Width; i++) - for (var j = 0; j < shp.Height; j++) - q[j * stride + i] = frame.Image[i + shp.Width * j]; - } - - bitmap.UnlockBits(data); - return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 }; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using System.Drawing.Imaging; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Editor +{ + static class RenderUtils + { + public static ColorPalette MakeSystemPalette(Palette p) + { + ColorPalette pal; + using (var b = new Bitmap(1, 1, PixelFormat.Format8bppIndexed)) + pal = b.Palette; + + for (var i = 0; i < 256; i++) + pal.Entries[i] = p.GetColor(i); + return pal; + } + + public static Bitmap RenderTemplate(TileSet ts, ushort n, Palette p) + { + var template = ts.Templates[n]; + var tile = ts.Tiles[n]; + + var bitmap = new Bitmap(ts.TileSize * template.Size.X, ts.TileSize * template.Size.Y, + PixelFormat.Format8bppIndexed); + + bitmap.Palette = MakeSystemPalette(p); + + var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); + + unsafe + { + byte* q = (byte*)data.Scan0.ToPointer(); + var stride = data.Stride; + + for (var u = 0; u < template.Size.X; u++) + for (var v = 0; v < template.Size.Y; v++) + if (tile.TileBitmapBytes[u + v * template.Size.X] != null) + { + var rawImage = tile.TileBitmapBytes[u + v * template.Size.X]; + for (var i = 0; i < ts.TileSize; i++) + for (var j = 0; j < ts.TileSize; j++) + q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = rawImage[i + ts.TileSize * j]; + } + else + { + for (var i = 0; i < ts.TileSize; i++) + for (var j = 0; j < ts.TileSize; j++) + q[(v * ts.TileSize + j) * stride + u * ts.TileSize + i] = 0; + } + } + + bitmap.UnlockBits(data); + return bitmap; + } + + static Bitmap RenderShp(ShpReader shp, Palette p) + { + var frame = shp[0]; + + var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed); + + bitmap.Palette = MakeSystemPalette(p); + + var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); + + unsafe + { + byte* q = (byte*)data.Scan0.ToPointer(); + var stride2 = data.Stride; + + for (var i = 0; i < shp.Width; i++) + for (var j = 0; j < shp.Height; j++) + q[j * stride2 + i] = frame.Image[i + shp.Width * j]; + } + + bitmap.UnlockBits(data); + return bitmap; + } + + public static ActorTemplate RenderActor(ActorInfo info, TileSet tileset, Palette p) + { + var ri = info.Traits.Get(); + var image = RenderSimple.GetImage(info, tileset.Id); + + using (var s = FileSystem.OpenWithExts(image, tileset.Extensions)) + { + var shp = new ShpReader(s); + var bitmap = RenderShp(shp, p); + + try + { + using (var s2 = FileSystem.OpenWithExts(image + "2", tileset.Extensions)) + { + var shp2 = new ShpReader(s2); + var roofBitmap = RenderShp(shp2, p); + + using (var g = System.Drawing.Graphics.FromImage(bitmap)) + g.DrawImage(roofBitmap, 0, 0); + } + } + catch { } + + return new ActorTemplate + { + Bitmap = bitmap, + Info = info, + Appearance = info.Traits.GetOrDefault() + }; + } + } + + public static ResourceTemplate RenderResourceType(ResourceTypeInfo info, string[] exts, Palette p) + { + var image = info.SpriteNames[0]; + using (var s = FileSystem.OpenWithExts(image, exts)) + { + var shp = new ShpReader(s); + var frame = shp[shp.ImageCount - 1]; + + var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed); + bitmap.Palette = MakeSystemPalette(p); + var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); + + unsafe + { + byte* q = (byte*)data.Scan0.ToPointer(); + var stride = data.Stride; + + for (var i = 0; i < shp.Width; i++) + for (var j = 0; j < shp.Height; j++) + q[j * stride + i] = frame.Image[i + shp.Width * j]; + } + + bitmap.UnlockBits(data); + return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 }; + } + } + } +} diff --git a/OpenRA.Editor/ResizeDialog.cs b/OpenRA.Editor/ResizeDialog.cs index 5754d42464..081ec6105f 100644 --- a/OpenRA.Editor/ResizeDialog.cs +++ b/OpenRA.Editor/ResizeDialog.cs @@ -1,22 +1,22 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Windows.Forms; - -namespace OpenRA.Editor -{ - public partial class ResizeDialog : Form - { - public ResizeDialog() - { - InitializeComponent(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Windows.Forms; + +namespace OpenRA.Editor +{ + public partial class ResizeDialog : Form + { + public ResizeDialog() + { + InitializeComponent(); + } + } +} diff --git a/OpenRA.Editor/ResourceTool.cs b/OpenRA.Editor/ResourceTool.cs index a1c87f86dd..1c60edbfa1 100644 --- a/OpenRA.Editor/ResourceTool.cs +++ b/OpenRA.Editor/ResourceTool.cs @@ -1,50 +1,50 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.FileFormats; - -using SGraphics = System.Drawing.Graphics; - -namespace OpenRA.Editor -{ - class ResourceTool : ITool - { - ResourceTemplate Resource; - - public ResourceTool(ResourceTemplate resource) { Resource = resource; } - - public void Apply(Surface surface) - { - surface.Map.MapResources.Value[surface.GetBrushLocation().X, surface.GetBrushLocation().Y] - = new TileReference - { - type = (byte)Resource.Info.ResourceType, - index = (byte)random.Next(Resource.Info.SpriteNames.Length) - }; - - var ch = new int2((surface.GetBrushLocation().X) / Surface.ChunkSize, - (surface.GetBrushLocation().Y) / Surface.ChunkSize); - - if (surface.Chunks.ContainsKey(ch)) - { - surface.Chunks[ch].Dispose(); - surface.Chunks.Remove(ch); - } - } - - public void Preview(Surface surface, SGraphics g) - { - surface.DrawImage(g, Resource.Bitmap, surface.GetBrushLocation(), false, null); - } - - Random random = new Random(); - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.FileFormats; + +using SGraphics = System.Drawing.Graphics; + +namespace OpenRA.Editor +{ + class ResourceTool : ITool + { + ResourceTemplate Resource; + + public ResourceTool(ResourceTemplate resource) { Resource = resource; } + + public void Apply(Surface surface) + { + surface.Map.MapResources.Value[surface.GetBrushLocation().X, surface.GetBrushLocation().Y] + = new TileReference + { + type = (byte)Resource.Info.ResourceType, + index = (byte)random.Next(Resource.Info.SpriteNames.Length) + }; + + var ch = new int2((surface.GetBrushLocation().X) / Surface.ChunkSize, + (surface.GetBrushLocation().Y) / Surface.ChunkSize); + + if (surface.Chunks.ContainsKey(ch)) + { + surface.Chunks[ch].Dispose(); + surface.Chunks.Remove(ch); + } + } + + public void Preview(Surface surface, SGraphics g) + { + surface.DrawImage(g, Resource.Bitmap, surface.GetBrushLocation(), false, null); + } + + Random random = new Random(); + } +} diff --git a/OpenRA.Editor/Surface.cs b/OpenRA.Editor/Surface.cs index e87067a4cd..aad9195081 100755 --- a/OpenRA.Editor/Surface.cs +++ b/OpenRA.Editor/Surface.cs @@ -1,364 +1,364 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; -using System.Linq; -using System.Windows.Forms; -using OpenRA.FileFormats; -using OpenRA.Traits; - -using SGraphics = System.Drawing.Graphics; - -namespace OpenRA.Editor -{ - class Surface : Control - { - public Map Map { get; private set; } - public TileSet TileSet { get; private set; } - public Palette Palette { get; private set; } - public int2 Offset; - - public int2 GetOffset() { return Offset; } - - public float Zoom = 1.0f; - - ITool Tool; - - public bool IsPanning; - public event Action AfterChange = () => { }; - public event Action MousePositionChanged = _ => { }; - - Dictionary ActorTemplates = new Dictionary(); - Dictionary ResourceTemplates = new Dictionary(); - - public Keys GetModifiers() { return ModifierKeys; } - - public void Bind(Map m, TileSet ts, Palette p) - { - Map = m; - TileSet = ts; - Palette = p; - PlayerPalettes = null; - Chunks.Clear(); - Tool = null; - } - - public void SetTool(ITool tool) { Tool = tool; } - - public void BindActorTemplates(IEnumerable templates) - { - ActorTemplates = templates.ToDictionary(a => a.Info.Name.ToLowerInvariant()); - } - - public void BindResourceTemplates(IEnumerable templates) - { - ResourceTemplates = templates.ToDictionary(a => a.Info.ResourceType); - } - - public Dictionary Chunks = new Dictionary(); - - public Surface() - : base() - { - BackColor = Color.Black; - - SetStyle(ControlStyles.OptimizedDoubleBuffer, true); - SetStyle(ControlStyles.ResizeRedraw, true); - UpdateStyles(); - } - - static readonly Pen CordonPen = new Pen(Color.Red); - int2 MousePos; - - public void Scroll(int2 dx) - { - Offset -= dx; - Invalidate(); - } - - protected override void OnMouseWheel(MouseEventArgs e) - { - base.OnMouseWheel(e); - - if (Map == null) return; - - Zoom *= e.Delta > 0 ? 4.0f / 3.0f : .75f; - - Invalidate(); - } - - protected override void OnMouseLeave(EventArgs e) - { - base.OnMouseLeave(e); - - this.Parent.Focus(); - - Invalidate(); - } - - protected override void OnMouseEnter(EventArgs e) - { - base.OnMouseLeave(e); - - this.Focus(); - - Invalidate(); - } - - protected override void OnMouseMove(MouseEventArgs e) - { - base.OnMouseMove(e); - - if (Map == null) return; - - var oldMousePos = MousePos; - MousePos = new int2(e.Location); - MousePositionChanged(GetBrushLocation().ToString()); - - if (e.Button == MouseButtons.Middle || (e.Button != MouseButtons.None && IsPanning)) - Scroll(oldMousePos - MousePos); - else - { - if (e.Button == MouseButtons.Right) - Erase(); - - if (e.Button == MouseButtons.Left) - Draw(); - - Invalidate(); - } - } - - void Erase() - { - // Crash preventing - var BrushLocation = GetBrushLocation(); - - if (Map == null || BrushLocation.X >= Map.MapSize.X || - BrushLocation.Y >= Map.MapSize.Y || - BrushLocation.X < 0 || - BrushLocation.Y < 0) - return; - - Tool = null; - - var key = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == BrushLocation); - if (key.Key != null) Map.Actors.Value.Remove(key.Key); - - if (Map.MapResources.Value[BrushLocation.X, BrushLocation.Y].type != 0) - { - Map.MapResources.Value[BrushLocation.X, BrushLocation.Y] = new TileReference(); - var ch = new int2((BrushLocation.X) / ChunkSize, (BrushLocation.Y) / ChunkSize); - if (Chunks.ContainsKey(ch)) - { - Chunks[ch].Dispose(); - Chunks.Remove(ch); - } - } - - AfterChange(); - } - - void Draw() - { - if (Tool != null) Tool.Apply(this); - AfterChange(); - } - - protected override void OnMouseDown(MouseEventArgs e) - { - base.OnMouseDown(e); - - if (Map == null) return; - - if (!IsPanning) - { - if (e.Button == MouseButtons.Right) Erase(); - if (e.Button == MouseButtons.Left) Draw(); - } - - Invalidate(); - } - - public const int ChunkSize = 8; // 8x8 chunks ==> 192x192 bitmaps. - - Bitmap RenderChunk(int u, int v) - { - - var bitmap = new Bitmap(ChunkSize * TileSet.TileSize, ChunkSize * TileSet.TileSize); - bitmap.SetPixel(0, 0, Color.Green); - - var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), - ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); - - unsafe - { - int* p = (int*)data.Scan0.ToPointer(); - var stride = data.Stride >> 2; - - for (var i = 0; i < ChunkSize; i++) - for (var j = 0; j < ChunkSize; j++) - { - var tr = Map.MapTiles.Value[u * ChunkSize + i, v * ChunkSize + j]; - var tile = TileSet.Tiles[tr.type]; - var index = (tr.index < tile.TileBitmapBytes.Count) ? tr.index : (byte)0; - var rawImage = tile.TileBitmapBytes[index]; - for (var x = 0; x < TileSet.TileSize; x++) - for (var y = 0; y < TileSet.TileSize; y++) - p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = Palette.GetColor(rawImage[x + TileSet.TileSize * y]).ToArgb(); - - if (Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type != 0) - { - var resourceImage = ResourceTemplates[Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type].Bitmap; - var srcdata = resourceImage.LockBits(new Rectangle(0, 0, resourceImage.Width, resourceImage.Height), - ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); - - int* q = (int*)srcdata.Scan0.ToPointer(); - var srcstride = srcdata.Stride >> 2; - - for (var x = 0; x < TileSet.TileSize; x++) - for (var y = 0; y < TileSet.TileSize; y++) - { - var c = q[y * srcstride + x]; - if ((c & 0xff000000) != 0) /* quick & dirty, i cbf doing real alpha */ - p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = c; - } - - resourceImage.UnlockBits(srcdata); - } - } - } - - bitmap.UnlockBits(data); - return bitmap; - } - - public int2 GetBrushLocation() - { - var vX = (int)Math.Floor((MousePos.X - Offset.X) / Zoom); - var vY = (int)Math.Floor((MousePos.Y - Offset.Y) / Zoom); - return new int2(vX / TileSet.TileSize, vY / TileSet.TileSize); - } - - public void DrawActor(SGraphics g, int2 p, ActorTemplate t, ColorPalette cp) - { - var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft; - DrawImage(g, t.Bitmap, p, centered, cp); - } - - float2 GetDrawPosition(int2 location, Bitmap bmp, bool centered) - { - float OffsetX = centered ? bmp.Width / 2 - TileSet.TileSize / 2 : 0; - float DrawX = TileSet.TileSize * location.X * Zoom + Offset.X - OffsetX; - - float OffsetY = centered ? bmp.Height / 2 - TileSet.TileSize / 2 : 0; - float DrawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - OffsetY; - - return new float2(DrawX, DrawY); - } - - public void DrawImage(SGraphics g, Bitmap bmp, int2 location, bool centered, ColorPalette cp) - { - var drawPos = GetDrawPosition(location, bmp, centered); - - var sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height); - var destRect = new RectangleF(drawPos.X, drawPos.Y, bmp.Width * Zoom, bmp.Height * Zoom); - - var restorePalette = bmp.Palette; - if (cp != null) bmp.Palette = cp; - g.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel); - if (cp != null) bmp.Palette = restorePalette; - } - - void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t) - { - var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft; - var drawPos = GetDrawPosition(p, t.Bitmap, centered); - - g.DrawRectangle(CordonPen, - drawPos.X, drawPos.Y, - t.Bitmap.Width * Zoom, t.Bitmap.Height * Zoom); - } - - ColorPalette GetPaletteForPlayer(string name) - { - var pr = Map.Players[name]; - var pcpi = Rules.Info["player"].Traits.Get(); - var remap = new PlayerColorRemap(pr.ColorRamp, pcpi.PaletteFormat); - return RenderUtils.MakeSystemPalette(new Palette(Palette, remap)); - } - - Cache PlayerPalettes; - - ColorPalette GetPaletteForActor(ActorReference ar) - { - if (PlayerPalettes == null) - PlayerPalettes = new Cache(GetPaletteForPlayer); - - var ownerInit = ar.InitDict.GetOrDefault(); - if (ownerInit == null) - return null; - - return PlayerPalettes[ownerInit.PlayerName]; - } - - protected override void OnPaint(PaintEventArgs e) - { - if (Map == null) return; - if (TileSet == null) return; - - for (var u = 0; u < Map.MapSize.X; u += ChunkSize) - for (var v = 0; v < Map.MapSize.Y; v += ChunkSize) - { - var x = new int2(u / ChunkSize, v / ChunkSize); - if (!Chunks.ContainsKey(x)) Chunks[x] = RenderChunk(u / ChunkSize, v / ChunkSize); - - Bitmap bmp = Chunks[x]; - - float DrawX = TileSet.TileSize * (float)ChunkSize * (float)x.X * Zoom + Offset.X; - float DrawY = TileSet.TileSize * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y; - RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height); - RectangleF destRect = new RectangleF(DrawX, DrawY, bmp.Width * Zoom, bmp.Height * Zoom); - e.Graphics.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel); - } - - e.Graphics.DrawRectangle(CordonPen, - Map.Bounds.Left * TileSet.TileSize * Zoom + Offset.X, - Map.Bounds.Top * TileSet.TileSize * Zoom + Offset.Y, - Map.Bounds.Width * TileSet.TileSize * Zoom, - Map.Bounds.Height * TileSet.TileSize * Zoom); - - foreach (var ar in Map.Actors.Value) - DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type], - GetPaletteForActor(ar.Value)); - - if (Tool != null) - Tool.Preview(this, e.Graphics); - - if (Tool == null) - { - var x = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == GetBrushLocation()); - if (x.Key != null) - DrawActorBorder(e.Graphics, x.Value.Location(), ActorTemplates[x.Value.Type]); - } - } - } - - static class ActorReferenceExts - { - public static int2 Location(this ActorReference ar) - { - return ar.InitDict.Get().value; - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using System.Windows.Forms; +using OpenRA.FileFormats; +using OpenRA.Traits; + +using SGraphics = System.Drawing.Graphics; + +namespace OpenRA.Editor +{ + class Surface : Control + { + public Map Map { get; private set; } + public TileSet TileSet { get; private set; } + public Palette Palette { get; private set; } + public int2 Offset; + + public int2 GetOffset() { return Offset; } + + public float Zoom = 1.0f; + + ITool Tool; + + public bool IsPanning; + public event Action AfterChange = () => { }; + public event Action MousePositionChanged = _ => { }; + + Dictionary ActorTemplates = new Dictionary(); + Dictionary ResourceTemplates = new Dictionary(); + + public Keys GetModifiers() { return ModifierKeys; } + + public void Bind(Map m, TileSet ts, Palette p) + { + Map = m; + TileSet = ts; + Palette = p; + PlayerPalettes = null; + Chunks.Clear(); + Tool = null; + } + + public void SetTool(ITool tool) { Tool = tool; } + + public void BindActorTemplates(IEnumerable templates) + { + ActorTemplates = templates.ToDictionary(a => a.Info.Name.ToLowerInvariant()); + } + + public void BindResourceTemplates(IEnumerable templates) + { + ResourceTemplates = templates.ToDictionary(a => a.Info.ResourceType); + } + + public Dictionary Chunks = new Dictionary(); + + public Surface() + : base() + { + BackColor = Color.Black; + + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + SetStyle(ControlStyles.ResizeRedraw, true); + UpdateStyles(); + } + + static readonly Pen CordonPen = new Pen(Color.Red); + int2 MousePos; + + public void Scroll(int2 dx) + { + Offset -= dx; + Invalidate(); + } + + protected override void OnMouseWheel(MouseEventArgs e) + { + base.OnMouseWheel(e); + + if (Map == null) return; + + Zoom *= e.Delta > 0 ? 4.0f / 3.0f : .75f; + + Invalidate(); + } + + protected override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + + this.Parent.Focus(); + + Invalidate(); + } + + protected override void OnMouseEnter(EventArgs e) + { + base.OnMouseLeave(e); + + this.Focus(); + + Invalidate(); + } + + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + if (Map == null) return; + + var oldMousePos = MousePos; + MousePos = new int2(e.Location); + MousePositionChanged(GetBrushLocation().ToString()); + + if (e.Button == MouseButtons.Middle || (e.Button != MouseButtons.None && IsPanning)) + Scroll(oldMousePos - MousePos); + else + { + if (e.Button == MouseButtons.Right) + Erase(); + + if (e.Button == MouseButtons.Left) + Draw(); + + Invalidate(); + } + } + + void Erase() + { + // Crash preventing + var BrushLocation = GetBrushLocation(); + + if (Map == null || BrushLocation.X >= Map.MapSize.X || + BrushLocation.Y >= Map.MapSize.Y || + BrushLocation.X < 0 || + BrushLocation.Y < 0) + return; + + Tool = null; + + var key = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == BrushLocation); + if (key.Key != null) Map.Actors.Value.Remove(key.Key); + + if (Map.MapResources.Value[BrushLocation.X, BrushLocation.Y].type != 0) + { + Map.MapResources.Value[BrushLocation.X, BrushLocation.Y] = new TileReference(); + var ch = new int2((BrushLocation.X) / ChunkSize, (BrushLocation.Y) / ChunkSize); + if (Chunks.ContainsKey(ch)) + { + Chunks[ch].Dispose(); + Chunks.Remove(ch); + } + } + + AfterChange(); + } + + void Draw() + { + if (Tool != null) Tool.Apply(this); + AfterChange(); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if (Map == null) return; + + if (!IsPanning) + { + if (e.Button == MouseButtons.Right) Erase(); + if (e.Button == MouseButtons.Left) Draw(); + } + + Invalidate(); + } + + public const int ChunkSize = 8; // 8x8 chunks ==> 192x192 bitmaps. + + Bitmap RenderChunk(int u, int v) + { + + var bitmap = new Bitmap(ChunkSize * TileSet.TileSize, ChunkSize * TileSet.TileSize); + bitmap.SetPixel(0, 0, Color.Green); + + var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + + unsafe + { + int* p = (int*)data.Scan0.ToPointer(); + var stride = data.Stride >> 2; + + for (var i = 0; i < ChunkSize; i++) + for (var j = 0; j < ChunkSize; j++) + { + var tr = Map.MapTiles.Value[u * ChunkSize + i, v * ChunkSize + j]; + var tile = TileSet.Tiles[tr.type]; + var index = (tr.index < tile.TileBitmapBytes.Count) ? tr.index : (byte)0; + var rawImage = tile.TileBitmapBytes[index]; + for (var x = 0; x < TileSet.TileSize; x++) + for (var y = 0; y < TileSet.TileSize; y++) + p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = Palette.GetColor(rawImage[x + TileSet.TileSize * y]).ToArgb(); + + if (Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type != 0) + { + var resourceImage = ResourceTemplates[Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type].Bitmap; + var srcdata = resourceImage.LockBits(new Rectangle(0, 0, resourceImage.Width, resourceImage.Height), + ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + + int* q = (int*)srcdata.Scan0.ToPointer(); + var srcstride = srcdata.Stride >> 2; + + for (var x = 0; x < TileSet.TileSize; x++) + for (var y = 0; y < TileSet.TileSize; y++) + { + var c = q[y * srcstride + x]; + if ((c & 0xff000000) != 0) /* quick & dirty, i cbf doing real alpha */ + p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = c; + } + + resourceImage.UnlockBits(srcdata); + } + } + } + + bitmap.UnlockBits(data); + return bitmap; + } + + public int2 GetBrushLocation() + { + var vX = (int)Math.Floor((MousePos.X - Offset.X) / Zoom); + var vY = (int)Math.Floor((MousePos.Y - Offset.Y) / Zoom); + return new int2(vX / TileSet.TileSize, vY / TileSet.TileSize); + } + + public void DrawActor(SGraphics g, int2 p, ActorTemplate t, ColorPalette cp) + { + var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft; + DrawImage(g, t.Bitmap, p, centered, cp); + } + + float2 GetDrawPosition(int2 location, Bitmap bmp, bool centered) + { + float OffsetX = centered ? bmp.Width / 2 - TileSet.TileSize / 2 : 0; + float DrawX = TileSet.TileSize * location.X * Zoom + Offset.X - OffsetX; + + float OffsetY = centered ? bmp.Height / 2 - TileSet.TileSize / 2 : 0; + float DrawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - OffsetY; + + return new float2(DrawX, DrawY); + } + + public void DrawImage(SGraphics g, Bitmap bmp, int2 location, bool centered, ColorPalette cp) + { + var drawPos = GetDrawPosition(location, bmp, centered); + + var sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height); + var destRect = new RectangleF(drawPos.X, drawPos.Y, bmp.Width * Zoom, bmp.Height * Zoom); + + var restorePalette = bmp.Palette; + if (cp != null) bmp.Palette = cp; + g.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel); + if (cp != null) bmp.Palette = restorePalette; + } + + void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t) + { + var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft; + var drawPos = GetDrawPosition(p, t.Bitmap, centered); + + g.DrawRectangle(CordonPen, + drawPos.X, drawPos.Y, + t.Bitmap.Width * Zoom, t.Bitmap.Height * Zoom); + } + + ColorPalette GetPaletteForPlayer(string name) + { + var pr = Map.Players[name]; + var pcpi = Rules.Info["player"].Traits.Get(); + var remap = new PlayerColorRemap(pr.ColorRamp, pcpi.PaletteFormat); + return RenderUtils.MakeSystemPalette(new Palette(Palette, remap)); + } + + Cache PlayerPalettes; + + ColorPalette GetPaletteForActor(ActorReference ar) + { + if (PlayerPalettes == null) + PlayerPalettes = new Cache(GetPaletteForPlayer); + + var ownerInit = ar.InitDict.GetOrDefault(); + if (ownerInit == null) + return null; + + return PlayerPalettes[ownerInit.PlayerName]; + } + + protected override void OnPaint(PaintEventArgs e) + { + if (Map == null) return; + if (TileSet == null) return; + + for (var u = 0; u < Map.MapSize.X; u += ChunkSize) + for (var v = 0; v < Map.MapSize.Y; v += ChunkSize) + { + var x = new int2(u / ChunkSize, v / ChunkSize); + if (!Chunks.ContainsKey(x)) Chunks[x] = RenderChunk(u / ChunkSize, v / ChunkSize); + + Bitmap bmp = Chunks[x]; + + float DrawX = TileSet.TileSize * (float)ChunkSize * (float)x.X * Zoom + Offset.X; + float DrawY = TileSet.TileSize * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y; + RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height); + RectangleF destRect = new RectangleF(DrawX, DrawY, bmp.Width * Zoom, bmp.Height * Zoom); + e.Graphics.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel); + } + + e.Graphics.DrawRectangle(CordonPen, + Map.Bounds.Left * TileSet.TileSize * Zoom + Offset.X, + Map.Bounds.Top * TileSet.TileSize * Zoom + Offset.Y, + Map.Bounds.Width * TileSet.TileSize * Zoom, + Map.Bounds.Height * TileSet.TileSize * Zoom); + + foreach (var ar in Map.Actors.Value) + DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type], + GetPaletteForActor(ar.Value)); + + if (Tool != null) + Tool.Preview(this, e.Graphics); + + if (Tool == null) + { + var x = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == GetBrushLocation()); + if (x.Key != null) + DrawActorBorder(e.Graphics, x.Value.Location(), ActorTemplates[x.Value.Type]); + } + } + } + + static class ActorReferenceExts + { + public static int2 Location(this ActorReference ar) + { + return ar.InitDict.Get().value; + } + } } \ No newline at end of file diff --git a/OpenRA.FileFormats/ColorHSLR.cs b/OpenRA.FileFormats/ColorHSLR.cs index 369a9313e7..ed04f6bed2 100644 --- a/OpenRA.FileFormats/ColorHSLR.cs +++ b/OpenRA.FileFormats/ColorHSLR.cs @@ -1,64 +1,64 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; - -namespace OpenRA.FileFormats -{ - public struct ColorRamp - { - public byte H,S,L,R; - - public ColorRamp(byte h, byte s, byte l, byte r) - { - H = h; S = s; L = l; R = r; - } - - /* returns a color along the Lum ramp */ - public Color GetColor( float t ) - { - return ColorFromHSL( H / 255f, S / 255f, float2.Lerp( L / 255f, L*R / (255f * 255f), t ) ); - } - - public override string ToString() - { - return "{0},{1},{2},{3}".F(H, S, L, R); - } - - // hk is hue in the range [0,1] instead of [0,360] - public static Color ColorFromHSL(float hk, float s, float l) - { - // Convert from HSL to RGB - var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s); - var p = 2 * l - q; - - float[] trgb = { hk + 1 / 3.0f, - hk, - hk - 1/3.0f }; - float[] rgb = { 0, 0, 0 }; - - for (int k = 0; k < 3; k++) - { - while (trgb[k] < 0) trgb[k] += 1.0f; - while (trgb[k] > 1) trgb[k] -= 1.0f; - } - - for (int k = 0; k < 3; k++) - { - if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); } - else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; } - else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); } - else { rgb[k] = p; } - } - - return Color.FromArgb((int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255)); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; + +namespace OpenRA.FileFormats +{ + public struct ColorRamp + { + public byte H,S,L,R; + + public ColorRamp(byte h, byte s, byte l, byte r) + { + H = h; S = s; L = l; R = r; + } + + /* returns a color along the Lum ramp */ + public Color GetColor( float t ) + { + return ColorFromHSL( H / 255f, S / 255f, float2.Lerp( L / 255f, L*R / (255f * 255f), t ) ); + } + + public override string ToString() + { + return "{0},{1},{2},{3}".F(H, S, L, R); + } + + // hk is hue in the range [0,1] instead of [0,360] + public static Color ColorFromHSL(float hk, float s, float l) + { + // Convert from HSL to RGB + var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s); + var p = 2 * l - q; + + float[] trgb = { hk + 1 / 3.0f, + hk, + hk - 1/3.0f }; + float[] rgb = { 0, 0, 0 }; + + for (int k = 0; k < 3; k++) + { + while (trgb[k] < 0) trgb[k] += 1.0f; + while (trgb[k] > 1) trgb[k] -= 1.0f; + } + + for (int k = 0; k < 3; k++) + { + if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); } + else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; } + else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); } + else { rgb[k] = p; } + } + + return Color.FromArgb((int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255)); + } + } +} diff --git a/OpenRA.FileFormats/Evaluator.cs b/OpenRA.FileFormats/Evaluator.cs index e8a4258aca..523e354dbd 100644 --- a/OpenRA.FileFormats/Evaluator.cs +++ b/OpenRA.FileFormats/Evaluator.cs @@ -1,107 +1,107 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.FileFormats -{ - public static class Evaluator - { - public static int Evaluate(string expr) - { - return Evaluate(expr, new Dictionary()); - } - - public static int Evaluate(string expr, Dictionary syms) - { - var toks = Tokens(expr, "+-*/()"); - var postfix = ToPostfix(toks, syms); - - var s = new Stack(); - - foreach (var t in postfix) - { - switch (t[0]) - { - case '+': ApplyBinop(s, (x, y) => y + x); break; - case '-': ApplyBinop(s, (x, y) => y - x); break; - case '*': ApplyBinop(s, (x, y) => y * x); break; - case '/': ApplyBinop(s, (x, y) => y / x); break; - default: s.Push(int.Parse(t)); break; - } - } - return s.Pop(); - } - - static void ApplyBinop( Stack s, Func f ) - { - var x = s.Pop(); - var y = s.Pop(); - s.Push( f(x,y) ); - } - - static IEnumerable ToPostfix(IEnumerable toks, Dictionary syms) - { - var s = new Stack(); - foreach (var t in toks) - { - if (t[0] == '(') s.Push(t); - else if (t[0] == ')') - { - var temp = ""; - while ((temp = s.Pop()) != "(") yield return temp; - } - else if (char.IsNumber(t[0])) yield return t; - else if (char.IsLetter(t[0])) - { - if (!syms.ContainsKey(t)) - throw new InvalidOperationException("Substitution `{0}` undefined".F(t)); - - yield return syms[t].ToString();; - } - else - { - while (s.Count > 0 && Prec[t] <= Prec[s.Peek()]) yield return s.Pop(); - s.Push(t); - } - } - - while (s.Count > 0) yield return s.Pop(); - } - - static readonly Dictionary Prec - = new Dictionary { { "+", 0 }, { "-", 0 }, { "*", 1 }, { "/", 1 }, { "(", -1 } }; - - static IEnumerable Tokens(string expr, string ops) - { - var s = ""; - foreach (var c in expr) - { - if (char.IsWhiteSpace(c)) - { - if (s != "") yield return s; - s = ""; - } - else if (ops.Contains(c)) - { - if (s != "") yield return s; - s = ""; - yield return "" + c; - } - else - s += c; - } - - if (s != "") yield return s; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.FileFormats +{ + public static class Evaluator + { + public static int Evaluate(string expr) + { + return Evaluate(expr, new Dictionary()); + } + + public static int Evaluate(string expr, Dictionary syms) + { + var toks = Tokens(expr, "+-*/()"); + var postfix = ToPostfix(toks, syms); + + var s = new Stack(); + + foreach (var t in postfix) + { + switch (t[0]) + { + case '+': ApplyBinop(s, (x, y) => y + x); break; + case '-': ApplyBinop(s, (x, y) => y - x); break; + case '*': ApplyBinop(s, (x, y) => y * x); break; + case '/': ApplyBinop(s, (x, y) => y / x); break; + default: s.Push(int.Parse(t)); break; + } + } + return s.Pop(); + } + + static void ApplyBinop( Stack s, Func f ) + { + var x = s.Pop(); + var y = s.Pop(); + s.Push( f(x,y) ); + } + + static IEnumerable ToPostfix(IEnumerable toks, Dictionary syms) + { + var s = new Stack(); + foreach (var t in toks) + { + if (t[0] == '(') s.Push(t); + else if (t[0] == ')') + { + var temp = ""; + while ((temp = s.Pop()) != "(") yield return temp; + } + else if (char.IsNumber(t[0])) yield return t; + else if (char.IsLetter(t[0])) + { + if (!syms.ContainsKey(t)) + throw new InvalidOperationException("Substitution `{0}` undefined".F(t)); + + yield return syms[t].ToString();; + } + else + { + while (s.Count > 0 && Prec[t] <= Prec[s.Peek()]) yield return s.Pop(); + s.Push(t); + } + } + + while (s.Count > 0) yield return s.Pop(); + } + + static readonly Dictionary Prec + = new Dictionary { { "+", 0 }, { "-", 0 }, { "*", 1 }, { "/", 1 }, { "(", -1 } }; + + static IEnumerable Tokens(string expr, string ops) + { + var s = ""; + foreach (var c in expr) + { + if (char.IsWhiteSpace(c)) + { + if (s != "") yield return s; + s = ""; + } + else if (ops.Contains(c)) + { + if (s != "") yield return s; + s = ""; + yield return "" + c; + } + else + s += c; + } + + if (s != "") yield return s; + } + } +} diff --git a/OpenRA.FileFormats/Exts.cs b/OpenRA.FileFormats/Exts.cs index 890f781504..d2b9f4aaa6 100755 --- a/OpenRA.FileFormats/Exts.cs +++ b/OpenRA.FileFormats/Exts.cs @@ -1,110 +1,110 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Reflection; - -namespace OpenRA -{ - public static class Exts - { - public static string F(this string fmt, params object[] args) - { - return string.Format(fmt, args); - } - - public static void Do(this IEnumerable e, Action fn) - { - foreach (var ee in e) - fn(ee); - } - - public static IEnumerable GetNamespaces(this Assembly a) - { - return a.GetTypes().Select(t => t.Namespace).Distinct().Where(n => n != null); - } - - public static string ReadAllText(this Stream s) - { - using (s) - using (var sr = new StreamReader(s)) - return sr.ReadToEnd(); - } - - public static byte[] ReadAllBytes(this Stream s) - { - using (s) - { - var data = new byte[s.Length - s.Position]; - s.Read(data, 0, data.Length); - return data; - } - } - - public static void Write(this Stream s, byte[] data) - { - s.Write(data, 0, data.Length); - } - - public static IEnumerable ReadAllLines(this Stream s) - { - using (var sr = new StreamReader(s)) - for (; ; ) - { - var line = sr.ReadLine(); - if (line == null) - yield break; - else - yield return line; - } - } - - public static bool HasAttribute(this MemberInfo mi) - { - return mi.GetCustomAttributes(typeof(T), true).Length != 0; - } - - public static T[] GetCustomAttributes(this MemberInfo mi, bool inherit) - where T : class - { - return (T[])mi.GetCustomAttributes(typeof(T), inherit); - } - - public static T[] GetCustomAttributes(this ParameterInfo mi) - where T : class - { - return (T[])mi.GetCustomAttributes(typeof(T), true); - } - - public static T Clamp(this T val, T min, T max) where T : IComparable - { - if (val.CompareTo(min) < 0) - return min; - else if (val.CompareTo(max) > 0) - return max; - else - return val; - } - - public static bool Contains(this Rectangle r, int2 p) - { - return r.Contains(p.ToPoint()); - } - - public static bool Contains(this RectangleF r, int2 p) - { - return r.Contains(p.ToPointF()); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace OpenRA +{ + public static class Exts + { + public static string F(this string fmt, params object[] args) + { + return string.Format(fmt, args); + } + + public static void Do(this IEnumerable e, Action fn) + { + foreach (var ee in e) + fn(ee); + } + + public static IEnumerable GetNamespaces(this Assembly a) + { + return a.GetTypes().Select(t => t.Namespace).Distinct().Where(n => n != null); + } + + public static string ReadAllText(this Stream s) + { + using (s) + using (var sr = new StreamReader(s)) + return sr.ReadToEnd(); + } + + public static byte[] ReadAllBytes(this Stream s) + { + using (s) + { + var data = new byte[s.Length - s.Position]; + s.Read(data, 0, data.Length); + return data; + } + } + + public static void Write(this Stream s, byte[] data) + { + s.Write(data, 0, data.Length); + } + + public static IEnumerable ReadAllLines(this Stream s) + { + using (var sr = new StreamReader(s)) + for (; ; ) + { + var line = sr.ReadLine(); + if (line == null) + yield break; + else + yield return line; + } + } + + public static bool HasAttribute(this MemberInfo mi) + { + return mi.GetCustomAttributes(typeof(T), true).Length != 0; + } + + public static T[] GetCustomAttributes(this MemberInfo mi, bool inherit) + where T : class + { + return (T[])mi.GetCustomAttributes(typeof(T), inherit); + } + + public static T[] GetCustomAttributes(this ParameterInfo mi) + where T : class + { + return (T[])mi.GetCustomAttributes(typeof(T), true); + } + + public static T Clamp(this T val, T min, T max) where T : IComparable + { + if (val.CompareTo(min) < 0) + return min; + else if (val.CompareTo(max) > 0) + return max; + else + return val; + } + + public static bool Contains(this Rectangle r, int2 p) + { + return r.Contains(p.ToPoint()); + } + + public static bool Contains(this RectangleF r, int2 p) + { + return r.Contains(p.ToPointF()); + } + } +} diff --git a/OpenRA.FileFormats/FieldLoader.cs b/OpenRA.FileFormats/FieldLoader.cs index 74f07967e1..ece0c28bc3 100755 --- a/OpenRA.FileFormats/FieldLoader.cs +++ b/OpenRA.FileFormats/FieldLoader.cs @@ -1,316 +1,316 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Reflection; -using System.Globalization; - -namespace OpenRA.FileFormats -{ - public static class FieldLoader - { - public static Func InvalidValueAction = (s,t,f) => - { - throw new InvalidOperationException("FieldLoader: Cannot parse `{0}` into `{1}.{2}` ".F(s,f,t) ); - }; - - public static Action UnknownFieldAction = (s,f) => - { - throw new NotImplementedException( "FieldLoader: Missing field `{0}` on `{1}`".F( s, f.Name ) ); - }; - - public static void Load( object self, MiniYaml my ) - { - var loadDict = typeLoadInfo[ self.GetType() ]; - - foreach( var kv in loadDict ) - { - object val; - if( kv.Value != null ) - val = kv.Value( kv.Key.Name, kv.Key.FieldType, my ); - else if( !TryGetValueFromYaml( kv.Key.Name, kv.Key.FieldType, my, out val ) ) - continue; - - kv.Key.SetValue( self, val ); - } - } - - static bool TryGetValueFromYaml( string fieldName, Type fieldType, MiniYaml yaml, out object ret ) - { - ret = null; - var n = yaml.Nodes.Where( x=>x.Key == fieldName ).ToList(); - if( n.Count == 0 ) - return false; - if( n.Count == 1 && n[ 0 ].Value.Nodes.Count == 0 ) - { - ret = GetValue( fieldName, fieldType, n[ 0 ].Value.Value ); - return true; - } - throw new InvalidOperationException( "TryGetValueFromYaml: unable to load field {0} (of type {1})".F( fieldName, fieldType ) ); - } - - public static T Load(MiniYaml y) where T : new() - { - var t = new T(); - Load(t, y); - return t; - } - - public static void LoadField( object self, string key, string value ) - { - var field = self.GetType().GetField( key.Trim() ); - - if( field == null ) - UnknownFieldAction( key.Trim(), self.GetType() ); - else if( field.HasAttribute() ) - return; - else - field.SetValue( self, GetValue( field.Name, field.FieldType, value ) ); - } - - public static object GetValue( string field, Type fieldType, string x ) - { - if (x != null) x = x.Trim(); - if( fieldType == typeof( int ) ) - { - int res; - if (int.TryParse(x,out res)) - return res; - return InvalidValueAction(x,fieldType, field); - } - - else if( fieldType == typeof( ushort ) ) - { - ushort res; - if (ushort.TryParse(x,out res)) - return res; - return InvalidValueAction(x,fieldType, field); - } - - else if (fieldType == typeof(float)) - { - float res; - if (float.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res)) - return res * (x.Contains( '%' ) ? 0.01f : 1f); - return InvalidValueAction(x,fieldType, field); - } - - else if (fieldType == typeof(decimal)) - { - decimal res; - if (decimal.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res)) - return res * (x.Contains( '%' ) ? 0.01m : 1m); - return InvalidValueAction(x,fieldType, field); - } - - else if (fieldType == typeof(string)) - return x; - - else if (fieldType == typeof(Color)) - { - var parts = x.Split(','); - if (parts.Length == 3) - return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255)); - if (parts.Length == 4) - return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255), int.Parse(parts[3]).Clamp(0, 255)); - return InvalidValueAction(x,fieldType, field); - } - - else if (fieldType == typeof(ColorRamp)) - { - var parts = x.Split(','); - if (parts.Length == 4) - return new ColorRamp( - (byte)int.Parse(parts[0]).Clamp(0, 255), - (byte)int.Parse(parts[1]).Clamp(0, 255), - (byte)int.Parse(parts[2]).Clamp(0, 255), - (byte)int.Parse(parts[3]).Clamp(0, 255)); - - return InvalidValueAction(x, fieldType, field); - } - - else if (fieldType.IsEnum) - { - if (!Enum.GetNames(fieldType).Select(a => a.ToLower()).Contains(x.ToLower())) - return InvalidValueAction(x, fieldType, field); - return Enum.Parse(fieldType, x, true); - } - - else if (fieldType == typeof(bool)) - return ParseYesNo(x, fieldType, field); - - else if (fieldType.IsArray) - { - if (x == null) - return Array.CreateInstance(fieldType.GetElementType(), 0); - - var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length); - for (int i = 0; i < parts.Length; i++) - ret.SetValue(GetValue(field, fieldType.GetElementType(), parts[i].Trim()), i); - return ret; - } - else if (fieldType == typeof(int2)) - { - var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - return new int2(int.Parse(parts[0]), int.Parse(parts[1])); - } - else if (fieldType == typeof(float2)) - { - var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - float xx = 0; - float yy = 0; - float res; - if (float.TryParse(parts[0].Replace("%", ""), out res)) - xx = res * (parts[0].Contains('%') ? 0.01f : 1f); - if (float.TryParse(parts[1].Replace("%", ""), out res)) - yy = res * (parts[1].Contains('%') ? 0.01f : 1f); - return new float2(xx, yy); - } - else if (fieldType == typeof(Rectangle)) - { - var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - return new Rectangle(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3])); - } - - UnknownFieldAction("[Type] {0}".F(x),fieldType); - return null; - } - - static object ParseYesNo( string p, System.Type fieldType, string field ) - { - p = p.ToLowerInvariant(); - if( p == "yes" ) return true; - if( p == "true" ) return true; - if( p == "no" ) return false; - if( p == "false" ) return false; - return InvalidValueAction(p,fieldType, field); - } - - static Cache>> typeLoadInfo = new Cache>>( GetTypeLoadInfo ); - - static Dictionary> GetTypeLoadInfo( Type type ) - { - var ret = new Dictionary>(); - - foreach( var ff in type.GetFields() ) - { - var field = ff; - var load = field.GetCustomAttributes( false ); - var loadUsing = field.GetCustomAttributes( false ); - var fromYamlKey = field.GetCustomAttributes( false ); - if( loadUsing.Length != 0 ) - ret[ field ] = ( _1, fieldType, yaml ) => loadUsing[ 0 ].LoaderFunc( field )( yaml ); - else if( fromYamlKey.Length != 0 ) - ret[ field ] = ( f, ft, yaml ) => GetValue( f, ft, yaml.Value ); - else if( load.Length != 0 ) - ret[ field ] = null; - } - - if( ret.Count == 0 ) - foreach( var f in type.GetFields() ) - ret.Add( f, null ); - - return ret; - } - - [AttributeUsage( AttributeTargets.Field )] - public class LoadAttribute : Attribute { } - - [AttributeUsage( AttributeTargets.Field )] - public class LoadUsingAttribute : Attribute - { - Func loaderFuncCache; - public readonly string Loader; - - public LoadUsingAttribute( string loader ) - { - Loader = loader; - } - - internal Func LoaderFunc( FieldInfo field ) - { - const BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; - if( loaderFuncCache == null ) - loaderFuncCache = (Func)Delegate.CreateDelegate( typeof( Func ), field.DeclaringType.GetMethod( Loader, bf ) ); - return loaderFuncCache; - } - } - } - - public static class FieldSaver - { - public static MiniYaml Save(object o) - { - var nodes = new List(); - string root = null; - - foreach( var f in o.GetType().GetFields( BindingFlags.Public | BindingFlags.Instance ) ) - { - if( f.HasAttribute() ) - root = FormatValue( o, f ); - else - nodes.Add( new MiniYamlNode( f.Name, FormatValue( o, f ) ) ); - } - - return new MiniYaml( root, nodes ); - } - - public static MiniYaml SaveDifferences(object o, object from) - { - if (o.GetType() != from.GetType()) - throw new InvalidOperationException("FieldLoader: can't diff objects of different types"); - - var fields = o.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance) - .Where(f => FormatValue(o,f) != FormatValue(from,f)); - - return new MiniYaml( null, fields.Select( f => new MiniYamlNode( - f.Name, - FormatValue( o, f ) ) ).ToList() ); - } - - public static MiniYamlNode SaveField(object o, string field) - { - return new MiniYamlNode(field, FieldSaver.FormatValue( o, o.GetType().GetField(field) )); - } - - public static string FormatValue(object o, FieldInfo f) - { - var v = f.GetValue(o); - if (v == null) - return ""; - - // Color.ToString() does the wrong thing; force it to format as an array - if (f.FieldType == typeof(Color)) - { - var c = (Color)v; - return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255), - ((int)c.R).Clamp(0, 255), - ((int)c.G).Clamp(0, 255), - ((int)c.B).Clamp(0, 255)); - } - else if (f.FieldType == typeof(Rectangle)) - { - var r = (Rectangle)v; - return "{0},{1},{2},{3}".F(r.X, r.Y, r.Width, r.Height); - } - - return f.FieldType.IsArray - ? string.Join(",", ((Array)v).OfType().Select(a => a.ToString()).ToArray()) - : v.ToString(); - } - } - - public class FieldFromYamlKeyAttribute : Attribute { } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Globalization; + +namespace OpenRA.FileFormats +{ + public static class FieldLoader + { + public static Func InvalidValueAction = (s,t,f) => + { + throw new InvalidOperationException("FieldLoader: Cannot parse `{0}` into `{1}.{2}` ".F(s,f,t) ); + }; + + public static Action UnknownFieldAction = (s,f) => + { + throw new NotImplementedException( "FieldLoader: Missing field `{0}` on `{1}`".F( s, f.Name ) ); + }; + + public static void Load( object self, MiniYaml my ) + { + var loadDict = typeLoadInfo[ self.GetType() ]; + + foreach( var kv in loadDict ) + { + object val; + if( kv.Value != null ) + val = kv.Value( kv.Key.Name, kv.Key.FieldType, my ); + else if( !TryGetValueFromYaml( kv.Key.Name, kv.Key.FieldType, my, out val ) ) + continue; + + kv.Key.SetValue( self, val ); + } + } + + static bool TryGetValueFromYaml( string fieldName, Type fieldType, MiniYaml yaml, out object ret ) + { + ret = null; + var n = yaml.Nodes.Where( x=>x.Key == fieldName ).ToList(); + if( n.Count == 0 ) + return false; + if( n.Count == 1 && n[ 0 ].Value.Nodes.Count == 0 ) + { + ret = GetValue( fieldName, fieldType, n[ 0 ].Value.Value ); + return true; + } + throw new InvalidOperationException( "TryGetValueFromYaml: unable to load field {0} (of type {1})".F( fieldName, fieldType ) ); + } + + public static T Load(MiniYaml y) where T : new() + { + var t = new T(); + Load(t, y); + return t; + } + + public static void LoadField( object self, string key, string value ) + { + var field = self.GetType().GetField( key.Trim() ); + + if( field == null ) + UnknownFieldAction( key.Trim(), self.GetType() ); + else if( field.HasAttribute() ) + return; + else + field.SetValue( self, GetValue( field.Name, field.FieldType, value ) ); + } + + public static object GetValue( string field, Type fieldType, string x ) + { + if (x != null) x = x.Trim(); + if( fieldType == typeof( int ) ) + { + int res; + if (int.TryParse(x,out res)) + return res; + return InvalidValueAction(x,fieldType, field); + } + + else if( fieldType == typeof( ushort ) ) + { + ushort res; + if (ushort.TryParse(x,out res)) + return res; + return InvalidValueAction(x,fieldType, field); + } + + else if (fieldType == typeof(float)) + { + float res; + if (float.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res)) + return res * (x.Contains( '%' ) ? 0.01f : 1f); + return InvalidValueAction(x,fieldType, field); + } + + else if (fieldType == typeof(decimal)) + { + decimal res; + if (decimal.TryParse(x.Replace("%",""), System.Globalization.NumberStyles.Any, NumberFormatInfo.InvariantInfo, out res)) + return res * (x.Contains( '%' ) ? 0.01m : 1m); + return InvalidValueAction(x,fieldType, field); + } + + else if (fieldType == typeof(string)) + return x; + + else if (fieldType == typeof(Color)) + { + var parts = x.Split(','); + if (parts.Length == 3) + return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255)); + if (parts.Length == 4) + return Color.FromArgb(int.Parse(parts[0]).Clamp(0, 255), int.Parse(parts[1]).Clamp(0, 255), int.Parse(parts[2]).Clamp(0, 255), int.Parse(parts[3]).Clamp(0, 255)); + return InvalidValueAction(x,fieldType, field); + } + + else if (fieldType == typeof(ColorRamp)) + { + var parts = x.Split(','); + if (parts.Length == 4) + return new ColorRamp( + (byte)int.Parse(parts[0]).Clamp(0, 255), + (byte)int.Parse(parts[1]).Clamp(0, 255), + (byte)int.Parse(parts[2]).Clamp(0, 255), + (byte)int.Parse(parts[3]).Clamp(0, 255)); + + return InvalidValueAction(x, fieldType, field); + } + + else if (fieldType.IsEnum) + { + if (!Enum.GetNames(fieldType).Select(a => a.ToLower()).Contains(x.ToLower())) + return InvalidValueAction(x, fieldType, field); + return Enum.Parse(fieldType, x, true); + } + + else if (fieldType == typeof(bool)) + return ParseYesNo(x, fieldType, field); + + else if (fieldType.IsArray) + { + if (x == null) + return Array.CreateInstance(fieldType.GetElementType(), 0); + + var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + + var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length); + for (int i = 0; i < parts.Length; i++) + ret.SetValue(GetValue(field, fieldType.GetElementType(), parts[i].Trim()), i); + return ret; + } + else if (fieldType == typeof(int2)) + { + var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + return new int2(int.Parse(parts[0]), int.Parse(parts[1])); + } + else if (fieldType == typeof(float2)) + { + var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + float xx = 0; + float yy = 0; + float res; + if (float.TryParse(parts[0].Replace("%", ""), out res)) + xx = res * (parts[0].Contains('%') ? 0.01f : 1f); + if (float.TryParse(parts[1].Replace("%", ""), out res)) + yy = res * (parts[1].Contains('%') ? 0.01f : 1f); + return new float2(xx, yy); + } + else if (fieldType == typeof(Rectangle)) + { + var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + return new Rectangle(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3])); + } + + UnknownFieldAction("[Type] {0}".F(x),fieldType); + return null; + } + + static object ParseYesNo( string p, System.Type fieldType, string field ) + { + p = p.ToLowerInvariant(); + if( p == "yes" ) return true; + if( p == "true" ) return true; + if( p == "no" ) return false; + if( p == "false" ) return false; + return InvalidValueAction(p,fieldType, field); + } + + static Cache>> typeLoadInfo = new Cache>>( GetTypeLoadInfo ); + + static Dictionary> GetTypeLoadInfo( Type type ) + { + var ret = new Dictionary>(); + + foreach( var ff in type.GetFields() ) + { + var field = ff; + var load = field.GetCustomAttributes( false ); + var loadUsing = field.GetCustomAttributes( false ); + var fromYamlKey = field.GetCustomAttributes( false ); + if( loadUsing.Length != 0 ) + ret[ field ] = ( _1, fieldType, yaml ) => loadUsing[ 0 ].LoaderFunc( field )( yaml ); + else if( fromYamlKey.Length != 0 ) + ret[ field ] = ( f, ft, yaml ) => GetValue( f, ft, yaml.Value ); + else if( load.Length != 0 ) + ret[ field ] = null; + } + + if( ret.Count == 0 ) + foreach( var f in type.GetFields() ) + ret.Add( f, null ); + + return ret; + } + + [AttributeUsage( AttributeTargets.Field )] + public class LoadAttribute : Attribute { } + + [AttributeUsage( AttributeTargets.Field )] + public class LoadUsingAttribute : Attribute + { + Func loaderFuncCache; + public readonly string Loader; + + public LoadUsingAttribute( string loader ) + { + Loader = loader; + } + + internal Func LoaderFunc( FieldInfo field ) + { + const BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; + if( loaderFuncCache == null ) + loaderFuncCache = (Func)Delegate.CreateDelegate( typeof( Func ), field.DeclaringType.GetMethod( Loader, bf ) ); + return loaderFuncCache; + } + } + } + + public static class FieldSaver + { + public static MiniYaml Save(object o) + { + var nodes = new List(); + string root = null; + + foreach( var f in o.GetType().GetFields( BindingFlags.Public | BindingFlags.Instance ) ) + { + if( f.HasAttribute() ) + root = FormatValue( o, f ); + else + nodes.Add( new MiniYamlNode( f.Name, FormatValue( o, f ) ) ); + } + + return new MiniYaml( root, nodes ); + } + + public static MiniYaml SaveDifferences(object o, object from) + { + if (o.GetType() != from.GetType()) + throw new InvalidOperationException("FieldLoader: can't diff objects of different types"); + + var fields = o.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance) + .Where(f => FormatValue(o,f) != FormatValue(from,f)); + + return new MiniYaml( null, fields.Select( f => new MiniYamlNode( + f.Name, + FormatValue( o, f ) ) ).ToList() ); + } + + public static MiniYamlNode SaveField(object o, string field) + { + return new MiniYamlNode(field, FieldSaver.FormatValue( o, o.GetType().GetField(field) )); + } + + public static string FormatValue(object o, FieldInfo f) + { + var v = f.GetValue(o); + if (v == null) + return ""; + + // Color.ToString() does the wrong thing; force it to format as an array + if (f.FieldType == typeof(Color)) + { + var c = (Color)v; + return "{0},{1},{2},{3}".F(((int)c.A).Clamp(0, 255), + ((int)c.R).Clamp(0, 255), + ((int)c.G).Clamp(0, 255), + ((int)c.B).Clamp(0, 255)); + } + else if (f.FieldType == typeof(Rectangle)) + { + var r = (Rectangle)v; + return "{0},{1},{2},{3}".F(r.X, r.Y, r.Width, r.Height); + } + + return f.FieldType.IsArray + ? string.Join(",", ((Array)v).OfType().Select(a => a.ToString()).ToArray()) + : v.ToString(); + } + } + + public class FieldFromYamlKeyAttribute : Attribute { } +} diff --git a/OpenRA.FileFormats/FileFormats/AudLoader.cs b/OpenRA.FileFormats/FileFormats/AudLoader.cs index 2717945aa4..bfa0915784 100644 --- a/OpenRA.FileFormats/FileFormats/AudLoader.cs +++ b/OpenRA.FileFormats/FileFormats/AudLoader.cs @@ -1,155 +1,155 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.IO; - -namespace OpenRA.FileFormats -{ - [Flags] - enum SoundFlags - { - Stereo = 0x1, - _16Bit = 0x2, - } - - enum SoundFormat - { - WestwoodCompressed = 1, - ImaAdpcm = 99, - } - - struct Chunk - { - public int CompressedSize; - public int OutputSize; - - public static Chunk Read(BinaryReader r) - { - Chunk c; - c.CompressedSize = r.ReadUInt16(); - c.OutputSize = r.ReadUInt16(); - if (0xdeaf != r.ReadUInt32()) - throw new InvalidDataException("Chunk header is bogus"); - return c; - } - } - - public static class AudLoader - { - static int[] IndexAdjust = { -1, -1, -1, -1, 2, 4, 6, 8 }; - static int[] StepTable = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, - 17, 19, 21, 23, 25, 28, 31, 34, 37, - 41, 45, 50, 55, 60, 66, 73, 80, 88, - 97, 107, 118, 130, 143, 157, 173, 190, 209, - 230, 253, 279, 307, 337, 371, 408, 449, 494, - 544, 598, 658, 724, 796, 876, 963, 1060, 1166, - 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, - 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, - 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, - 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; - - static short DecodeSample(byte b, ref int index, ref int current) - { - var sb = (b & 8) != 0; - b &= 7; - - var delta = (StepTable[index] * b) / 4 + StepTable[index] / 8; - if (sb) delta = -delta; - - current += delta; - if (current > short.MaxValue) current = short.MaxValue; - if (current < short.MinValue) current = short.MinValue; - - index += IndexAdjust[b]; - if (index < 0) index = 0; - if (index > 88) index = 88; - - return (short)current; - } - - public static byte[] LoadSound(byte[] raw, ref int index) - { - var br = new BinaryReader(new MemoryStream(raw)); - var dataSize = raw.Length; - var outputSize = raw.Length * 4; - - var output = new byte[outputSize]; - var offset = 0; - var currentSample = 0; - - while (dataSize-- > 0) - { - var b = br.ReadByte(); - - var t = DecodeSample(b, ref index, ref currentSample); - output[offset++] = (byte)t; - output[offset++] = (byte)(t >> 8); - - t = DecodeSample((byte)(b >> 4), ref index, ref currentSample); - output[offset++] = (byte)t; - output[offset++] = (byte)(t >> 8); - } - - return output; - } - - public static float SoundLength(Stream s) - { - var br = new BinaryReader(s); - var sampleRate = br.ReadUInt16(); - /*var dataSize = */ br.ReadInt32(); - var outputSize = br.ReadInt32(); - var flags = (SoundFlags) br.ReadByte(); - - var samples = outputSize; - if (0 != (flags & SoundFlags.Stereo)) samples /= 2; - if (0 != (flags & SoundFlags._16Bit)) samples /= 2; - return samples / sampleRate; - } - - public static byte[] LoadSound(Stream s) - { - var br = new BinaryReader(s); - /*var sampleRate =*/ br.ReadUInt16(); - var dataSize = br.ReadInt32(); - var outputSize = br.ReadInt32(); - /*var flags = (SoundFlags)*/ br.ReadByte(); - /*var format = (SoundFormat)*/ br.ReadByte(); - - var output = new byte[outputSize]; - var offset = 0; - var index = 0; - var currentSample = 0; - - while (dataSize > 0) - { - var chunk = Chunk.Read(br); - for (int n = 0; n < chunk.CompressedSize; n++) - { - var b = br.ReadByte(); - - var t = DecodeSample(b, ref index, ref currentSample); - output[offset++] = (byte)t; - output[offset++] = (byte)(t >> 8); - - t = DecodeSample((byte)(b >> 4), ref index, ref currentSample); - output[offset++] = (byte)t; - output[offset++] = (byte)(t >> 8); - } - - dataSize -= 8 + chunk.CompressedSize; - } - - return output; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.IO; + +namespace OpenRA.FileFormats +{ + [Flags] + enum SoundFlags + { + Stereo = 0x1, + _16Bit = 0x2, + } + + enum SoundFormat + { + WestwoodCompressed = 1, + ImaAdpcm = 99, + } + + struct Chunk + { + public int CompressedSize; + public int OutputSize; + + public static Chunk Read(BinaryReader r) + { + Chunk c; + c.CompressedSize = r.ReadUInt16(); + c.OutputSize = r.ReadUInt16(); + if (0xdeaf != r.ReadUInt32()) + throw new InvalidDataException("Chunk header is bogus"); + return c; + } + } + + public static class AudLoader + { + static int[] IndexAdjust = { -1, -1, -1, -1, 2, 4, 6, 8 }; + static int[] StepTable = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, + 17, 19, 21, 23, 25, 28, 31, 34, 37, + 41, 45, 50, 55, 60, 66, 73, 80, 88, + 97, 107, 118, 130, 143, 157, 173, 190, 209, + 230, 253, 279, 307, 337, 371, 408, 449, 494, + 544, 598, 658, 724, 796, 876, 963, 1060, 1166, + 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, + 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, + 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, + 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; + + static short DecodeSample(byte b, ref int index, ref int current) + { + var sb = (b & 8) != 0; + b &= 7; + + var delta = (StepTable[index] * b) / 4 + StepTable[index] / 8; + if (sb) delta = -delta; + + current += delta; + if (current > short.MaxValue) current = short.MaxValue; + if (current < short.MinValue) current = short.MinValue; + + index += IndexAdjust[b]; + if (index < 0) index = 0; + if (index > 88) index = 88; + + return (short)current; + } + + public static byte[] LoadSound(byte[] raw, ref int index) + { + var br = new BinaryReader(new MemoryStream(raw)); + var dataSize = raw.Length; + var outputSize = raw.Length * 4; + + var output = new byte[outputSize]; + var offset = 0; + var currentSample = 0; + + while (dataSize-- > 0) + { + var b = br.ReadByte(); + + var t = DecodeSample(b, ref index, ref currentSample); + output[offset++] = (byte)t; + output[offset++] = (byte)(t >> 8); + + t = DecodeSample((byte)(b >> 4), ref index, ref currentSample); + output[offset++] = (byte)t; + output[offset++] = (byte)(t >> 8); + } + + return output; + } + + public static float SoundLength(Stream s) + { + var br = new BinaryReader(s); + var sampleRate = br.ReadUInt16(); + /*var dataSize = */ br.ReadInt32(); + var outputSize = br.ReadInt32(); + var flags = (SoundFlags) br.ReadByte(); + + var samples = outputSize; + if (0 != (flags & SoundFlags.Stereo)) samples /= 2; + if (0 != (flags & SoundFlags._16Bit)) samples /= 2; + return samples / sampleRate; + } + + public static byte[] LoadSound(Stream s) + { + var br = new BinaryReader(s); + /*var sampleRate =*/ br.ReadUInt16(); + var dataSize = br.ReadInt32(); + var outputSize = br.ReadInt32(); + /*var flags = (SoundFlags)*/ br.ReadByte(); + /*var format = (SoundFormat)*/ br.ReadByte(); + + var output = new byte[outputSize]; + var offset = 0; + var index = 0; + var currentSample = 0; + + while (dataSize > 0) + { + var chunk = Chunk.Read(br); + for (int n = 0; n < chunk.CompressedSize; n++) + { + var b = br.ReadByte(); + + var t = DecodeSample(b, ref index, ref currentSample); + output[offset++] = (byte)t; + output[offset++] = (byte)(t >> 8); + + t = DecodeSample((byte)(b >> 4), ref index, ref currentSample); + output[offset++] = (byte)t; + output[offset++] = (byte)(t >> 8); + } + + dataSize -= 8 + chunk.CompressedSize; + } + + return output; + } + } +} diff --git a/OpenRA.FileFormats/FileFormats/Blast.cs b/OpenRA.FileFormats/FileFormats/Blast.cs index 0e8bbee749..961287d5f6 100644 --- a/OpenRA.FileFormats/FileFormats/Blast.cs +++ b/OpenRA.FileFormats/FileFormats/Blast.cs @@ -1,274 +1,274 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - * - * This file is based on the blast routines (version 1.1 by Mark Adler) - * included in zlib/contrib - */ -#endregion - -using System; -using System.IO; - -namespace OpenRA.FileFormats -{ - public static class Blast - { - public static readonly int MAXBITS = 13; // maximum code length - public static readonly int MAXWIN = 4096; // maximum window size - - static byte[] litlen = new byte[] { - 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, - 10, 8, 12, 10, 12, 10, 8, 23, 8, 9, - 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, - 12, 11, 7, 9, 11, 12, 6, 7, 22, 5, - 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, - 38, 7, 9, 8, 25, 11, 8, 11, 9, 12, - 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, - 6, 21, 6, 10, 53, 8, 7, 24, 10, 27, - 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, - 12, 45, 12, 61, 12, 45, 44, 173 - }; - - // bit lengths of length codes 0..15 - static byte[] lenlen = new byte[] { 2, 35, 36, 53, 38, 23 }; - - // bit lengths of distance codes 0..63 - static byte[] distlen = new byte[] { 2, 20, 53, 230, 247, 151, 248 }; - - // base for length codes - static short[] lengthbase = new short[] { - 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, - 16, 24, 40, 72, 136, 264 - }; - - // extra bits for length codes - static byte[] extra = new byte[] { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, - 3, 4, 5, 6, 7, 8 - }; - - static Huffman litcode = new Huffman(litlen, litlen.Length, 256); - static Huffman lencode = new Huffman(lenlen, lenlen.Length, 16); - static Huffman distcode = new Huffman(distlen, distlen.Length, 64); - - // Decode PKWare Compression Library stream. - public static byte[] Decompress(byte[] src) - { - BitReader br = new BitReader(src); - - // Are literals coded? - int coded = br.ReadBits(8); - - if (coded < 0 || coded > 1) - throw new NotImplementedException("Invalid datastream"); - bool EncodedLiterals = (coded == 1); - - // log2(dictionary size) - 6 - int dict = br.ReadBits(8); - if (dict < 4 || dict > 6) - throw new InvalidDataException("Invalid dictionary size"); - - // output state - ushort next = 0; // index of next write location in out[] - bool first = true; // true to check distances (for first 4K) - byte[] outBuffer = new byte[MAXWIN]; // output buffer and sliding window - var ms = new MemoryStream(); - - // decode literals and length/distance pairs - do - { - // length/distance pair - if (br.ReadBits(1) == 1) - { - // Length - int symbol = Decode(lencode, br); - int len = lengthbase[symbol] + br.ReadBits(extra[symbol]); - if (len == 519) // Magic number for "done" - { - for (int i = 0; i < next; i++) - ms.WriteByte(outBuffer[i]); - break; - } - - // Distance - symbol = len == 2 ? 2 : dict; - int dist = Decode(distcode, br) << symbol; - dist += br.ReadBits(symbol); - dist++; - - if (first && dist > next) - throw new InvalidDataException("Attempt to jump before data"); - - // copy length bytes from distance bytes back - do - { - int dest = next; - int source = dest - dist; - - int copy = MAXWIN; - if (next < dist) - { - source += copy; - copy = dist; - } - - copy -= next; - if (copy > len) - copy = len; - - len -= copy; - next += (ushort)copy; - Array.Copy(outBuffer, source, outBuffer, dest, copy); - - // Flush window to outstream - if (next == MAXWIN) - { - for (int i = 0; i < next; i++) - ms.WriteByte(outBuffer[i]); - next = 0; - first = false; - } - } while (len != 0); - } - else // literal value - { - int symbol = EncodedLiterals ? Decode(litcode, br) : br.ReadBits(8); - outBuffer[next++] = (byte)symbol; - if (next == MAXWIN) - { - for (int i = 0; i < next; i++) - ms.WriteByte(outBuffer[i]); - next = 0; - first = false; - } - } - } while (true); - - return ms.ToArray(); - } - - // Decode a code using huffman table h. - private static int Decode(Huffman h, BitReader br) - { - int code = 0; // len bits being decoded - int first = 0; // first code of length len - int index = 0; // index of first code of length len in symbol table - short next = 1; - while (true) - { - code |= br.ReadBits(1) ^ 1; // invert code - int count = h.Count[next++]; - if (code < first + count) - return h.Symbol[index + (code - first)]; - - index += count; - first += count; - first <<= 1; - code <<= 1; - } - } - } - - class BitReader - { - readonly byte[] src; - int offset = 0; - int bitBuffer = 0; - int bitCount = 0; - - public BitReader(byte[] src) - { - this.src = src; - } - - public int ReadBits(int count) - { - int ret = 0; - int filled = 0; - while (filled < count) - { - if (bitCount == 0) - { - bitBuffer = src[offset++]; - bitCount = 8; - } - - ret |= (bitBuffer & 1) << filled; - bitBuffer >>= 1; - bitCount--; - filled++; - } - return ret; - } - } - - /* - * Given a list of repeated code lengths rep[0..n-1], where each byte is a - * count (high four bits + 1) and a code length (low four bits), generate the - * list of code lengths. This compaction reduces the size of the object code. - * Then given the list of code lengths length[0..n-1] representing a canonical - * Huffman code for n symbols, construct the tables required to decode those - * codes. Those tables are the number of codes of each length, and the symbols - * sorted by length, retaining their original order within each length. - */ - class Huffman - { - public short[] Count; // number of symbols of each length - public short[] Symbol; // canonically ordered symbols - - public Huffman(byte[] rep, int n, short SymbolCount) - { - short[] length = new short[256]; // code lengths - int s = 0; // current symbol - - // convert compact repeat counts into symbol bit length list - foreach (byte code in rep) - { - int num = (code >> 4) + 1; // Number of codes (top four bits plus 1) - byte len = (byte)(code & 15); // Code length (low four bits) - do - { - length[s++] = len; - } while (--num > 0); - } - n = s; - - // count number of codes of each length - Count = new short[Blast.MAXBITS + 1]; - for (int i = 0; i < n; i++) - Count[length[i]]++; - - // no codes! - if (Count[0] == n) - return; - - // check for an over-subscribed or incomplete set of lengths - int left = 1; // one possible code of zero length - for (int len = 1; len <= Blast.MAXBITS; len++) - { - left <<= 1; - // one more bit, double codes left - left -= Count[len]; - // deduct count from possible codes - if (left < 0) - throw new InvalidDataException ("over subscribed code set"); - } - - // generate offsets into symbol table for each length for sorting - short[] offs = new short[Blast.MAXBITS + 1]; - for (int len = 1; len < Blast.MAXBITS; len++) - offs[len + 1] = (short)(offs[len] + Count[len]); - - // put symbols in table sorted by length, by symbol order within each length - Symbol = new short[SymbolCount]; - for (short i = 0; i < n; i++) - if (length[i] != 0) - Symbol[offs[length[i]]++] = i; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + * + * This file is based on the blast routines (version 1.1 by Mark Adler) + * included in zlib/contrib + */ +#endregion + +using System; +using System.IO; + +namespace OpenRA.FileFormats +{ + public static class Blast + { + public static readonly int MAXBITS = 13; // maximum code length + public static readonly int MAXWIN = 4096; // maximum window size + + static byte[] litlen = new byte[] { + 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, + 10, 8, 12, 10, 12, 10, 8, 23, 8, 9, + 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, + 12, 11, 7, 9, 11, 12, 6, 7, 22, 5, + 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, + 38, 7, 9, 8, 25, 11, 8, 11, 9, 12, + 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, + 6, 21, 6, 10, 53, 8, 7, 24, 10, 27, + 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, + 12, 45, 12, 61, 12, 45, 44, 173 + }; + + // bit lengths of length codes 0..15 + static byte[] lenlen = new byte[] { 2, 35, 36, 53, 38, 23 }; + + // bit lengths of distance codes 0..63 + static byte[] distlen = new byte[] { 2, 20, 53, 230, 247, 151, 248 }; + + // base for length codes + static short[] lengthbase = new short[] { + 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, + 16, 24, 40, 72, 136, 264 + }; + + // extra bits for length codes + static byte[] extra = new byte[] { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, + 3, 4, 5, 6, 7, 8 + }; + + static Huffman litcode = new Huffman(litlen, litlen.Length, 256); + static Huffman lencode = new Huffman(lenlen, lenlen.Length, 16); + static Huffman distcode = new Huffman(distlen, distlen.Length, 64); + + // Decode PKWare Compression Library stream. + public static byte[] Decompress(byte[] src) + { + BitReader br = new BitReader(src); + + // Are literals coded? + int coded = br.ReadBits(8); + + if (coded < 0 || coded > 1) + throw new NotImplementedException("Invalid datastream"); + bool EncodedLiterals = (coded == 1); + + // log2(dictionary size) - 6 + int dict = br.ReadBits(8); + if (dict < 4 || dict > 6) + throw new InvalidDataException("Invalid dictionary size"); + + // output state + ushort next = 0; // index of next write location in out[] + bool first = true; // true to check distances (for first 4K) + byte[] outBuffer = new byte[MAXWIN]; // output buffer and sliding window + var ms = new MemoryStream(); + + // decode literals and length/distance pairs + do + { + // length/distance pair + if (br.ReadBits(1) == 1) + { + // Length + int symbol = Decode(lencode, br); + int len = lengthbase[symbol] + br.ReadBits(extra[symbol]); + if (len == 519) // Magic number for "done" + { + for (int i = 0; i < next; i++) + ms.WriteByte(outBuffer[i]); + break; + } + + // Distance + symbol = len == 2 ? 2 : dict; + int dist = Decode(distcode, br) << symbol; + dist += br.ReadBits(symbol); + dist++; + + if (first && dist > next) + throw new InvalidDataException("Attempt to jump before data"); + + // copy length bytes from distance bytes back + do + { + int dest = next; + int source = dest - dist; + + int copy = MAXWIN; + if (next < dist) + { + source += copy; + copy = dist; + } + + copy -= next; + if (copy > len) + copy = len; + + len -= copy; + next += (ushort)copy; + Array.Copy(outBuffer, source, outBuffer, dest, copy); + + // Flush window to outstream + if (next == MAXWIN) + { + for (int i = 0; i < next; i++) + ms.WriteByte(outBuffer[i]); + next = 0; + first = false; + } + } while (len != 0); + } + else // literal value + { + int symbol = EncodedLiterals ? Decode(litcode, br) : br.ReadBits(8); + outBuffer[next++] = (byte)symbol; + if (next == MAXWIN) + { + for (int i = 0; i < next; i++) + ms.WriteByte(outBuffer[i]); + next = 0; + first = false; + } + } + } while (true); + + return ms.ToArray(); + } + + // Decode a code using huffman table h. + private static int Decode(Huffman h, BitReader br) + { + int code = 0; // len bits being decoded + int first = 0; // first code of length len + int index = 0; // index of first code of length len in symbol table + short next = 1; + while (true) + { + code |= br.ReadBits(1) ^ 1; // invert code + int count = h.Count[next++]; + if (code < first + count) + return h.Symbol[index + (code - first)]; + + index += count; + first += count; + first <<= 1; + code <<= 1; + } + } + } + + class BitReader + { + readonly byte[] src; + int offset = 0; + int bitBuffer = 0; + int bitCount = 0; + + public BitReader(byte[] src) + { + this.src = src; + } + + public int ReadBits(int count) + { + int ret = 0; + int filled = 0; + while (filled < count) + { + if (bitCount == 0) + { + bitBuffer = src[offset++]; + bitCount = 8; + } + + ret |= (bitBuffer & 1) << filled; + bitBuffer >>= 1; + bitCount--; + filled++; + } + return ret; + } + } + + /* + * Given a list of repeated code lengths rep[0..n-1], where each byte is a + * count (high four bits + 1) and a code length (low four bits), generate the + * list of code lengths. This compaction reduces the size of the object code. + * Then given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. + */ + class Huffman + { + public short[] Count; // number of symbols of each length + public short[] Symbol; // canonically ordered symbols + + public Huffman(byte[] rep, int n, short SymbolCount) + { + short[] length = new short[256]; // code lengths + int s = 0; // current symbol + + // convert compact repeat counts into symbol bit length list + foreach (byte code in rep) + { + int num = (code >> 4) + 1; // Number of codes (top four bits plus 1) + byte len = (byte)(code & 15); // Code length (low four bits) + do + { + length[s++] = len; + } while (--num > 0); + } + n = s; + + // count number of codes of each length + Count = new short[Blast.MAXBITS + 1]; + for (int i = 0; i < n; i++) + Count[length[i]]++; + + // no codes! + if (Count[0] == n) + return; + + // check for an over-subscribed or incomplete set of lengths + int left = 1; // one possible code of zero length + for (int len = 1; len <= Blast.MAXBITS; len++) + { + left <<= 1; + // one more bit, double codes left + left -= Count[len]; + // deduct count from possible codes + if (left < 0) + throw new InvalidDataException ("over subscribed code set"); + } + + // generate offsets into symbol table for each length for sorting + short[] offs = new short[Blast.MAXBITS + 1]; + for (int len = 1; len < Blast.MAXBITS; len++) + offs[len + 1] = (short)(offs[len] + Count[len]); + + // put symbols in table sorted by length, by symbol order within each length + Symbol = new short[SymbolCount]; + for (short i = 0; i < n; i++) + if (length[i] != 0) + Symbol[offs[length[i]]++] = i; + } + } +} diff --git a/OpenRA.FileFormats/FileFormats/Blowfish.cs b/OpenRA.FileFormats/FileFormats/Blowfish.cs index a87a3fce58..2b4d415664 100644 --- a/OpenRA.FileFormats/FileFormats/Blowfish.cs +++ b/OpenRA.FileFormats/FileFormats/Blowfish.cs @@ -1,406 +1,406 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.FileFormats -{ - class Blowfish - { - public Blowfish(byte[] key) - { - for (int i = 0, j = 0; i < 18; ++i) - { - uint a = key[j++ % key.Length]; - uint b = key[j++ % key.Length]; - uint c = key[j++ % key.Length]; - uint d = key[j++ % key.Length]; - - m_p[i] ^= a << 24 | b << 16 | c << 8 | d; - } - - uint l = 0, r = 0; - - for (int i = 0; i < 18; ) - { - Encrypt(ref l, ref r); - m_p[i++] = l; - m_p[i++] = r; - } - - for (int i = 0; i < 4; ++i) - for (int j = 0; j < 256; ) - { - Encrypt(ref l, ref r); - m_s[i, j++] = l; - m_s[i, j++] = r; - } - } - - public uint[] Encrypt(uint[] data) { return RunCipher(data, Encrypt); } - public uint[] Decrypt(uint[] data) { return RunCipher(data, Decrypt); } - - delegate void CipherFunc( ref uint a, ref uint b ); - - uint[] RunCipher(uint[] data, CipherFunc f) - { - uint[] result = new uint[data.Length]; - - int size = data.Length / 2; - int i = 0; - while (size-- > 0) - { - uint a = SwapBytes(data[i]); - uint b = SwapBytes(data[i+1]); - - f(ref a, ref b); - - result[i++] = SwapBytes(a); - result[i++] = SwapBytes(b); - } - - return result; - } - - void Encrypt(ref uint a, ref uint b) - { - uint _a = a, _b = b; - _a ^= m_p[0]; - - bool x = false; - for( int i = 1; i <= 16; i++, x ^= true) - { - if (x) - Round(ref _a, _b, i); - else - Round(ref _b, _a, i); - } - _b ^= m_p[17]; - - a = _b; - b = _a; - } - - void Decrypt(ref uint a, ref uint b) - { - uint _a = a, _b = b; - _a ^= m_p[17]; - - bool x = false; - for (int i = 16; i >= 1; i--, x ^= true) - { - if (x) - Round(ref _a, _b, i); - else - Round(ref _b, _a, i); - } - _b ^= m_p[0]; - - a = _b; - b = _a; - } - - uint S(uint x, int i) - { - return m_s[i, (x >> ((3 - i) << 3)) & 0xff]; - } - - uint bf_f(uint x) - { - return ((S(x, 0) + S(x, 1)) ^ S(x, 2)) + S(x, 3); - } - - void Round(ref uint a, uint b, int n) - { - a ^= bf_f(b) ^ m_p[n]; - } - - uint SwapBytes(uint i) - { - i = (i << 16) | (i >> 16); - i = ((i << 8) & 0xff00ff00) | ((i >> 8) & 0x00ff00ff); - return i; - } - - uint[] m_p = new uint[] { - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, - 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, - 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, - 0x9216d5d9, 0x8979fb1b - }; - - uint[,] m_s = new uint[,] { - { - 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, - 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, - 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, - 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, - 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, - 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, - 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, - 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, - 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, - 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, - 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, - 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, - 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, - 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, - 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, - 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, - 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, - 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, - 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, - 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, - 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, - 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, - 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, - 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, - 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, - 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, - 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, - 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, - 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, - 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, - 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, - 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, - 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, - 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, - 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, - 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, - 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, - 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, - 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, - 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, - 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, - 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, - 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, - 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, - 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, - 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, - 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, - 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, - 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, - 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, - 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, - 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, - 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, - 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, - 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, - 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, - 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, - 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, - 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, - 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, - 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, - 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, - 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, - 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a - }, - { - 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, - 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, - 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, - 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, - 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, - 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, - 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, - 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, - 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, - 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, - 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, - 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, - 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, - 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, - 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, - 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, - 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, - 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, - 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, - 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, - 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, - 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, - 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, - 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, - 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, - 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, - 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, - 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, - 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, - 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, - 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, - 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, - 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, - 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, - 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, - 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, - 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, - 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, - 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, - 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, - 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, - 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, - 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, - 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, - 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, - 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, - 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, - 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, - 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, - 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, - 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, - 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, - 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, - 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, - 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, - 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, - 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, - 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, - 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, - 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, - 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, - 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, - 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, - 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 - }, - { - 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, - 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, - 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, - 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, - 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, - 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, - 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, - 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, - 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, - 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, - 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, - 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, - 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, - 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, - 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, - 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, - 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, - 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, - 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, - 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, - 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, - 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, - 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, - 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, - 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, - 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, - 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, - 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, - 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, - 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, - 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, - 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, - 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, - 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, - 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, - 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, - 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, - 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, - 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, - 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, - 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, - 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, - 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, - 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, - 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, - 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, - 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, - 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, - 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, - 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, - 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, - 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, - 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, - 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, - 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, - 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, - 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, - 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, - 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, - 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, - 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, - 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, - 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, - 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 - }, - { - 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, - 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, - 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, - 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, - 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, - 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, - 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, - 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, - 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, - 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, - 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, - 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, - 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, - 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, - 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, - 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, - 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, - 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, - 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, - 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, - 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, - 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, - 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, - 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, - 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, - 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, - 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, - 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, - 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, - 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, - 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, - 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, - 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, - 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, - 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, - 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, - 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, - 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, - 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, - 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, - 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, - 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, - 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, - 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, - 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, - 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, - 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, - 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, - 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, - 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, - 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, - 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, - 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, - 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, - 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, - 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, - 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, - 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, - 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, - 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, - 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, - 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, - 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, - 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 - } - - }; - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.FileFormats +{ + class Blowfish + { + public Blowfish(byte[] key) + { + for (int i = 0, j = 0; i < 18; ++i) + { + uint a = key[j++ % key.Length]; + uint b = key[j++ % key.Length]; + uint c = key[j++ % key.Length]; + uint d = key[j++ % key.Length]; + + m_p[i] ^= a << 24 | b << 16 | c << 8 | d; + } + + uint l = 0, r = 0; + + for (int i = 0; i < 18; ) + { + Encrypt(ref l, ref r); + m_p[i++] = l; + m_p[i++] = r; + } + + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 256; ) + { + Encrypt(ref l, ref r); + m_s[i, j++] = l; + m_s[i, j++] = r; + } + } + + public uint[] Encrypt(uint[] data) { return RunCipher(data, Encrypt); } + public uint[] Decrypt(uint[] data) { return RunCipher(data, Decrypt); } + + delegate void CipherFunc( ref uint a, ref uint b ); + + uint[] RunCipher(uint[] data, CipherFunc f) + { + uint[] result = new uint[data.Length]; + + int size = data.Length / 2; + int i = 0; + while (size-- > 0) + { + uint a = SwapBytes(data[i]); + uint b = SwapBytes(data[i+1]); + + f(ref a, ref b); + + result[i++] = SwapBytes(a); + result[i++] = SwapBytes(b); + } + + return result; + } + + void Encrypt(ref uint a, ref uint b) + { + uint _a = a, _b = b; + _a ^= m_p[0]; + + bool x = false; + for( int i = 1; i <= 16; i++, x ^= true) + { + if (x) + Round(ref _a, _b, i); + else + Round(ref _b, _a, i); + } + _b ^= m_p[17]; + + a = _b; + b = _a; + } + + void Decrypt(ref uint a, ref uint b) + { + uint _a = a, _b = b; + _a ^= m_p[17]; + + bool x = false; + for (int i = 16; i >= 1; i--, x ^= true) + { + if (x) + Round(ref _a, _b, i); + else + Round(ref _b, _a, i); + } + _b ^= m_p[0]; + + a = _b; + b = _a; + } + + uint S(uint x, int i) + { + return m_s[i, (x >> ((3 - i) << 3)) & 0xff]; + } + + uint bf_f(uint x) + { + return ((S(x, 0) + S(x, 1)) ^ S(x, 2)) + S(x, 3); + } + + void Round(ref uint a, uint b, int n) + { + a ^= bf_f(b) ^ m_p[n]; + } + + uint SwapBytes(uint i) + { + i = (i << 16) | (i >> 16); + i = ((i << 8) & 0xff00ff00) | ((i >> 8) & 0x00ff00ff); + return i; + } + + uint[] m_p = new uint[] { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b + }; + + uint[,] m_s = new uint[,] { + { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + }, + { + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + }, + { + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + }, + { + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + } + + }; + } +} diff --git a/OpenRA.FileFormats/FileFormats/BlowfishKeyProvider.cs b/OpenRA.FileFormats/FileFormats/BlowfishKeyProvider.cs index b4e0df0e9f..6ce863856a 100644 --- a/OpenRA.FileFormats/FileFormats/BlowfishKeyProvider.cs +++ b/OpenRA.FileFormats/FileFormats/BlowfishKeyProvider.cs @@ -1,528 +1,528 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; - -namespace OpenRA.FileFormats -{ - /* possibly the fugliest C# i've ever seen. */ - - class BlowfishKeyProvider - { - const string pubkeyStr = "AihRvNoIbTn85FZRYNZRcT+i6KpU+maCsEqr3Q5q+LDB5tH7Tz2qQ38V"; - - static sbyte[] char2num = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; - - class PublicKey - { - public uint[] key1 = new uint[64]; - public uint[] key2 = new uint[64]; - public uint len; - } - PublicKey pubkey = new PublicKey(); - - uint[] glob1 = new uint[64]; - uint glob1_bitlen, glob1_len_x2; - uint[] glob2 = new uint[130]; - uint[] glob1_hi = new uint[4]; - uint[] glob1_hi_inv = new uint[4]; - uint glob1_hi_bitlen; - uint glob1_hi_inv_lo, glob1_hi_inv_hi; - - void init_bignum(uint[] n, uint val, uint len) - { - for (int i = 0; i < len; i++) n[i] = 0; - n[0] = val; - } - - void move_key_to_big(uint[] n, byte[] key, uint klen, uint blen) - { - byte sign; - - if ((key[0] & 0x80) != 0) sign = 0xff; - else sign = 0; - - unsafe - { - fixed (uint* _pn = &n[0]) - { - byte* pn = (byte*)_pn; - uint i = blen * 4; - for (; i > klen; i--) pn[i - 1] = (byte)sign; - for (; i > 0; i--) pn[i - 1] = key[klen - i]; - } - } - } - - void key_to_bignum(uint[] n, byte[] key, uint len) - { - uint keylen; - int i; - - int j = 0; - - if (key[j] != 2) return; - j++; - - if ((key[j] & 0x80) != 0) - { - keylen = 0; - for (i = 0; i < (key[j] & 0x7f); i++) keylen = (keylen << 8) | key[j + i + 1]; - j += (key[j] & 0x7f) + 1; - } - else - { - keylen = key[j]; - j++; - } - if (keylen <= len * 4) - move_key_to_big(n, key.Skip(j).ToArray(), keylen, len); - } - - uint len_bignum(uint[] n, uint len) - { - uint i; - i = len - 1; - while ((i >= 0) && (n[i] == 0)) i--; - return i + 1; - } - - uint bitlen_bignum(uint[] n, uint len) - { - uint ddlen, bitlen, mask; - ddlen = len_bignum(n, len); - if (ddlen == 0) return 0; - bitlen = ddlen * 32; - mask = 0x80000000; - while ((mask & n[ddlen - 1]) == 0) - { - mask >>= 1; - bitlen--; - } - return bitlen; - } - - void init_pubkey() - { - int i = 0; - uint i2, tmp; - byte[] keytmp = new byte[256]; - - init_bignum(pubkey.key2, 0x10001, 64); - - i2 = 0; - while (i < pubkeyStr.Length) - { - tmp = (uint)char2num[pubkeyStr[i++]]; - tmp <<= 6; tmp |= (uint)(byte)char2num[pubkeyStr[i++]]; - tmp <<= 6; tmp |= (uint)(byte)char2num[pubkeyStr[i++]]; - tmp <<= 6; tmp |= (uint)(byte)char2num[pubkeyStr[i++]]; - keytmp[i2++] = (byte)((tmp >> 16) & 0xff); - keytmp[i2++] = (byte)((tmp >> 8) & 0xff); - keytmp[i2++] = (byte)(tmp & 0xff); - } - - key_to_bignum(pubkey.key1, keytmp, 64); - pubkey.len = bitlen_bignum(pubkey.key1, 64) - 1; - } - - uint len_predata() - { - uint a = (pubkey.len - 1) / 8; - return (55 / a + 1) * (a + 1); - } - - int cmp_bignum(uint[] n1, uint[] n2, uint len) - { - - while (len > 0) - { - --len; - if (n1[len] < n2[len]) return -1; - if (n1[len] > n2[len]) return 1; - } - return 0; - } - - void mov_bignum(uint[] dest, uint[] src, uint len) - { - Array.Copy(src, dest, len); - } - - void shr_bignum(uint[] n, int bits, int len) - { - int i; int i2 = bits / 32; - - if (i2 > 0) - { - for (i = 0; i < len - i2; i++) n[i] = n[i + i2]; - for (; i < len; i++) n[i] = 0; - bits = bits % 32; - } - if (bits == 0) return; - for (i = 0; i < len - 1; i++) n[i] = (n[i] >> bits) | (n[i + 1] << (32 - - bits)); - n[i] = n[i] >> bits; - } - - void shl_bignum(uint[] n, int bits, int len) - { - int i, i2; - - i2 = bits / 32; - if (i2 > 0) - { - for (i = len - 1; i > i2; i--) n[i] = n[i - i2]; - for (; i > 0; i--) n[i] = 0; - bits = bits % 32; - } - if (bits == 0) return; - for (i = len - 1; i > 0; i--) n[i] = (n[i] << bits) | (n[i - 1] >> (32 - - bits)); - n[0] <<= bits; - } - - uint sub_bignum(uint[] dest, uint[] src1, uint[] src2, uint carry, int len) - { - uint i1, i2; - - len += len; - unsafe - { - fixed (uint* _ps1 = &src1[0]) - fixed (uint* _ps2 = &src2[0]) - fixed (uint* _pd = &dest[0]) - { - ushort* ps1 = (ushort*)_ps1; - ushort* ps2 = (ushort*)_ps2; - ushort* pd = (ushort*)_pd; - - while (--len != -1) - { - i1 = *ps1++; - i2 = *ps2++; - *pd++ = (ushort)(i1 - i2 - carry); - if (((i1 - i2 - carry) & 0x10000) != 0) carry = 1; else carry = 0; - } - } - } - return carry; - } - - unsafe uint sub_bignum(uint* dest, uint* src1, uint* src2, uint carry, int len) - { - uint i1, i2; - - len += len; - - ushort* ps1 = (ushort*)src1; - ushort* ps2 = (ushort*)src2; - ushort* pd = (ushort*)dest; - - while (--len != -1) - { - i1 = *ps1++; - i2 = *ps2++; - *pd++ = (ushort)(i1 - i2 - carry); - if (((i1 - i2 - carry) & 0x10000) != 0) carry = 1; else carry = 0; - - } - return carry; - } - - void inv_bignum(uint[] n1, uint[] n2, uint len) - { - uint[] n_tmp = new uint[64]; - uint n2_bytelen, bit; - int n2_bitlen; - - int j = 0; - - init_bignum(n_tmp, 0, len); - init_bignum(n1, 0, len); - n2_bitlen = (int)bitlen_bignum(n2, len); - bit = ((uint)1) << (n2_bitlen % 32); - j = ((n2_bitlen + 32) / 32) - 1; - n2_bytelen = (uint)((n2_bitlen - 1) / 32) * 4; - n_tmp[n2_bytelen / 4] |= ((uint)1) << ((n2_bitlen - 1) & 0x1f); - - while (n2_bitlen > 0) - { - n2_bitlen--; - shl_bignum(n_tmp, 1, (int)len); - if (cmp_bignum(n_tmp, n2, len) != -1) - { - sub_bignum(n_tmp, n_tmp, n2, 0, (int)len); - n1[j] |= bit; - } - bit >>= 1; - if (bit == 0) - { - j--; - bit = 0x80000000; - } - } - init_bignum(n_tmp, 0, len); - } - - void inc_bignum(uint[] n, uint len) - { - int i = 0; - while ((++n[i] == 0) && (--len > 0)) i++; - } - - void init_two_dw(uint[] n, uint len) - { - mov_bignum(glob1, n, len); - glob1_bitlen = bitlen_bignum(glob1, len); - glob1_len_x2 = (glob1_bitlen + 15) / 16; - mov_bignum(glob1_hi, glob1.Skip((int)len_bignum(glob1, len) - 2).ToArray(), 2); - glob1_hi_bitlen = bitlen_bignum(glob1_hi, 2) - 32; - shr_bignum(glob1_hi, (int)glob1_hi_bitlen, 2); - inv_bignum(glob1_hi_inv, glob1_hi, 2); - shr_bignum(glob1_hi_inv, 1, 2); - glob1_hi_bitlen = (glob1_hi_bitlen + 15) % 16 + 1; - inc_bignum(glob1_hi_inv, 2); - if (bitlen_bignum(glob1_hi_inv, 2) > 32) - { - shr_bignum(glob1_hi_inv, 1, 2); - glob1_hi_bitlen--; - } - glob1_hi_inv_lo = (ushort)glob1_hi_inv[0]; - glob1_hi_inv_hi = (ushort)(glob1_hi_inv[0] >> 16); - } - - unsafe void mul_bignum_word(ushort *pn1, uint[] n2, uint mul, uint len) - { - uint i, tmp; - unsafe - { - fixed (uint* _pn2 = &n2[0]) - { - ushort* pn2 = (ushort*)_pn2; - - tmp = 0; - for (i = 0; i < len; i++) - { - tmp = mul * (*pn2) + (*pn1) + tmp; - *pn1 = (ushort)tmp; - pn1++; - pn2++; - tmp >>= 16; - } - *pn1 += (ushort)tmp; - } - } - } - - void mul_bignum(uint[] dest, uint[] src1, uint[] src2, uint len) - { - uint i; - - unsafe - { - fixed( uint * _psrc2 = &src2[0] ) - fixed(uint* _pdest = &dest[0]) - { - ushort* psrc2 = (ushort*)_psrc2; - ushort* pdest = (ushort*)_pdest; - - init_bignum(dest, 0, len * 2); - for (i = 0; i < len * 2; i++) - mul_bignum_word(pdest++, src1, *psrc2++, len * 2); - } - } - } - - void not_bignum(uint[] n, uint len) - { - uint i; - for (i = 0; i < len; i++) n[i] = ~n[i]; - } - - void neg_bignum(uint[] n, uint len) - { - not_bignum(n, len); - inc_bignum(n, len); - } - - unsafe uint get_mulword(uint* n) - { - ushort* wn = (ushort*)n; - uint i = (uint)((((((((((*(wn - 1) ^ 0xffff) & 0xffff) * glob1_hi_inv_lo + 0x10000) >> 1) - + (((*(wn - 2) ^ 0xffff) * glob1_hi_inv_hi + glob1_hi_inv_hi) >> 1) + 1) - >> 16) + ((((*(wn - 1) ^ 0xffff) & 0xffff) * glob1_hi_inv_hi) >> 1) + - (((*wn ^ 0xffff) * glob1_hi_inv_lo) >> 1) + 1) >> 14) + glob1_hi_inv_hi - * (*wn ^ 0xffff) * 2) >> (int)glob1_hi_bitlen); - if (i > 0xffff) i = 0xffff; - return i & 0xffff; - } - - void dec_bignum(uint[] n, uint len) - { - int i = 0; - while ((--n[i] == 0xffffffff) && (--len > 0)) - i++; - } - - void calc_a_bignum(uint[] n1, uint[] n2, uint[] n3, uint len) - { - uint g2_len_x2, len_diff; - unsafe - { - fixed( uint* g1 = &glob1[0]) - fixed (uint* g2 = &glob2[0]) - { - mul_bignum(glob2, n2, n3, len); - glob2[len * 2] = 0; - g2_len_x2 = len_bignum(glob2, len * 2 + 1) * 2; - if (g2_len_x2 >= glob1_len_x2) - { - inc_bignum(glob2, len * 2 + 1); - neg_bignum(glob2, len * 2 + 1); - len_diff = g2_len_x2 + 1 - glob1_len_x2; - ushort* esi = ((ushort*)g2) + (1 + g2_len_x2 - glob1_len_x2); - ushort* edi = ((ushort*)g2) + (g2_len_x2 + 1); - for (; len_diff != 0; len_diff--) - { - edi--; - uint tmp = get_mulword((uint*)edi); - esi--; - if (tmp > 0) - { - mul_bignum_word(esi, glob1, tmp, 2 * len); - if ((*edi & 0x8000) == 0) - { - if (0 != sub_bignum((uint*)esi, (uint*)esi, g1, 0, (int)len)) (*edi)--; - } - } - } - neg_bignum(glob2, len); - dec_bignum(glob2, len); - } - mov_bignum(n1, glob2, len); - } - } - } - - void clear_tmp_vars(uint len) - { - init_bignum(glob1, 0, len); - init_bignum(glob2, 0, len); - init_bignum(glob1_hi_inv, 0, 4); - init_bignum(glob1_hi, 0, 4); - glob1_bitlen = 0; - glob1_hi_bitlen = 0; - glob1_len_x2 = 0; - glob1_hi_inv_lo = 0; - glob1_hi_inv_hi = 0; - } - - void calc_a_key(uint[] n1, uint[] n2, uint[] n3, uint[] n4, uint len) - { - uint[] n_tmp = new uint[64]; - uint n3_len, n4_len; - int n3_bitlen; - uint bit_mask; - - unsafe - { - fixed (uint* _pn3 = &n3[0]) - { - uint* pn3 = _pn3; - - init_bignum(n1, 1, len); - n4_len = len_bignum(n4, len); - init_two_dw(n4, n4_len); - n3_bitlen = (int)bitlen_bignum(n3, n4_len); - n3_len = (uint)((n3_bitlen + 31) / 32); - bit_mask = (((uint)1) << ((n3_bitlen - 1) % 32)) >> 1; - pn3 += n3_len - 1; - n3_bitlen--; - mov_bignum(n1, n2, n4_len); - while (--n3_bitlen != -1) - { - if (bit_mask == 0) - { - bit_mask = 0x80000000; - pn3--; - } - calc_a_bignum(n_tmp, n1, n1, n4_len); - if ((*pn3 & bit_mask) != 0) - calc_a_bignum(n1, n_tmp, n2, n4_len); - else - mov_bignum(n1, n_tmp, n4_len); - bit_mask >>= 1; - } - init_bignum(n_tmp, 0, n4_len); - clear_tmp_vars(len); - } - } - } - - unsafe void memcpy(byte* dest, byte* src, int len) - { - while (len-- != 0) *dest++ = *src++; - } - - unsafe void process_predata(byte* pre, uint pre_len, byte *buf) - { - uint[] n2 = new uint[64]; - uint[] n3 = new uint[64]; - - uint a = (pubkey.len - 1) / 8; - while (a + 1 <= pre_len) - { - init_bignum(n2, 0, 64); - fixed( uint * pn2 = &n2[0] ) - memcpy((byte *)pn2, pre, (int)a + 1); - calc_a_key(n3, n2, pubkey.key2, pubkey.key1, 64); - - fixed( uint * pn3 = &n3[0] ) - memcpy(buf, (byte *)pn3, (int)a); - - pre_len -= a + 1; - pre += a + 1; - buf += a; - } - } - - public byte[] DecryptKey(byte[] src) - { - init_pubkey(); - byte[] dest = new byte[256]; - - unsafe - { - fixed (byte* pdest = &dest[0]) - fixed (byte* psrc = &src[0]) - process_predata(psrc, len_predata(), pdest); - } - return dest.Take(56).ToArray(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; + +namespace OpenRA.FileFormats +{ + /* possibly the fugliest C# i've ever seen. */ + + class BlowfishKeyProvider + { + const string pubkeyStr = "AihRvNoIbTn85FZRYNZRcT+i6KpU+maCsEqr3Q5q+LDB5tH7Tz2qQ38V"; + + static sbyte[] char2num = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + + class PublicKey + { + public uint[] key1 = new uint[64]; + public uint[] key2 = new uint[64]; + public uint len; + } + PublicKey pubkey = new PublicKey(); + + uint[] glob1 = new uint[64]; + uint glob1_bitlen, glob1_len_x2; + uint[] glob2 = new uint[130]; + uint[] glob1_hi = new uint[4]; + uint[] glob1_hi_inv = new uint[4]; + uint glob1_hi_bitlen; + uint glob1_hi_inv_lo, glob1_hi_inv_hi; + + void init_bignum(uint[] n, uint val, uint len) + { + for (int i = 0; i < len; i++) n[i] = 0; + n[0] = val; + } + + void move_key_to_big(uint[] n, byte[] key, uint klen, uint blen) + { + byte sign; + + if ((key[0] & 0x80) != 0) sign = 0xff; + else sign = 0; + + unsafe + { + fixed (uint* _pn = &n[0]) + { + byte* pn = (byte*)_pn; + uint i = blen * 4; + for (; i > klen; i--) pn[i - 1] = (byte)sign; + for (; i > 0; i--) pn[i - 1] = key[klen - i]; + } + } + } + + void key_to_bignum(uint[] n, byte[] key, uint len) + { + uint keylen; + int i; + + int j = 0; + + if (key[j] != 2) return; + j++; + + if ((key[j] & 0x80) != 0) + { + keylen = 0; + for (i = 0; i < (key[j] & 0x7f); i++) keylen = (keylen << 8) | key[j + i + 1]; + j += (key[j] & 0x7f) + 1; + } + else + { + keylen = key[j]; + j++; + } + if (keylen <= len * 4) + move_key_to_big(n, key.Skip(j).ToArray(), keylen, len); + } + + uint len_bignum(uint[] n, uint len) + { + uint i; + i = len - 1; + while ((i >= 0) && (n[i] == 0)) i--; + return i + 1; + } + + uint bitlen_bignum(uint[] n, uint len) + { + uint ddlen, bitlen, mask; + ddlen = len_bignum(n, len); + if (ddlen == 0) return 0; + bitlen = ddlen * 32; + mask = 0x80000000; + while ((mask & n[ddlen - 1]) == 0) + { + mask >>= 1; + bitlen--; + } + return bitlen; + } + + void init_pubkey() + { + int i = 0; + uint i2, tmp; + byte[] keytmp = new byte[256]; + + init_bignum(pubkey.key2, 0x10001, 64); + + i2 = 0; + while (i < pubkeyStr.Length) + { + tmp = (uint)char2num[pubkeyStr[i++]]; + tmp <<= 6; tmp |= (uint)(byte)char2num[pubkeyStr[i++]]; + tmp <<= 6; tmp |= (uint)(byte)char2num[pubkeyStr[i++]]; + tmp <<= 6; tmp |= (uint)(byte)char2num[pubkeyStr[i++]]; + keytmp[i2++] = (byte)((tmp >> 16) & 0xff); + keytmp[i2++] = (byte)((tmp >> 8) & 0xff); + keytmp[i2++] = (byte)(tmp & 0xff); + } + + key_to_bignum(pubkey.key1, keytmp, 64); + pubkey.len = bitlen_bignum(pubkey.key1, 64) - 1; + } + + uint len_predata() + { + uint a = (pubkey.len - 1) / 8; + return (55 / a + 1) * (a + 1); + } + + int cmp_bignum(uint[] n1, uint[] n2, uint len) + { + + while (len > 0) + { + --len; + if (n1[len] < n2[len]) return -1; + if (n1[len] > n2[len]) return 1; + } + return 0; + } + + void mov_bignum(uint[] dest, uint[] src, uint len) + { + Array.Copy(src, dest, len); + } + + void shr_bignum(uint[] n, int bits, int len) + { + int i; int i2 = bits / 32; + + if (i2 > 0) + { + for (i = 0; i < len - i2; i++) n[i] = n[i + i2]; + for (; i < len; i++) n[i] = 0; + bits = bits % 32; + } + if (bits == 0) return; + for (i = 0; i < len - 1; i++) n[i] = (n[i] >> bits) | (n[i + 1] << (32 - + bits)); + n[i] = n[i] >> bits; + } + + void shl_bignum(uint[] n, int bits, int len) + { + int i, i2; + + i2 = bits / 32; + if (i2 > 0) + { + for (i = len - 1; i > i2; i--) n[i] = n[i - i2]; + for (; i > 0; i--) n[i] = 0; + bits = bits % 32; + } + if (bits == 0) return; + for (i = len - 1; i > 0; i--) n[i] = (n[i] << bits) | (n[i - 1] >> (32 - + bits)); + n[0] <<= bits; + } + + uint sub_bignum(uint[] dest, uint[] src1, uint[] src2, uint carry, int len) + { + uint i1, i2; + + len += len; + unsafe + { + fixed (uint* _ps1 = &src1[0]) + fixed (uint* _ps2 = &src2[0]) + fixed (uint* _pd = &dest[0]) + { + ushort* ps1 = (ushort*)_ps1; + ushort* ps2 = (ushort*)_ps2; + ushort* pd = (ushort*)_pd; + + while (--len != -1) + { + i1 = *ps1++; + i2 = *ps2++; + *pd++ = (ushort)(i1 - i2 - carry); + if (((i1 - i2 - carry) & 0x10000) != 0) carry = 1; else carry = 0; + } + } + } + return carry; + } + + unsafe uint sub_bignum(uint* dest, uint* src1, uint* src2, uint carry, int len) + { + uint i1, i2; + + len += len; + + ushort* ps1 = (ushort*)src1; + ushort* ps2 = (ushort*)src2; + ushort* pd = (ushort*)dest; + + while (--len != -1) + { + i1 = *ps1++; + i2 = *ps2++; + *pd++ = (ushort)(i1 - i2 - carry); + if (((i1 - i2 - carry) & 0x10000) != 0) carry = 1; else carry = 0; + + } + return carry; + } + + void inv_bignum(uint[] n1, uint[] n2, uint len) + { + uint[] n_tmp = new uint[64]; + uint n2_bytelen, bit; + int n2_bitlen; + + int j = 0; + + init_bignum(n_tmp, 0, len); + init_bignum(n1, 0, len); + n2_bitlen = (int)bitlen_bignum(n2, len); + bit = ((uint)1) << (n2_bitlen % 32); + j = ((n2_bitlen + 32) / 32) - 1; + n2_bytelen = (uint)((n2_bitlen - 1) / 32) * 4; + n_tmp[n2_bytelen / 4] |= ((uint)1) << ((n2_bitlen - 1) & 0x1f); + + while (n2_bitlen > 0) + { + n2_bitlen--; + shl_bignum(n_tmp, 1, (int)len); + if (cmp_bignum(n_tmp, n2, len) != -1) + { + sub_bignum(n_tmp, n_tmp, n2, 0, (int)len); + n1[j] |= bit; + } + bit >>= 1; + if (bit == 0) + { + j--; + bit = 0x80000000; + } + } + init_bignum(n_tmp, 0, len); + } + + void inc_bignum(uint[] n, uint len) + { + int i = 0; + while ((++n[i] == 0) && (--len > 0)) i++; + } + + void init_two_dw(uint[] n, uint len) + { + mov_bignum(glob1, n, len); + glob1_bitlen = bitlen_bignum(glob1, len); + glob1_len_x2 = (glob1_bitlen + 15) / 16; + mov_bignum(glob1_hi, glob1.Skip((int)len_bignum(glob1, len) - 2).ToArray(), 2); + glob1_hi_bitlen = bitlen_bignum(glob1_hi, 2) - 32; + shr_bignum(glob1_hi, (int)glob1_hi_bitlen, 2); + inv_bignum(glob1_hi_inv, glob1_hi, 2); + shr_bignum(glob1_hi_inv, 1, 2); + glob1_hi_bitlen = (glob1_hi_bitlen + 15) % 16 + 1; + inc_bignum(glob1_hi_inv, 2); + if (bitlen_bignum(glob1_hi_inv, 2) > 32) + { + shr_bignum(glob1_hi_inv, 1, 2); + glob1_hi_bitlen--; + } + glob1_hi_inv_lo = (ushort)glob1_hi_inv[0]; + glob1_hi_inv_hi = (ushort)(glob1_hi_inv[0] >> 16); + } + + unsafe void mul_bignum_word(ushort *pn1, uint[] n2, uint mul, uint len) + { + uint i, tmp; + unsafe + { + fixed (uint* _pn2 = &n2[0]) + { + ushort* pn2 = (ushort*)_pn2; + + tmp = 0; + for (i = 0; i < len; i++) + { + tmp = mul * (*pn2) + (*pn1) + tmp; + *pn1 = (ushort)tmp; + pn1++; + pn2++; + tmp >>= 16; + } + *pn1 += (ushort)tmp; + } + } + } + + void mul_bignum(uint[] dest, uint[] src1, uint[] src2, uint len) + { + uint i; + + unsafe + { + fixed( uint * _psrc2 = &src2[0] ) + fixed(uint* _pdest = &dest[0]) + { + ushort* psrc2 = (ushort*)_psrc2; + ushort* pdest = (ushort*)_pdest; + + init_bignum(dest, 0, len * 2); + for (i = 0; i < len * 2; i++) + mul_bignum_word(pdest++, src1, *psrc2++, len * 2); + } + } + } + + void not_bignum(uint[] n, uint len) + { + uint i; + for (i = 0; i < len; i++) n[i] = ~n[i]; + } + + void neg_bignum(uint[] n, uint len) + { + not_bignum(n, len); + inc_bignum(n, len); + } + + unsafe uint get_mulword(uint* n) + { + ushort* wn = (ushort*)n; + uint i = (uint)((((((((((*(wn - 1) ^ 0xffff) & 0xffff) * glob1_hi_inv_lo + 0x10000) >> 1) + + (((*(wn - 2) ^ 0xffff) * glob1_hi_inv_hi + glob1_hi_inv_hi) >> 1) + 1) + >> 16) + ((((*(wn - 1) ^ 0xffff) & 0xffff) * glob1_hi_inv_hi) >> 1) + + (((*wn ^ 0xffff) * glob1_hi_inv_lo) >> 1) + 1) >> 14) + glob1_hi_inv_hi + * (*wn ^ 0xffff) * 2) >> (int)glob1_hi_bitlen); + if (i > 0xffff) i = 0xffff; + return i & 0xffff; + } + + void dec_bignum(uint[] n, uint len) + { + int i = 0; + while ((--n[i] == 0xffffffff) && (--len > 0)) + i++; + } + + void calc_a_bignum(uint[] n1, uint[] n2, uint[] n3, uint len) + { + uint g2_len_x2, len_diff; + unsafe + { + fixed( uint* g1 = &glob1[0]) + fixed (uint* g2 = &glob2[0]) + { + mul_bignum(glob2, n2, n3, len); + glob2[len * 2] = 0; + g2_len_x2 = len_bignum(glob2, len * 2 + 1) * 2; + if (g2_len_x2 >= glob1_len_x2) + { + inc_bignum(glob2, len * 2 + 1); + neg_bignum(glob2, len * 2 + 1); + len_diff = g2_len_x2 + 1 - glob1_len_x2; + ushort* esi = ((ushort*)g2) + (1 + g2_len_x2 - glob1_len_x2); + ushort* edi = ((ushort*)g2) + (g2_len_x2 + 1); + for (; len_diff != 0; len_diff--) + { + edi--; + uint tmp = get_mulword((uint*)edi); + esi--; + if (tmp > 0) + { + mul_bignum_word(esi, glob1, tmp, 2 * len); + if ((*edi & 0x8000) == 0) + { + if (0 != sub_bignum((uint*)esi, (uint*)esi, g1, 0, (int)len)) (*edi)--; + } + } + } + neg_bignum(glob2, len); + dec_bignum(glob2, len); + } + mov_bignum(n1, glob2, len); + } + } + } + + void clear_tmp_vars(uint len) + { + init_bignum(glob1, 0, len); + init_bignum(glob2, 0, len); + init_bignum(glob1_hi_inv, 0, 4); + init_bignum(glob1_hi, 0, 4); + glob1_bitlen = 0; + glob1_hi_bitlen = 0; + glob1_len_x2 = 0; + glob1_hi_inv_lo = 0; + glob1_hi_inv_hi = 0; + } + + void calc_a_key(uint[] n1, uint[] n2, uint[] n3, uint[] n4, uint len) + { + uint[] n_tmp = new uint[64]; + uint n3_len, n4_len; + int n3_bitlen; + uint bit_mask; + + unsafe + { + fixed (uint* _pn3 = &n3[0]) + { + uint* pn3 = _pn3; + + init_bignum(n1, 1, len); + n4_len = len_bignum(n4, len); + init_two_dw(n4, n4_len); + n3_bitlen = (int)bitlen_bignum(n3, n4_len); + n3_len = (uint)((n3_bitlen + 31) / 32); + bit_mask = (((uint)1) << ((n3_bitlen - 1) % 32)) >> 1; + pn3 += n3_len - 1; + n3_bitlen--; + mov_bignum(n1, n2, n4_len); + while (--n3_bitlen != -1) + { + if (bit_mask == 0) + { + bit_mask = 0x80000000; + pn3--; + } + calc_a_bignum(n_tmp, n1, n1, n4_len); + if ((*pn3 & bit_mask) != 0) + calc_a_bignum(n1, n_tmp, n2, n4_len); + else + mov_bignum(n1, n_tmp, n4_len); + bit_mask >>= 1; + } + init_bignum(n_tmp, 0, n4_len); + clear_tmp_vars(len); + } + } + } + + unsafe void memcpy(byte* dest, byte* src, int len) + { + while (len-- != 0) *dest++ = *src++; + } + + unsafe void process_predata(byte* pre, uint pre_len, byte *buf) + { + uint[] n2 = new uint[64]; + uint[] n3 = new uint[64]; + + uint a = (pubkey.len - 1) / 8; + while (a + 1 <= pre_len) + { + init_bignum(n2, 0, 64); + fixed( uint * pn2 = &n2[0] ) + memcpy((byte *)pn2, pre, (int)a + 1); + calc_a_key(n3, n2, pubkey.key2, pubkey.key1, 64); + + fixed( uint * pn3 = &n3[0] ) + memcpy(buf, (byte *)pn3, (int)a); + + pre_len -= a + 1; + pre += a + 1; + buf += a; + } + } + + public byte[] DecryptKey(byte[] src) + { + init_pubkey(); + byte[] dest = new byte[256]; + + unsafe + { + fixed (byte* pdest = &dest[0]) + fixed (byte* psrc = &src[0]) + process_predata(psrc, len_predata(), pdest); + } + return dest.Take(56).ToArray(); + } + } +} diff --git a/OpenRA.FileFormats/FileFormats/Format2.cs b/OpenRA.FileFormats/FileFormats/Format2.cs index 602b626c1d..5989e4fc92 100644 --- a/OpenRA.FileFormats/FileFormats/Format2.cs +++ b/OpenRA.FileFormats/FileFormats/Format2.cs @@ -1,36 +1,36 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.FileFormats -{ - public static class Format2 - { - public static int DecodeInto(byte[] src, byte[] dest) - { - FastByteReader r = new FastByteReader(src); - - int i = 0; - while (!r.Done()) - { - byte cmd = r.ReadByte(); - if (cmd == 0) - { - byte count = r.ReadByte(); - while (count-- > 0) - dest[i++] = 0; - } - else - dest[i++] = cmd; - } - - return i; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.FileFormats +{ + public static class Format2 + { + public static int DecodeInto(byte[] src, byte[] dest) + { + FastByteReader r = new FastByteReader(src); + + int i = 0; + while (!r.Done()) + { + byte cmd = r.ReadByte(); + if (cmd == 0) + { + byte count = r.ReadByte(); + while (count-- > 0) + dest[i++] = 0; + } + else + dest[i++] = cmd; + } + + return i; + } + } +} diff --git a/OpenRA.FileFormats/FileFormats/Format40.cs b/OpenRA.FileFormats/FileFormats/Format40.cs index dd7ea3df34..78dacf4c45 100644 --- a/OpenRA.FileFormats/FileFormats/Format40.cs +++ b/OpenRA.FileFormats/FileFormats/Format40.cs @@ -1,78 +1,78 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.FileFormats -{ - public static class Format40 - { - public static int DecodeInto( byte[] src, byte[] dest ) - { - var ctx = new FastByteReader(src); - int destIndex = 0; - - while( true ) - { - byte i = ctx.ReadByte(); - if( ( i & 0x80 ) == 0 ) - { - int count = i & 0x7F; - if( count == 0 ) - { - // case 6 - count = ctx.ReadByte(); - byte value = ctx.ReadByte(); - for( int end = destIndex + count ; destIndex < end ; destIndex++ ) - dest[ destIndex ] ^= value; - } - else - { - // case 5 - for( int end = destIndex + count ; destIndex < end ; destIndex++ ) - dest[destIndex] ^= ctx.ReadByte(); - } - } - else - { - int count = i & 0x7F; - if( count == 0 ) - { - count = ctx.ReadWord(); - if( count == 0 ) - return destIndex; - - if( ( count & 0x8000 ) == 0 ) - { - // case 2 - destIndex += ( count & 0x7FFF ); - } - else if( ( count & 0x4000 ) == 0 ) - { - // case 3 - for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ ) - dest[destIndex] ^= ctx.ReadByte(); - } - else - { - // case 4 - byte value = ctx.ReadByte(); - for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ ) - dest[ destIndex ] ^= value; - } - } - else - { - // case 1 - destIndex += count; - } - } - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.FileFormats +{ + public static class Format40 + { + public static int DecodeInto( byte[] src, byte[] dest ) + { + var ctx = new FastByteReader(src); + int destIndex = 0; + + while( true ) + { + byte i = ctx.ReadByte(); + if( ( i & 0x80 ) == 0 ) + { + int count = i & 0x7F; + if( count == 0 ) + { + // case 6 + count = ctx.ReadByte(); + byte value = ctx.ReadByte(); + for( int end = destIndex + count ; destIndex < end ; destIndex++ ) + dest[ destIndex ] ^= value; + } + else + { + // case 5 + for( int end = destIndex + count ; destIndex < end ; destIndex++ ) + dest[destIndex] ^= ctx.ReadByte(); + } + } + else + { + int count = i & 0x7F; + if( count == 0 ) + { + count = ctx.ReadWord(); + if( count == 0 ) + return destIndex; + + if( ( count & 0x8000 ) == 0 ) + { + // case 2 + destIndex += ( count & 0x7FFF ); + } + else if( ( count & 0x4000 ) == 0 ) + { + // case 3 + for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ ) + dest[destIndex] ^= ctx.ReadByte(); + } + else + { + // case 4 + byte value = ctx.ReadByte(); + for( int end = destIndex + ( count & 0x3FFF ) ; destIndex < end ; destIndex++ ) + dest[ destIndex ] ^= value; + } + } + else + { + // case 1 + destIndex += count; + } + } + } + } + } +} diff --git a/OpenRA.FileFormats/FileFormats/Format80.cs b/OpenRA.FileFormats/FileFormats/Format80.cs index 8dcc9ad6ac..a61f0abbd4 100644 --- a/OpenRA.FileFormats/FileFormats/Format80.cs +++ b/OpenRA.FileFormats/FileFormats/Format80.cs @@ -1,150 +1,150 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.IO; - -namespace OpenRA.FileFormats -{ - class FastByteReader - { - readonly byte[] src; - int offset = 0; - - public FastByteReader(byte[] src) - { - this.src = src; - } - - public bool Done() { return offset >= src.Length; } - public byte ReadByte() { return src[offset++]; } - public int ReadWord() - { - int x = ReadByte(); - return x | (ReadByte() << 8); - } - - public void CopyTo(byte[] dest, int offset, int count) - { - Array.Copy(src, this.offset, dest, offset, count); - this.offset += count; - } - - public int Remaining() { return src.Length - offset; } - } - - public static class Format80 - { - static void ReplicatePrevious( byte[] dest, int destIndex, int srcIndex, int count ) - { - if( srcIndex > destIndex ) - throw new NotImplementedException( string.Format( "srcIndex > destIndex {0} {1}", srcIndex, destIndex ) ); - - if( destIndex - srcIndex == 1 ) - { - for( int i = 0 ; i < count ; i++ ) - dest[ destIndex + i ] = dest[ destIndex - 1 ]; - } - else - { - for( int i = 0 ; i < count ; i++ ) - dest[ destIndex + i ] = dest[ srcIndex + i ]; - } - } - - public static int DecodeInto( byte[] src, byte[] dest ) - { - var ctx = new FastByteReader(src); - int destIndex = 0; - - while( true ) - { - byte i = ctx.ReadByte(); - if( ( i & 0x80 ) == 0 ) - { - // case 2 - byte secondByte = ctx.ReadByte(); - int count = ( ( i & 0x70 ) >> 4 ) + 3; - int rpos = ( ( i & 0xf ) << 8 ) + secondByte; - - ReplicatePrevious( dest, destIndex, destIndex - rpos, count ); - destIndex += count; - } - else if( ( i & 0x40 ) == 0 ) - { - // case 1 - int count = i & 0x3F; - if( count == 0 ) - return destIndex; - - ctx.CopyTo( dest, destIndex, count ); - destIndex += count; - } - else - { - int count3 = i & 0x3F; - if( count3 == 0x3E ) - { - // case 4 - int count = ctx.ReadWord(); - byte color = ctx.ReadByte(); - - for( int end = destIndex + count ; destIndex < end ; destIndex++ ) - dest[ destIndex ] = color; - } - else if( count3 == 0x3F ) - { - // case 5 - int count = ctx.ReadWord(); - int srcIndex = ctx.ReadWord(); - if( srcIndex >= destIndex ) - throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) ); - - for( int end = destIndex + count ; destIndex < end ; destIndex++ ) - dest[ destIndex ] = dest[ srcIndex++ ]; - } - else - { - // case 3 - int count = count3 + 3; - int srcIndex = ctx.ReadWord(); - if( srcIndex >= destIndex ) - throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) ); - - for( int end = destIndex + count ; destIndex < end ; destIndex++ ) - dest[ destIndex ] = dest[ srcIndex++ ]; - } - } - } - } - - public static byte[] Encode(byte[] src) - { - /* quick & dirty format80 encoder -- only uses raw copy operator, terminated with a zero-run. */ - /* this does not produce good compression, but it's valid format80 */ - - var ctx = new FastByteReader(src); - var ms = new MemoryStream(); - - do - { - var len = Math.Min(ctx.Remaining(), 0x3F); - ms.WriteByte((byte)(0x80 | len)); - while (len-- > 0) - ms.WriteByte(ctx.ReadByte()); - } - while (!ctx.Done()); - - ms.WriteByte(0x80); // terminator -- 0-length run. - - return ms.ToArray(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.IO; + +namespace OpenRA.FileFormats +{ + class FastByteReader + { + readonly byte[] src; + int offset = 0; + + public FastByteReader(byte[] src) + { + this.src = src; + } + + public bool Done() { return offset >= src.Length; } + public byte ReadByte() { return src[offset++]; } + public int ReadWord() + { + int x = ReadByte(); + return x | (ReadByte() << 8); + } + + public void CopyTo(byte[] dest, int offset, int count) + { + Array.Copy(src, this.offset, dest, offset, count); + this.offset += count; + } + + public int Remaining() { return src.Length - offset; } + } + + public static class Format80 + { + static void ReplicatePrevious( byte[] dest, int destIndex, int srcIndex, int count ) + { + if( srcIndex > destIndex ) + throw new NotImplementedException( string.Format( "srcIndex > destIndex {0} {1}", srcIndex, destIndex ) ); + + if( destIndex - srcIndex == 1 ) + { + for( int i = 0 ; i < count ; i++ ) + dest[ destIndex + i ] = dest[ destIndex - 1 ]; + } + else + { + for( int i = 0 ; i < count ; i++ ) + dest[ destIndex + i ] = dest[ srcIndex + i ]; + } + } + + public static int DecodeInto( byte[] src, byte[] dest ) + { + var ctx = new FastByteReader(src); + int destIndex = 0; + + while( true ) + { + byte i = ctx.ReadByte(); + if( ( i & 0x80 ) == 0 ) + { + // case 2 + byte secondByte = ctx.ReadByte(); + int count = ( ( i & 0x70 ) >> 4 ) + 3; + int rpos = ( ( i & 0xf ) << 8 ) + secondByte; + + ReplicatePrevious( dest, destIndex, destIndex - rpos, count ); + destIndex += count; + } + else if( ( i & 0x40 ) == 0 ) + { + // case 1 + int count = i & 0x3F; + if( count == 0 ) + return destIndex; + + ctx.CopyTo( dest, destIndex, count ); + destIndex += count; + } + else + { + int count3 = i & 0x3F; + if( count3 == 0x3E ) + { + // case 4 + int count = ctx.ReadWord(); + byte color = ctx.ReadByte(); + + for( int end = destIndex + count ; destIndex < end ; destIndex++ ) + dest[ destIndex ] = color; + } + else if( count3 == 0x3F ) + { + // case 5 + int count = ctx.ReadWord(); + int srcIndex = ctx.ReadWord(); + if( srcIndex >= destIndex ) + throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) ); + + for( int end = destIndex + count ; destIndex < end ; destIndex++ ) + dest[ destIndex ] = dest[ srcIndex++ ]; + } + else + { + // case 3 + int count = count3 + 3; + int srcIndex = ctx.ReadWord(); + if( srcIndex >= destIndex ) + throw new NotImplementedException( string.Format( "srcIndex >= destIndex {0} {1}", srcIndex, destIndex ) ); + + for( int end = destIndex + count ; destIndex < end ; destIndex++ ) + dest[ destIndex ] = dest[ srcIndex++ ]; + } + } + } + } + + public static byte[] Encode(byte[] src) + { + /* quick & dirty format80 encoder -- only uses raw copy operator, terminated with a zero-run. */ + /* this does not produce good compression, but it's valid format80 */ + + var ctx = new FastByteReader(src); + var ms = new MemoryStream(); + + do + { + var len = Math.Min(ctx.Remaining(), 0x3F); + ms.WriteByte((byte)(0x80 | len)); + while (len-- > 0) + ms.WriteByte(ctx.ReadByte()); + } + while (!ctx.Done()); + + ms.WriteByte(0x80); // terminator -- 0-length run. + + return ms.ToArray(); + } + } +} diff --git a/OpenRA.FileFormats/FileFormats/IniFile.cs b/OpenRA.FileFormats/FileFormats/IniFile.cs index 185dfb7992..8cb96974f4 100644 --- a/OpenRA.FileFormats/FileFormats/IniFile.cs +++ b/OpenRA.FileFormats/FileFormats/IniFile.cs @@ -1,151 +1,151 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; - -namespace OpenRA.FileFormats -{ - public class IniFile - { - Dictionary sections = new Dictionary(); - - public IniFile( Stream s ) - { - Load( s ); - } - - public IniFile( params Stream[] streams ) - { - foreach( var s in streams ) - Load( s ); - } - - public void Load( Stream s ) - { - StreamReader reader = new StreamReader( s ); - IniSection currentSection = null; - - while( !reader.EndOfStream ) - { - string line = reader.ReadLine(); - - if( line.Length == 0 ) continue; - - switch( line[ 0 ] ) - { - case ';': break; - case '[': currentSection = ProcessSection( line ); break; - default: ProcessEntry( line, currentSection ); break; - } - } - } - - Regex sectionPattern = new Regex( @"^\[([^]]*)\]" ); - - IniSection ProcessSection( string line ) - { - Match m = sectionPattern.Match( line ); - if( m == null || !m.Success ) - return null; - string sectionName = m.Groups[ 1 ].Value.ToLowerInvariant(); - - IniSection ret; - if( !sections.TryGetValue( sectionName, out ret ) ) - sections.Add( sectionName, ret = new IniSection( sectionName ) ); - return ret; - } - - bool ProcessEntry( string line, IniSection currentSection ) - { - int comment = line.IndexOf( ';' ); - if( comment >= 0 ) - line = line.Substring( 0, comment ); - - line = line.Trim(); - if( line.Length == 0 ) - return false; - - var key = line; - var value = ""; - int eq = line.IndexOf( '=' ); - if( eq >= 0 ) - { - key = line.Substring( 0, eq ); - value = line.Substring( eq + 1, line.Length - eq - 1 ); - } - - if( currentSection == null ) - throw new InvalidOperationException( "No current INI section" ); - - if( !currentSection.Contains( key ) ) - currentSection.Add( key, value ); - return true; - } - - public IniSection GetSection( string s ) - { - return GetSection( s, false ); - } - - public IniSection GetSection( string s, bool allowFail ) - { - IniSection section; - if( sections.TryGetValue( s.ToLowerInvariant(), out section ) ) - return section; - - if( allowFail ) - return new IniSection( s ); - throw new InvalidOperationException( "Section does not exist in map or rules: " + s ); - } - - public IEnumerable Sections { get { return sections.Values; } } - } - - public class IniSection : IEnumerable> - { - public string Name { get; private set; } - Dictionary values = new Dictionary(); - - public IniSection( string name ) - { - Name = name; - } - - public void Add( string key, string value ) - { - values[key] = value; - } - - public bool Contains( string key ) - { - return values.ContainsKey( key ); - } - - public string GetValue( string key, string defaultValue ) - { - string s; - return values.TryGetValue( key, out s ) ? s : defaultValue; - } - - public IEnumerator> GetEnumerator() - { - return values.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; + +namespace OpenRA.FileFormats +{ + public class IniFile + { + Dictionary sections = new Dictionary(); + + public IniFile( Stream s ) + { + Load( s ); + } + + public IniFile( params Stream[] streams ) + { + foreach( var s in streams ) + Load( s ); + } + + public void Load( Stream s ) + { + StreamReader reader = new StreamReader( s ); + IniSection currentSection = null; + + while( !reader.EndOfStream ) + { + string line = reader.ReadLine(); + + if( line.Length == 0 ) continue; + + switch( line[ 0 ] ) + { + case ';': break; + case '[': currentSection = ProcessSection( line ); break; + default: ProcessEntry( line, currentSection ); break; + } + } + } + + Regex sectionPattern = new Regex( @"^\[([^]]*)\]" ); + + IniSection ProcessSection( string line ) + { + Match m = sectionPattern.Match( line ); + if( m == null || !m.Success ) + return null; + string sectionName = m.Groups[ 1 ].Value.ToLowerInvariant(); + + IniSection ret; + if( !sections.TryGetValue( sectionName, out ret ) ) + sections.Add( sectionName, ret = new IniSection( sectionName ) ); + return ret; + } + + bool ProcessEntry( string line, IniSection currentSection ) + { + int comment = line.IndexOf( ';' ); + if( comment >= 0 ) + line = line.Substring( 0, comment ); + + line = line.Trim(); + if( line.Length == 0 ) + return false; + + var key = line; + var value = ""; + int eq = line.IndexOf( '=' ); + if( eq >= 0 ) + { + key = line.Substring( 0, eq ); + value = line.Substring( eq + 1, line.Length - eq - 1 ); + } + + if( currentSection == null ) + throw new InvalidOperationException( "No current INI section" ); + + if( !currentSection.Contains( key ) ) + currentSection.Add( key, value ); + return true; + } + + public IniSection GetSection( string s ) + { + return GetSection( s, false ); + } + + public IniSection GetSection( string s, bool allowFail ) + { + IniSection section; + if( sections.TryGetValue( s.ToLowerInvariant(), out section ) ) + return section; + + if( allowFail ) + return new IniSection( s ); + throw new InvalidOperationException( "Section does not exist in map or rules: " + s ); + } + + public IEnumerable Sections { get { return sections.Values; } } + } + + public class IniSection : IEnumerable> + { + public string Name { get; private set; } + Dictionary values = new Dictionary(); + + public IniSection( string name ) + { + Name = name; + } + + public void Add( string key, string value ) + { + values[key] = value; + } + + public bool Contains( string key ) + { + return values.ContainsKey( key ); + } + + public string GetValue( string key, string defaultValue ) + { + string s; + return values.TryGetValue( key, out s ) ? s : defaultValue; + } + + public IEnumerator> GetEnumerator() + { + return values.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/OpenRA.FileFormats/Filesystem/FileSystem.cs b/OpenRA.FileFormats/Filesystem/FileSystem.cs index 1e3b704585..5d6e25e63f 100644 --- a/OpenRA.FileFormats/Filesystem/FileSystem.cs +++ b/OpenRA.FileFormats/Filesystem/FileSystem.cs @@ -1,206 +1,206 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Linq; - -namespace OpenRA.FileFormats -{ - public static class FileSystem - { - static List mountedFolders = new List(); - public static string SpecialPackageRoot = ""; - - static Cache> allFiles = new Cache>( _ => new List() ); - - static void MountInner(IFolder folder) - { - mountedFolders.Add(folder); - - foreach( var hash in folder.AllFileHashes() ) - { - var l = allFiles[hash]; - if( !l.Contains( folder ) ) - l.Add( folder ); - } - } - - static int order = 0; - - static IFolder OpenPackage(string filename) - { - return OpenPackage(filename, order++); - } - - public static IFolder CreatePackage(string filename, int order, Dictionary content) - { - if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) - return new MixFile(filename, order, content); - else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) - return new ZipFile(filename, order, content); - else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) - return new ZipFile(filename, order, content); - else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase)) - throw new NotImplementedException("Creating .Z archives is unsupported"); - else - return new Folder(filename, order, content); - } - - public static IFolder OpenPackage(string filename, int order) - { - if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) - return new MixFile(filename, order); - else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) - return new ZipFile(filename, order); - else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) - return new ZipFile(filename, order); - else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase)) - return new InstallShieldPackage(filename, order); - else - return new Folder(filename, order); - } - - public static void Mount(string name) - { - var optional = name.StartsWith("~"); - if (optional) name = name.Substring(1); - - // paths starting with $ are relative to SpecialPackageRoot - if (name.StartsWith("$")) - name = SpecialPackageRoot+name.Substring(1); - - var a = (Action)(() => FileSystem.MountInner(OpenPackage(name))); - - if (optional) - try { a(); } - catch { } - else - a(); - } - - public static void UnmountAll() - { - mountedFolders.Clear(); - allFiles = new Cache>( _ => new List() ); - } - - public static bool Unmount(IFolder mount) - { - return (mountedFolders.RemoveAll(f => f == mount) > 0); - } - - public static void Mount(IFolder mount) - { - if (!mountedFolders.Contains(mount)) mountedFolders.Add(mount); - } - - public static void LoadFromManifest( Manifest manifest ) - { - UnmountAll(); - foreach (var dir in manifest.Folders) Mount(dir); - foreach (var pkg in manifest.Packages) Mount(pkg); - } - - static Stream GetFromCache( Cache> index, string filename ) - { - var folder = index[PackageEntry.HashFilename(filename)] - .Where(x => x.Exists(filename)) - .OrderBy(x => x.Priority) - .FirstOrDefault(); - - if (folder != null) - return folder.GetContent(filename); - - return null; - } - - public static Stream Open(string filename) - { - if( filename.IndexOfAny( new char[] { '/', '\\' } ) == -1 ) - { - var ret = GetFromCache( allFiles, filename ); - if( ret != null ) - return ret; - } - - var folder = mountedFolders - .Where(x => x.Exists(filename)) - .OrderByDescending(x => x.Priority) - .FirstOrDefault(); - - if (folder != null) - return folder.GetContent(filename); - - throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename ); - } - - public static Stream OpenWithExts( string filename, params string[] exts ) - { - if( filename.IndexOfAny( new char[] { '/', '\\' } ) == -1 ) - { - foreach( var ext in exts ) - { - var s = GetFromCache( allFiles, filename + ext ); - if( s != null ) - return s; - } - } - - foreach( var ext in exts ) - { - foreach( IFolder folder in mountedFolders ) - if (folder.Exists(filename + ext)) - return folder.GetContent( filename + ext ); - } - - throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename ); - } - - public static bool Exists(string filename) - { - foreach (var folder in mountedFolders) - if (folder.Exists(filename)) - return true; - return false; - } - - static Dictionary assemblyCache = new Dictionary(); - - public static Assembly ResolveAssembly(object sender, ResolveEventArgs e) - { - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - if (assembly.FullName == e.Name) - return assembly; - } - - string[] frags = e.Name.Split(','); - var filename = frags[0] + ".dll"; - Assembly a; - if (assemblyCache.TryGetValue(filename, out a)) - return a; - - if (FileSystem.Exists(filename)) - using (Stream s = FileSystem.Open(filename)) - { - byte[] buf = new byte[s.Length]; - s.Read(buf, 0, buf.Length); - a = Assembly.Load(buf); - assemblyCache.Add(filename, a); - return a; - } - - return null; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Linq; + +namespace OpenRA.FileFormats +{ + public static class FileSystem + { + static List mountedFolders = new List(); + public static string SpecialPackageRoot = ""; + + static Cache> allFiles = new Cache>( _ => new List() ); + + static void MountInner(IFolder folder) + { + mountedFolders.Add(folder); + + foreach( var hash in folder.AllFileHashes() ) + { + var l = allFiles[hash]; + if( !l.Contains( folder ) ) + l.Add( folder ); + } + } + + static int order = 0; + + static IFolder OpenPackage(string filename) + { + return OpenPackage(filename, order++); + } + + public static IFolder CreatePackage(string filename, int order, Dictionary content) + { + if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) + return new MixFile(filename, order, content); + else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) + return new ZipFile(filename, order, content); + else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) + return new ZipFile(filename, order, content); + else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase)) + throw new NotImplementedException("Creating .Z archives is unsupported"); + else + return new Folder(filename, order, content); + } + + public static IFolder OpenPackage(string filename, int order) + { + if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) + return new MixFile(filename, order); + else if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) + return new ZipFile(filename, order); + else if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) + return new ZipFile(filename, order); + else if (filename.EndsWith(".Z", StringComparison.InvariantCultureIgnoreCase)) + return new InstallShieldPackage(filename, order); + else + return new Folder(filename, order); + } + + public static void Mount(string name) + { + var optional = name.StartsWith("~"); + if (optional) name = name.Substring(1); + + // paths starting with $ are relative to SpecialPackageRoot + if (name.StartsWith("$")) + name = SpecialPackageRoot+name.Substring(1); + + var a = (Action)(() => FileSystem.MountInner(OpenPackage(name))); + + if (optional) + try { a(); } + catch { } + else + a(); + } + + public static void UnmountAll() + { + mountedFolders.Clear(); + allFiles = new Cache>( _ => new List() ); + } + + public static bool Unmount(IFolder mount) + { + return (mountedFolders.RemoveAll(f => f == mount) > 0); + } + + public static void Mount(IFolder mount) + { + if (!mountedFolders.Contains(mount)) mountedFolders.Add(mount); + } + + public static void LoadFromManifest( Manifest manifest ) + { + UnmountAll(); + foreach (var dir in manifest.Folders) Mount(dir); + foreach (var pkg in manifest.Packages) Mount(pkg); + } + + static Stream GetFromCache( Cache> index, string filename ) + { + var folder = index[PackageEntry.HashFilename(filename)] + .Where(x => x.Exists(filename)) + .OrderBy(x => x.Priority) + .FirstOrDefault(); + + if (folder != null) + return folder.GetContent(filename); + + return null; + } + + public static Stream Open(string filename) + { + if( filename.IndexOfAny( new char[] { '/', '\\' } ) == -1 ) + { + var ret = GetFromCache( allFiles, filename ); + if( ret != null ) + return ret; + } + + var folder = mountedFolders + .Where(x => x.Exists(filename)) + .OrderByDescending(x => x.Priority) + .FirstOrDefault(); + + if (folder != null) + return folder.GetContent(filename); + + throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename ); + } + + public static Stream OpenWithExts( string filename, params string[] exts ) + { + if( filename.IndexOfAny( new char[] { '/', '\\' } ) == -1 ) + { + foreach( var ext in exts ) + { + var s = GetFromCache( allFiles, filename + ext ); + if( s != null ) + return s; + } + } + + foreach( var ext in exts ) + { + foreach( IFolder folder in mountedFolders ) + if (folder.Exists(filename + ext)) + return folder.GetContent( filename + ext ); + } + + throw new FileNotFoundException( string.Format( "File not found: {0}", filename ), filename ); + } + + public static bool Exists(string filename) + { + foreach (var folder in mountedFolders) + if (folder.Exists(filename)) + return true; + return false; + } + + static Dictionary assemblyCache = new Dictionary(); + + public static Assembly ResolveAssembly(object sender, ResolveEventArgs e) + { + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + if (assembly.FullName == e.Name) + return assembly; + } + + string[] frags = e.Name.Split(','); + var filename = frags[0] + ".dll"; + Assembly a; + if (assemblyCache.TryGetValue(filename, out a)) + return a; + + if (FileSystem.Exists(filename)) + using (Stream s = FileSystem.Open(filename)) + { + byte[] buf = new byte[s.Length]; + s.Read(buf, 0, buf.Length); + a = Assembly.Load(buf); + assemblyCache.Add(filename, a); + return a; + } + + return null; + } + } +} diff --git a/OpenRA.FileFormats/Filesystem/Folder.cs b/OpenRA.FileFormats/Filesystem/Folder.cs index 96557a862a..7005aced68 100644 --- a/OpenRA.FileFormats/Filesystem/Folder.cs +++ b/OpenRA.FileFormats/Filesystem/Folder.cs @@ -1,73 +1,73 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.IO; -using System; - -namespace OpenRA.FileFormats -{ - public class Folder : IFolder - { - readonly string path; - - int priority; - - // Create a new folder package - public Folder(string path, int priority, Dictionary contents) - { - this.path = path; - this.priority = priority; - if (Directory.Exists(path)) - Directory.Delete(path); - - Write(contents); - } - - public Folder(string path, int priority) - { - this.path = path; - this.priority = priority; - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - } - - public Stream GetContent(string filename) - { - try { return File.OpenRead( Path.Combine( path, filename ) ); } - catch { return null; } - } - - public IEnumerable AllFileHashes() - { - foreach( var filename in Directory.GetFiles( path, "*", SearchOption.TopDirectoryOnly ) ) - yield return PackageEntry.HashFilename( Path.GetFileName(filename) ); - } - - public bool Exists(string filename) - { - return File.Exists(Path.Combine(path,filename)); - } - - - public int Priority - { - get { return priority; } - } - - public void Write(Dictionary contents) - { - foreach (var file in contents) - using (var dataStream = File.Create(Path.Combine(path, file.Key))) - using (var writer = new BinaryWriter(dataStream)) - writer.Write(file.Value); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.IO; +using System; + +namespace OpenRA.FileFormats +{ + public class Folder : IFolder + { + readonly string path; + + int priority; + + // Create a new folder package + public Folder(string path, int priority, Dictionary contents) + { + this.path = path; + this.priority = priority; + if (Directory.Exists(path)) + Directory.Delete(path); + + Write(contents); + } + + public Folder(string path, int priority) + { + this.path = path; + this.priority = priority; + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + } + + public Stream GetContent(string filename) + { + try { return File.OpenRead( Path.Combine( path, filename ) ); } + catch { return null; } + } + + public IEnumerable AllFileHashes() + { + foreach( var filename in Directory.GetFiles( path, "*", SearchOption.TopDirectoryOnly ) ) + yield return PackageEntry.HashFilename( Path.GetFileName(filename) ); + } + + public bool Exists(string filename) + { + return File.Exists(Path.Combine(path,filename)); + } + + + public int Priority + { + get { return priority; } + } + + public void Write(Dictionary contents) + { + foreach (var file in contents) + using (var dataStream = File.Create(Path.Combine(path, file.Key))) + using (var writer = new BinaryWriter(dataStream)) + writer.Write(file.Value); + } + } +} diff --git a/OpenRA.FileFormats/Filesystem/InstallShieldPackage.cs b/OpenRA.FileFormats/Filesystem/InstallShieldPackage.cs index 44472481fc..1ddbba8ba7 100644 --- a/OpenRA.FileFormats/Filesystem/InstallShieldPackage.cs +++ b/OpenRA.FileFormats/Filesystem/InstallShieldPackage.cs @@ -1,126 +1,126 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace OpenRA.FileFormats -{ - public class InstallShieldPackage : IFolder - { - readonly Dictionary index = new Dictionary(); - readonly Stream s; - readonly long dataStart = 255; - int priority; - - public InstallShieldPackage(string filename, int priority) - { - this.priority = priority; - s = FileSystem.Open(filename); - - // Parse package header - BinaryReader reader = new BinaryReader(s); - uint signature = reader.ReadUInt32(); - if (signature != 0x8C655D13) - throw new InvalidDataException("Not an Installshield package"); - - reader.ReadBytes(8); - /*var FileCount = */reader.ReadUInt16(); - reader.ReadBytes(4); - /*var ArchiveSize = */reader.ReadUInt32(); - reader.ReadBytes(19); - var TOCAddress = reader.ReadInt32(); - reader.ReadBytes(4); - var DirCount = reader.ReadUInt16(); - - // Parse the directory list - s.Seek(TOCAddress, SeekOrigin.Begin); - BinaryReader TOCreader = new BinaryReader(s); - for (var i = 0; i < DirCount; i++) - ParseDirectory(TOCreader); - } - - void ParseDirectory(BinaryReader reader) - { - // Parse directory header - var FileCount = reader.ReadUInt16(); - var ChunkSize = reader.ReadUInt16(); - var NameLength = reader.ReadUInt16(); - reader.ReadChars(NameLength); //var DirName = new String(reader.ReadChars(NameLength)); - - // Skip to the end of the chunk - reader.ReadBytes(ChunkSize - NameLength - 6); - - // Parse files - for (var i = 0; i < FileCount; i++) - ParseFile(reader); - } - - uint AccumulatedData = 0; - void ParseFile(BinaryReader reader) - { - reader.ReadBytes(7); - var CompressedSize = reader.ReadUInt32(); - reader.ReadBytes(12); - var ChunkSize = reader.ReadUInt16(); - reader.ReadBytes(4); - var NameLength = reader.ReadByte(); - var FileName = new String(reader.ReadChars(NameLength)); - - var hash = PackageEntry.HashFilename(FileName); - index.Add(hash, new PackageEntry(hash,AccumulatedData, CompressedSize)); - AccumulatedData += CompressedSize; - - // Skip to the end of the chunk - reader.ReadBytes(ChunkSize - NameLength - 30); - } - - public Stream GetContent(uint hash) - { - PackageEntry e; - if (!index.TryGetValue(hash, out e)) - return null; - - s.Seek( dataStart + e.Offset, SeekOrigin.Begin ); - byte[] data = new byte[ e.Length ]; - s.Read( data, 0, (int)e.Length ); - - return new MemoryStream(Blast.Decompress(data)); - } - - public Stream GetContent(string filename) - { - return GetContent(PackageEntry.HashFilename(filename)); - } - - public IEnumerable AllFileHashes() - { - return index.Keys; - } - - public bool Exists(string filename) - { - return index.ContainsKey(PackageEntry.HashFilename(filename)); - } - - - public int Priority - { - get { return 2000 + priority; } - } - - public void Write(Dictionary contents) - { - throw new NotImplementedException("Cannot save InstallShieldPackages."); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace OpenRA.FileFormats +{ + public class InstallShieldPackage : IFolder + { + readonly Dictionary index = new Dictionary(); + readonly Stream s; + readonly long dataStart = 255; + int priority; + + public InstallShieldPackage(string filename, int priority) + { + this.priority = priority; + s = FileSystem.Open(filename); + + // Parse package header + BinaryReader reader = new BinaryReader(s); + uint signature = reader.ReadUInt32(); + if (signature != 0x8C655D13) + throw new InvalidDataException("Not an Installshield package"); + + reader.ReadBytes(8); + /*var FileCount = */reader.ReadUInt16(); + reader.ReadBytes(4); + /*var ArchiveSize = */reader.ReadUInt32(); + reader.ReadBytes(19); + var TOCAddress = reader.ReadInt32(); + reader.ReadBytes(4); + var DirCount = reader.ReadUInt16(); + + // Parse the directory list + s.Seek(TOCAddress, SeekOrigin.Begin); + BinaryReader TOCreader = new BinaryReader(s); + for (var i = 0; i < DirCount; i++) + ParseDirectory(TOCreader); + } + + void ParseDirectory(BinaryReader reader) + { + // Parse directory header + var FileCount = reader.ReadUInt16(); + var ChunkSize = reader.ReadUInt16(); + var NameLength = reader.ReadUInt16(); + reader.ReadChars(NameLength); //var DirName = new String(reader.ReadChars(NameLength)); + + // Skip to the end of the chunk + reader.ReadBytes(ChunkSize - NameLength - 6); + + // Parse files + for (var i = 0; i < FileCount; i++) + ParseFile(reader); + } + + uint AccumulatedData = 0; + void ParseFile(BinaryReader reader) + { + reader.ReadBytes(7); + var CompressedSize = reader.ReadUInt32(); + reader.ReadBytes(12); + var ChunkSize = reader.ReadUInt16(); + reader.ReadBytes(4); + var NameLength = reader.ReadByte(); + var FileName = new String(reader.ReadChars(NameLength)); + + var hash = PackageEntry.HashFilename(FileName); + index.Add(hash, new PackageEntry(hash,AccumulatedData, CompressedSize)); + AccumulatedData += CompressedSize; + + // Skip to the end of the chunk + reader.ReadBytes(ChunkSize - NameLength - 30); + } + + public Stream GetContent(uint hash) + { + PackageEntry e; + if (!index.TryGetValue(hash, out e)) + return null; + + s.Seek( dataStart + e.Offset, SeekOrigin.Begin ); + byte[] data = new byte[ e.Length ]; + s.Read( data, 0, (int)e.Length ); + + return new MemoryStream(Blast.Decompress(data)); + } + + public Stream GetContent(string filename) + { + return GetContent(PackageEntry.HashFilename(filename)); + } + + public IEnumerable AllFileHashes() + { + return index.Keys; + } + + public bool Exists(string filename) + { + return index.ContainsKey(PackageEntry.HashFilename(filename)); + } + + + public int Priority + { + get { return 2000 + priority; } + } + + public void Write(Dictionary contents) + { + throw new NotImplementedException("Cannot save InstallShieldPackages."); + } + } +} diff --git a/OpenRA.FileFormats/Filesystem/MixFile.cs b/OpenRA.FileFormats/Filesystem/MixFile.cs index 093d824a12..7fac6d9d97 100644 --- a/OpenRA.FileFormats/Filesystem/MixFile.cs +++ b/OpenRA.FileFormats/Filesystem/MixFile.cs @@ -1,220 +1,220 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace OpenRA.FileFormats -{ - public interface IFolder - { - Stream GetContent(string filename); - bool Exists(string filename); - IEnumerable AllFileHashes(); - void Write(Dictionary contents); - int Priority { get; } - } - - public class MixFile : IFolder - { - readonly Dictionary index; - readonly bool isRmix, isEncrypted; - readonly long dataStart; - readonly Stream s; - int priority; - - // Create a new MixFile - public MixFile(string filename, int priority, Dictionary contents) - { - this.priority = priority; - if (File.Exists(filename)) - File.Delete(filename); - - s = File.Create(filename); - Write(contents); - } - - public MixFile(string filename, int priority) - { - this.priority = priority; - s = FileSystem.Open(filename); - - BinaryReader reader = new BinaryReader(s); - uint signature = reader.ReadUInt32(); - - isRmix = 0 == (signature & ~(uint)(MixFileFlags.Checksum | MixFileFlags.Encrypted)); - - if (isRmix) - { - isEncrypted = 0 != (signature & (uint)MixFileFlags.Encrypted); - if( isEncrypted ) - { - index = ParseRaHeader( s, out dataStart ).ToDictionary(x => x.Hash); - return; - } - } - else - s.Seek( 0, SeekOrigin.Begin ); - - isEncrypted = false; - index = ParseTdHeader(s, out dataStart).ToDictionary(x => x.Hash); - } - - const long headerStart = 84; - - List ParseRaHeader(Stream s, out long dataStart) - { - BinaryReader reader = new BinaryReader(s); - byte[] keyblock = reader.ReadBytes(80); - byte[] blowfishKey = new BlowfishKeyProvider().DecryptKey(keyblock); - - uint[] h = ReadUints(reader, 2); - - Blowfish fish = new Blowfish(blowfishKey); - MemoryStream ms = Decrypt( h, fish ); - BinaryReader reader2 = new BinaryReader(ms); - - ushort numFiles = reader2.ReadUInt16(); - reader2.ReadUInt32(); /*datasize*/ - - s.Position = headerStart; - reader = new BinaryReader(s); - - int byteCount = 6 + numFiles * PackageEntry.Size; - h = ReadUints( reader, ( byteCount + 3 ) / 4 ); - - ms = Decrypt( h, fish ); - - dataStart = headerStart + byteCount + ( ( ~byteCount + 1 ) & 7 ); - - long ds; - return ParseTdHeader( ms, out ds ); - } - - static MemoryStream Decrypt( uint[] h, Blowfish fish ) - { - uint[] decrypted = fish.Decrypt( h ); - - MemoryStream ms = new MemoryStream(); - BinaryWriter writer = new BinaryWriter( ms ); - foreach( uint t in decrypted ) - writer.Write( t ); - writer.Flush(); - - ms.Position = 0; - return ms; - } - - uint[] ReadUints(BinaryReader r, int count) - { - uint[] ret = new uint[count]; - for (int i = 0; i < ret.Length; i++) - ret[i] = r.ReadUInt32(); - - return ret; - } - - List ParseTdHeader(Stream s, out long dataStart) - { - List items = new List(); - - BinaryReader reader = new BinaryReader(s); - ushort numFiles = reader.ReadUInt16(); - /*uint dataSize = */reader.ReadUInt32(); - - for (int i = 0; i < numFiles; i++) - items.Add(new PackageEntry(reader)); - - dataStart = s.Position; - return items; - } - - public Stream GetContent(uint hash) - { - PackageEntry e; - if (!index.TryGetValue(hash, out e)) - return null; - - s.Seek( dataStart + e.Offset, SeekOrigin.Begin ); - byte[] data = new byte[ e.Length ]; - s.Read( data, 0, (int)e.Length ); - return new MemoryStream(data); - } - - public Stream GetContent(string filename) - { - return GetContent(PackageEntry.HashFilename(filename)); - } - - public IEnumerable AllFileHashes() - { - return index.Keys; - } - - public bool Exists(string filename) - { - return index.ContainsKey(PackageEntry.HashFilename(filename)); - } - - - public int Priority - { - get { return 1000 + priority; } - } - - public void Write(Dictionary contents) - { - // Cannot modify existing mixfile - rename existing file and - // create a new one with original content plus modifications - FileSystem.Unmount(this); - - // TODO: Add existing data to the contents list - if (index.Count > 0) - throw new NotImplementedException("Updating mix files unfinished"); - - // Construct a list of entries for the file header - uint dataSize = 0; - var items = new List(); - foreach (var kv in contents) - { - uint length = (uint)kv.Value.Length; - uint hash = PackageEntry.HashFilename(Path.GetFileName(kv.Key)); - items.Add(new PackageEntry(hash, dataSize, length)); - dataSize += length; - } - - // Write the new file - s.Seek(0,SeekOrigin.Begin); - using (var writer = new BinaryWriter(s)) - { - // Write file header - writer.Write((ushort)items.Count); - writer.Write(dataSize); - foreach (var item in items) - item.Write(writer); - - writer.Flush(); - - // Copy file data - foreach (var file in contents) - s.Write(file.Value); - } - } - } - - [Flags] - enum MixFileFlags : uint - { - Checksum = 0x10000, - Encrypted = 0x20000, - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace OpenRA.FileFormats +{ + public interface IFolder + { + Stream GetContent(string filename); + bool Exists(string filename); + IEnumerable AllFileHashes(); + void Write(Dictionary contents); + int Priority { get; } + } + + public class MixFile : IFolder + { + readonly Dictionary index; + readonly bool isRmix, isEncrypted; + readonly long dataStart; + readonly Stream s; + int priority; + + // Create a new MixFile + public MixFile(string filename, int priority, Dictionary contents) + { + this.priority = priority; + if (File.Exists(filename)) + File.Delete(filename); + + s = File.Create(filename); + Write(contents); + } + + public MixFile(string filename, int priority) + { + this.priority = priority; + s = FileSystem.Open(filename); + + BinaryReader reader = new BinaryReader(s); + uint signature = reader.ReadUInt32(); + + isRmix = 0 == (signature & ~(uint)(MixFileFlags.Checksum | MixFileFlags.Encrypted)); + + if (isRmix) + { + isEncrypted = 0 != (signature & (uint)MixFileFlags.Encrypted); + if( isEncrypted ) + { + index = ParseRaHeader( s, out dataStart ).ToDictionary(x => x.Hash); + return; + } + } + else + s.Seek( 0, SeekOrigin.Begin ); + + isEncrypted = false; + index = ParseTdHeader(s, out dataStart).ToDictionary(x => x.Hash); + } + + const long headerStart = 84; + + List ParseRaHeader(Stream s, out long dataStart) + { + BinaryReader reader = new BinaryReader(s); + byte[] keyblock = reader.ReadBytes(80); + byte[] blowfishKey = new BlowfishKeyProvider().DecryptKey(keyblock); + + uint[] h = ReadUints(reader, 2); + + Blowfish fish = new Blowfish(blowfishKey); + MemoryStream ms = Decrypt( h, fish ); + BinaryReader reader2 = new BinaryReader(ms); + + ushort numFiles = reader2.ReadUInt16(); + reader2.ReadUInt32(); /*datasize*/ + + s.Position = headerStart; + reader = new BinaryReader(s); + + int byteCount = 6 + numFiles * PackageEntry.Size; + h = ReadUints( reader, ( byteCount + 3 ) / 4 ); + + ms = Decrypt( h, fish ); + + dataStart = headerStart + byteCount + ( ( ~byteCount + 1 ) & 7 ); + + long ds; + return ParseTdHeader( ms, out ds ); + } + + static MemoryStream Decrypt( uint[] h, Blowfish fish ) + { + uint[] decrypted = fish.Decrypt( h ); + + MemoryStream ms = new MemoryStream(); + BinaryWriter writer = new BinaryWriter( ms ); + foreach( uint t in decrypted ) + writer.Write( t ); + writer.Flush(); + + ms.Position = 0; + return ms; + } + + uint[] ReadUints(BinaryReader r, int count) + { + uint[] ret = new uint[count]; + for (int i = 0; i < ret.Length; i++) + ret[i] = r.ReadUInt32(); + + return ret; + } + + List ParseTdHeader(Stream s, out long dataStart) + { + List items = new List(); + + BinaryReader reader = new BinaryReader(s); + ushort numFiles = reader.ReadUInt16(); + /*uint dataSize = */reader.ReadUInt32(); + + for (int i = 0; i < numFiles; i++) + items.Add(new PackageEntry(reader)); + + dataStart = s.Position; + return items; + } + + public Stream GetContent(uint hash) + { + PackageEntry e; + if (!index.TryGetValue(hash, out e)) + return null; + + s.Seek( dataStart + e.Offset, SeekOrigin.Begin ); + byte[] data = new byte[ e.Length ]; + s.Read( data, 0, (int)e.Length ); + return new MemoryStream(data); + } + + public Stream GetContent(string filename) + { + return GetContent(PackageEntry.HashFilename(filename)); + } + + public IEnumerable AllFileHashes() + { + return index.Keys; + } + + public bool Exists(string filename) + { + return index.ContainsKey(PackageEntry.HashFilename(filename)); + } + + + public int Priority + { + get { return 1000 + priority; } + } + + public void Write(Dictionary contents) + { + // Cannot modify existing mixfile - rename existing file and + // create a new one with original content plus modifications + FileSystem.Unmount(this); + + // TODO: Add existing data to the contents list + if (index.Count > 0) + throw new NotImplementedException("Updating mix files unfinished"); + + // Construct a list of entries for the file header + uint dataSize = 0; + var items = new List(); + foreach (var kv in contents) + { + uint length = (uint)kv.Value.Length; + uint hash = PackageEntry.HashFilename(Path.GetFileName(kv.Key)); + items.Add(new PackageEntry(hash, dataSize, length)); + dataSize += length; + } + + // Write the new file + s.Seek(0,SeekOrigin.Begin); + using (var writer = new BinaryWriter(s)) + { + // Write file header + writer.Write((ushort)items.Count); + writer.Write(dataSize); + foreach (var item in items) + item.Write(writer); + + writer.Flush(); + + // Copy file data + foreach (var file in contents) + s.Write(file.Value); + } + } + } + + [Flags] + enum MixFileFlags : uint + { + Checksum = 0x10000, + Encrypted = 0x20000, + } +} diff --git a/OpenRA.FileFormats/Filesystem/ZipFile.cs b/OpenRA.FileFormats/Filesystem/ZipFile.cs index 29792fd364..1fd2a43bd0 100644 --- a/OpenRA.FileFormats/Filesystem/ZipFile.cs +++ b/OpenRA.FileFormats/Filesystem/ZipFile.cs @@ -1,117 +1,117 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.IO; -using ICSharpCode.SharpZipLib.Zip; -using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile; - -namespace OpenRA.FileFormats -{ - public class ZipFile : IFolder - { - string filename; - SZipFile pkg; - int priority; - - public ZipFile(string filename, int priority) - { - this.filename = filename; - this.priority = priority; - try - { - // pull the file into memory, dont keep it open. - pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename))); - } - catch (ZipException e) - { - Log.Write("debug", "Couldn't load zip file: {0}", e.Message); - } - } - - // Create a new zip with the specified contents - public ZipFile(string filename, int priority, Dictionary contents) - { - this.priority = priority; - this.filename = filename; - - if (File.Exists(filename)) - File.Delete(filename); - - pkg = SZipFile.Create(filename); - Write(contents); - } - - public Stream GetContent(string filename) - { - - using (var z = pkg.GetInputStream(pkg.GetEntry(filename))) - { - var ms = new MemoryStream(); - int bufSize = 2048; - byte[] buf = new byte[bufSize]; - while ((bufSize = z.Read(buf, 0, buf.Length)) > 0) - ms.Write(buf, 0, bufSize); - - ms.Seek(0, SeekOrigin.Begin); - return ms; - } - } - - public IEnumerable AllFileHashes() - { - foreach(ZipEntry entry in pkg) - yield return PackageEntry.HashFilename(entry.Name); - } - - public bool Exists(string filename) - { - return pkg.GetEntry(filename) != null; - } - - public int Priority - { - get { return 500 + priority; } - } - - public void Write(Dictionary contents) - { - pkg.Close(); - - pkg = SZipFile.Create(filename); - - pkg.BeginUpdate(); - // TODO: Clear existing content? - - foreach (var kvp in contents) - pkg.Add(new StaticMemoryDataSource(kvp.Value), kvp.Key); - - pkg.CommitUpdate(); - - pkg.Close(); - - pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename))); - } - } - - class StaticMemoryDataSource : IStaticDataSource - { - byte[] data; - public StaticMemoryDataSource (byte[] data) - { - this.data = data; - } - - public Stream GetSource() - { - return new MemoryStream(data); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.IO; +using ICSharpCode.SharpZipLib.Zip; +using SZipFile = ICSharpCode.SharpZipLib.Zip.ZipFile; + +namespace OpenRA.FileFormats +{ + public class ZipFile : IFolder + { + string filename; + SZipFile pkg; + int priority; + + public ZipFile(string filename, int priority) + { + this.filename = filename; + this.priority = priority; + try + { + // pull the file into memory, dont keep it open. + pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename))); + } + catch (ZipException e) + { + Log.Write("debug", "Couldn't load zip file: {0}", e.Message); + } + } + + // Create a new zip with the specified contents + public ZipFile(string filename, int priority, Dictionary contents) + { + this.priority = priority; + this.filename = filename; + + if (File.Exists(filename)) + File.Delete(filename); + + pkg = SZipFile.Create(filename); + Write(contents); + } + + public Stream GetContent(string filename) + { + + using (var z = pkg.GetInputStream(pkg.GetEntry(filename))) + { + var ms = new MemoryStream(); + int bufSize = 2048; + byte[] buf = new byte[bufSize]; + while ((bufSize = z.Read(buf, 0, buf.Length)) > 0) + ms.Write(buf, 0, bufSize); + + ms.Seek(0, SeekOrigin.Begin); + return ms; + } + } + + public IEnumerable AllFileHashes() + { + foreach(ZipEntry entry in pkg) + yield return PackageEntry.HashFilename(entry.Name); + } + + public bool Exists(string filename) + { + return pkg.GetEntry(filename) != null; + } + + public int Priority + { + get { return 500 + priority; } + } + + public void Write(Dictionary contents) + { + pkg.Close(); + + pkg = SZipFile.Create(filename); + + pkg.BeginUpdate(); + // TODO: Clear existing content? + + foreach (var kvp in contents) + pkg.Add(new StaticMemoryDataSource(kvp.Value), kvp.Key); + + pkg.CommitUpdate(); + + pkg.Close(); + + pkg = new SZipFile(new MemoryStream(File.ReadAllBytes(filename))); + } + } + + class StaticMemoryDataSource : IStaticDataSource + { + byte[] data; + public StaticMemoryDataSource (byte[] data) + { + this.data = data; + } + + public Stream GetSource() + { + return new MemoryStream(data); + } + } +} diff --git a/OpenRA.FileFormats/Graphics/Dune2ShpReader.cs b/OpenRA.FileFormats/Graphics/Dune2ShpReader.cs index 14dc421820..2e769bf2b0 100644 --- a/OpenRA.FileFormats/Graphics/Dune2ShpReader.cs +++ b/OpenRA.FileFormats/Graphics/Dune2ShpReader.cs @@ -1,146 +1,146 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections; -using System.Collections.Generic; -using System.Drawing; -using System.IO; - -namespace OpenRA.FileFormats -{ - public enum Dune2ImageFlags : int - { - F80_F2 = 0, - F2 = 2, - L16_F80_F2_1 = 1, - L16_F80_F2_2 = 3, - Ln_F80_F2 = 5 - } - - public class Dune2ImageHeader - { - public readonly Dune2ImageFlags Flags; - public readonly int Width; - public readonly int Height; - public readonly int Slices; - public readonly int FileSize; - public readonly int DataSize; - - public readonly byte[] LookupTable; - public byte[] Image; - - public Dune2ImageHeader(BinaryReader reader) - { - Flags = (Dune2ImageFlags)reader.ReadUInt16(); - Slices = reader.ReadByte(); - Width = reader.ReadUInt16(); - Height = reader.ReadByte(); - FileSize = reader.ReadUInt16(); - DataSize = reader.ReadUInt16(); - - if (Flags == Dune2ImageFlags.L16_F80_F2_1 || - Flags == Dune2ImageFlags.L16_F80_F2_2 || - Flags == Dune2ImageFlags.Ln_F80_F2) - { - int n = Flags == Dune2ImageFlags.Ln_F80_F2 ? reader.ReadByte() : (byte)16; - LookupTable = new byte[n]; - for (int i = 0; i < n; i++) - LookupTable[i] = reader.ReadByte(); - } - else - { - LookupTable = new byte[256]; - for (int i = 0; i < 256; i++) - LookupTable[i] = (byte)i; - LookupTable[1] = 0x7f; - LookupTable[2] = 0x7e; - LookupTable[3] = 0x7d; - LookupTable[4] = 0x7c; - } - } - - public Size Size - { - get { return new Size(Width, Height); } - } - } - - public class Dune2ShpReader : IEnumerable - { - public readonly int ImageCount; - - List headers = new List(); - - public Dune2ShpReader(Stream stream) - { - BinaryReader reader = new BinaryReader(stream); - - ImageCount = reader.ReadUInt16(); - - //Last offset is pointer to end of file. - uint[] offsets = new uint[ImageCount + 1]; - - uint temp = reader.ReadUInt32(); - - //If fourth byte in file is non-zero, the offsets are two bytes each. - bool twoByteOffsets = (temp & 0xFF0000) > 0; - if (twoByteOffsets) - { - offsets[0] = ((temp & 0xFFFF0000) >> 16) + 2; //Offset does not account for image count bytes - offsets[1] = (temp & 0xFFFF) + 2; - } - else - offsets[0] = temp + 2; - - for (int i = twoByteOffsets ? 2 : 1; i < ImageCount + 1; i++) - offsets[i] = (twoByteOffsets ? reader.ReadUInt16() : reader.ReadUInt32()) + 2; - - for (int i = 0; i < ImageCount; i++) - { - reader.BaseStream.Seek(offsets[i], SeekOrigin.Begin); - Dune2ImageHeader header = new Dune2ImageHeader(reader); - byte[] imgData = reader.ReadBytes(header.FileSize); - header.Image = new byte[header.Height * header.Width]; - - //Decode image data - if (header.Flags != Dune2ImageFlags.F2) - { - byte[] tempData = new byte[header.DataSize]; - Format80.DecodeInto(imgData, tempData); - Format2.DecodeInto(tempData, header.Image); - } - else - Format2.DecodeInto(imgData, header.Image); - - //Lookup values in lookup table - if (header.LookupTable != null) - for (int j = 0; j < header.Image.Length; j++) - header.Image[j] = header.LookupTable[header.Image[j]]; - - headers.Add(header); - } - } - - public Dune2ImageHeader this[int index] - { - get { return headers[index]; } - } - - public IEnumerator GetEnumerator() - { - return headers.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.IO; + +namespace OpenRA.FileFormats +{ + public enum Dune2ImageFlags : int + { + F80_F2 = 0, + F2 = 2, + L16_F80_F2_1 = 1, + L16_F80_F2_2 = 3, + Ln_F80_F2 = 5 + } + + public class Dune2ImageHeader + { + public readonly Dune2ImageFlags Flags; + public readonly int Width; + public readonly int Height; + public readonly int Slices; + public readonly int FileSize; + public readonly int DataSize; + + public readonly byte[] LookupTable; + public byte[] Image; + + public Dune2ImageHeader(BinaryReader reader) + { + Flags = (Dune2ImageFlags)reader.ReadUInt16(); + Slices = reader.ReadByte(); + Width = reader.ReadUInt16(); + Height = reader.ReadByte(); + FileSize = reader.ReadUInt16(); + DataSize = reader.ReadUInt16(); + + if (Flags == Dune2ImageFlags.L16_F80_F2_1 || + Flags == Dune2ImageFlags.L16_F80_F2_2 || + Flags == Dune2ImageFlags.Ln_F80_F2) + { + int n = Flags == Dune2ImageFlags.Ln_F80_F2 ? reader.ReadByte() : (byte)16; + LookupTable = new byte[n]; + for (int i = 0; i < n; i++) + LookupTable[i] = reader.ReadByte(); + } + else + { + LookupTable = new byte[256]; + for (int i = 0; i < 256; i++) + LookupTable[i] = (byte)i; + LookupTable[1] = 0x7f; + LookupTable[2] = 0x7e; + LookupTable[3] = 0x7d; + LookupTable[4] = 0x7c; + } + } + + public Size Size + { + get { return new Size(Width, Height); } + } + } + + public class Dune2ShpReader : IEnumerable + { + public readonly int ImageCount; + + List headers = new List(); + + public Dune2ShpReader(Stream stream) + { + BinaryReader reader = new BinaryReader(stream); + + ImageCount = reader.ReadUInt16(); + + //Last offset is pointer to end of file. + uint[] offsets = new uint[ImageCount + 1]; + + uint temp = reader.ReadUInt32(); + + //If fourth byte in file is non-zero, the offsets are two bytes each. + bool twoByteOffsets = (temp & 0xFF0000) > 0; + if (twoByteOffsets) + { + offsets[0] = ((temp & 0xFFFF0000) >> 16) + 2; //Offset does not account for image count bytes + offsets[1] = (temp & 0xFFFF) + 2; + } + else + offsets[0] = temp + 2; + + for (int i = twoByteOffsets ? 2 : 1; i < ImageCount + 1; i++) + offsets[i] = (twoByteOffsets ? reader.ReadUInt16() : reader.ReadUInt32()) + 2; + + for (int i = 0; i < ImageCount; i++) + { + reader.BaseStream.Seek(offsets[i], SeekOrigin.Begin); + Dune2ImageHeader header = new Dune2ImageHeader(reader); + byte[] imgData = reader.ReadBytes(header.FileSize); + header.Image = new byte[header.Height * header.Width]; + + //Decode image data + if (header.Flags != Dune2ImageFlags.F2) + { + byte[] tempData = new byte[header.DataSize]; + Format80.DecodeInto(imgData, tempData); + Format2.DecodeInto(tempData, header.Image); + } + else + Format2.DecodeInto(imgData, header.Image); + + //Lookup values in lookup table + if (header.LookupTable != null) + for (int j = 0; j < header.Image.Length; j++) + header.Image[j] = header.LookupTable[header.Image[j]]; + + headers.Add(header); + } + } + + public Dune2ImageHeader this[int index] + { + get { return headers[index]; } + } + + public IEnumerator GetEnumerator() + { + return headers.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs b/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs index 578d8df696..8158a0e26d 100755 --- a/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs +++ b/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs @@ -1,96 +1,96 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using System.IO; - -namespace OpenRA.FileFormats.Graphics -{ - [AttributeUsage( AttributeTargets.Assembly )] - public class RendererAttribute : Attribute - { - public readonly Type Type; - - public RendererAttribute( Type graphicsDeviceType ) - { - if( !typeof( IGraphicsDevice ).IsAssignableFrom( graphicsDeviceType ) ) - throw new InvalidOperationException( "Incorrect type in RendererAttribute" ); - Type = graphicsDeviceType; - } - } - - public interface IGraphicsDevice - { - IVertexBuffer CreateVertexBuffer( int length ); - IIndexBuffer CreateIndexBuffer( int length ); - ITexture CreateTexture( Bitmap bitmap ); - ITexture CreateTexture(); - IShader CreateShader( string name ); - - Size WindowSize { get; } - - void Clear( Color color ); - void Present( IInputHandler inputHandler ); - - void DrawIndexedPrimitives( PrimitiveType type, Range vertexRange, Range indexRange ); - void DrawIndexedPrimitives( PrimitiveType type, int vertexPool, int numPrimitives ); - - void EnableScissor( int left, int top, int width, int height ); - void DisableScissor(); - } - - public interface IVertexBuffer - { - void Bind(); - void SetData( T[] vertices, int length ); - } - - public interface IIndexBuffer - { - void Bind(); - void SetData( ushort[] indices, int length ); - } - - public interface IShader - { - void SetValue( string name, float x, float y ); - void SetValue( string param, ITexture texture ); - void Commit(); - void Render( Action a ); - } - - public interface ITexture - { - void SetData(Bitmap bitmap); - void SetData(uint[,] colors); - void SetData(byte[] colors, int width, int height); - } - - public enum PrimitiveType - { - PointList, - LineList, - TriangleList, - } - - public struct Range - { - public readonly T Start, End; - public Range( T start, T end ) { Start = start; End = end; } - } - - public enum WindowMode - { - Windowed, - Fullscreen, - PseudoFullscreen, - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using System.IO; + +namespace OpenRA.FileFormats.Graphics +{ + [AttributeUsage( AttributeTargets.Assembly )] + public class RendererAttribute : Attribute + { + public readonly Type Type; + + public RendererAttribute( Type graphicsDeviceType ) + { + if( !typeof( IGraphicsDevice ).IsAssignableFrom( graphicsDeviceType ) ) + throw new InvalidOperationException( "Incorrect type in RendererAttribute" ); + Type = graphicsDeviceType; + } + } + + public interface IGraphicsDevice + { + IVertexBuffer CreateVertexBuffer( int length ); + IIndexBuffer CreateIndexBuffer( int length ); + ITexture CreateTexture( Bitmap bitmap ); + ITexture CreateTexture(); + IShader CreateShader( string name ); + + Size WindowSize { get; } + + void Clear( Color color ); + void Present( IInputHandler inputHandler ); + + void DrawIndexedPrimitives( PrimitiveType type, Range vertexRange, Range indexRange ); + void DrawIndexedPrimitives( PrimitiveType type, int vertexPool, int numPrimitives ); + + void EnableScissor( int left, int top, int width, int height ); + void DisableScissor(); + } + + public interface IVertexBuffer + { + void Bind(); + void SetData( T[] vertices, int length ); + } + + public interface IIndexBuffer + { + void Bind(); + void SetData( ushort[] indices, int length ); + } + + public interface IShader + { + void SetValue( string name, float x, float y ); + void SetValue( string param, ITexture texture ); + void Commit(); + void Render( Action a ); + } + + public interface ITexture + { + void SetData(Bitmap bitmap); + void SetData(uint[,] colors); + void SetData(byte[] colors, int width, int height); + } + + public enum PrimitiveType + { + PointList, + LineList, + TriangleList, + } + + public struct Range + { + public readonly T Start, End; + public Range( T start, T end ) { Start = start; End = end; } + } + + public enum WindowMode + { + Windowed, + Fullscreen, + PseudoFullscreen, + } +} diff --git a/OpenRA.FileFormats/Graphics/IInputHandler.cs b/OpenRA.FileFormats/Graphics/IInputHandler.cs index 64e42144e6..43c0d7d483 100755 --- a/OpenRA.FileFormats/Graphics/IInputHandler.cs +++ b/OpenRA.FileFormats/Graphics/IInputHandler.cs @@ -1,71 +1,71 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA -{ - public interface IInputHandler - { - void ModifierKeys( Modifiers mods ); - void OnKeyInput( KeyInput input ); - void OnMouseInput( MouseInput input ); - } - - public struct MouseInput - { - public MouseInputEvent Event; - public MouseButton Button; - public int2 Location; - public Modifiers Modifiers; - - public MouseInput( MouseInputEvent ev, MouseButton button, int2 location, Modifiers mods ) - { - this.Event = ev; - this.Button = button; - this.Location = location; - this.Modifiers = mods; - } - } - - public enum MouseInputEvent { Down, Move, Up }; - - [Flags] - public enum MouseButton - { - None = 0, - Left = 1, - Right = 2, - Middle = 4, - WheelDown = 8, - WheelUp = 16 - } - - [Flags] - public enum Modifiers - { - None = 0, - Shift = 1, - Alt = 2, - Ctrl = 4, - } - - public enum KeyInputEvent { Down, Up }; - public struct KeyInput - { - public KeyInputEvent Event; - public char KeyChar; - public string KeyName; - public Modifiers Modifiers; - public int VirtKey; - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA +{ + public interface IInputHandler + { + void ModifierKeys( Modifiers mods ); + void OnKeyInput( KeyInput input ); + void OnMouseInput( MouseInput input ); + } + + public struct MouseInput + { + public MouseInputEvent Event; + public MouseButton Button; + public int2 Location; + public Modifiers Modifiers; + + public MouseInput( MouseInputEvent ev, MouseButton button, int2 location, Modifiers mods ) + { + this.Event = ev; + this.Button = button; + this.Location = location; + this.Modifiers = mods; + } + } + + public enum MouseInputEvent { Down, Move, Up }; + + [Flags] + public enum MouseButton + { + None = 0, + Left = 1, + Right = 2, + Middle = 4, + WheelDown = 8, + WheelUp = 16 + } + + [Flags] + public enum Modifiers + { + None = 0, + Shift = 1, + Alt = 2, + Ctrl = 4, + } + + public enum KeyInputEvent { Down, Up }; + public struct KeyInput + { + public KeyInputEvent Event; + public char KeyChar; + public string KeyName; + public Modifiers Modifiers; + public int VirtKey; + } +} diff --git a/OpenRA.FileFormats/Graphics/ShpReader.cs b/OpenRA.FileFormats/Graphics/ShpReader.cs index e734d42b98..3e99905c81 100644 --- a/OpenRA.FileFormats/Graphics/ShpReader.cs +++ b/OpenRA.FileFormats/Graphics/ShpReader.cs @@ -1,178 +1,178 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections; -using System.Collections.Generic; -using System.Drawing; -using System.IO; - -namespace OpenRA.FileFormats -{ - public class ImageHeader - { - public uint Offset; - public Format Format; - - public uint RefOffset; - public Format RefFormat; - public ImageHeader RefImage; - - public byte[] Image; - - public ImageHeader() { } - - public ImageHeader( BinaryReader reader ) - { - Offset = reader.ReadUInt32(); - Format = (Format)( Offset >> 24 ); - Offset &= 0xFFFFFF; - - RefOffset = reader.ReadUInt16(); - RefFormat = (Format)reader.ReadUInt16(); - } - - public static readonly int SizeOnDisk = 8; - - public void WriteTo(BinaryWriter writer) - { - writer.Write(Offset | ((uint)Format << 24)); - writer.Write((ushort)RefOffset); - writer.Write((ushort)RefFormat); - } - } - - public enum Format - { - Format20 = 0x20, - Format40 = 0x40, - Format80 = 0x80, - } - - public class ShpReader : IEnumerable - { - public readonly int ImageCount; - public readonly ushort Width; - public readonly ushort Height; - - public Size Size { get { return new Size(Width, Height); } } - - private readonly List headers = new List(); - - int recurseDepth = 0; - - public ShpReader( Stream stream ) - { - BinaryReader reader = new BinaryReader( stream ); - - ImageCount = reader.ReadUInt16(); - reader.ReadUInt16(); - reader.ReadUInt16(); - Width = reader.ReadUInt16(); - Height = reader.ReadUInt16(); - reader.ReadUInt32(); - - for( int i = 0 ; i < ImageCount ; i++ ) - headers.Add( new ImageHeader( reader ) ); - - new ImageHeader( reader ); // end-of-file header - new ImageHeader( reader ); // all-zeroes header - - Dictionary offsets = new Dictionary(); - foreach( ImageHeader h in headers ) - offsets.Add( h.Offset, h ); - - for( int i = 0 ; i < ImageCount ; i++ ) - { - ImageHeader h = headers[ i ]; - if( h.Format == Format.Format20 ) - h.RefImage = headers[ i - 1 ]; - - else if( h.Format == Format.Format40 ) - { - if( !offsets.TryGetValue( h.RefOffset, out h.RefImage ) ) - throw new InvalidDataException( string.Format( "Reference doesnt point to image data {0}->{1}", h.Offset, h.RefOffset ) ); - } - } - - foreach( ImageHeader h in headers ) - Decompress( stream, h ); - } - - public ImageHeader this[ int index ] - { - get { return headers[ index ]; } - } - - void Decompress( Stream stream, ImageHeader h ) - { - if( recurseDepth > ImageCount ) - throw new InvalidDataException( "Format20/40 headers contain infinite loop" ); - - switch( h.Format ) - { - case Format.Format20: - case Format.Format40: - { - if( h.RefImage.Image == null ) - { - ++recurseDepth; - Decompress( stream, h.RefImage ); - --recurseDepth; - } - - h.Image = CopyImageData( h.RefImage.Image ); - Format40.DecodeInto(ReadCompressedData(stream, h), h.Image); - break; - } - case Format.Format80: - { - byte[] imageBytes = new byte[ Width * Height ]; - Format80.DecodeInto( ReadCompressedData( stream, h ), imageBytes ); - h.Image = imageBytes; - break; - } - default: - throw new InvalidDataException(); - } - } - - static byte[] ReadCompressedData( Stream stream, ImageHeader h ) - { - stream.Position = h.Offset; - // Actually, far too big. There's no length field with the correct length though :( - int compressedLength = (int)( stream.Length - stream.Position ); - - byte[] compressedBytes = new byte[ compressedLength ]; - stream.Read( compressedBytes, 0, compressedLength ); - - //MemoryStream ms = new MemoryStream( compressedBytes ); - return compressedBytes; - } - - private byte[] CopyImageData( byte[] baseImage ) - { - byte[] imageData = new byte[ Width * Height ]; - for( int i = 0 ; i < Width * Height ; i++ ) - imageData[ i ] = baseImage[ i ]; - - return imageData; - } - - public IEnumerator GetEnumerator() - { - return headers.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.IO; + +namespace OpenRA.FileFormats +{ + public class ImageHeader + { + public uint Offset; + public Format Format; + + public uint RefOffset; + public Format RefFormat; + public ImageHeader RefImage; + + public byte[] Image; + + public ImageHeader() { } + + public ImageHeader( BinaryReader reader ) + { + Offset = reader.ReadUInt32(); + Format = (Format)( Offset >> 24 ); + Offset &= 0xFFFFFF; + + RefOffset = reader.ReadUInt16(); + RefFormat = (Format)reader.ReadUInt16(); + } + + public static readonly int SizeOnDisk = 8; + + public void WriteTo(BinaryWriter writer) + { + writer.Write(Offset | ((uint)Format << 24)); + writer.Write((ushort)RefOffset); + writer.Write((ushort)RefFormat); + } + } + + public enum Format + { + Format20 = 0x20, + Format40 = 0x40, + Format80 = 0x80, + } + + public class ShpReader : IEnumerable + { + public readonly int ImageCount; + public readonly ushort Width; + public readonly ushort Height; + + public Size Size { get { return new Size(Width, Height); } } + + private readonly List headers = new List(); + + int recurseDepth = 0; + + public ShpReader( Stream stream ) + { + BinaryReader reader = new BinaryReader( stream ); + + ImageCount = reader.ReadUInt16(); + reader.ReadUInt16(); + reader.ReadUInt16(); + Width = reader.ReadUInt16(); + Height = reader.ReadUInt16(); + reader.ReadUInt32(); + + for( int i = 0 ; i < ImageCount ; i++ ) + headers.Add( new ImageHeader( reader ) ); + + new ImageHeader( reader ); // end-of-file header + new ImageHeader( reader ); // all-zeroes header + + Dictionary offsets = new Dictionary(); + foreach( ImageHeader h in headers ) + offsets.Add( h.Offset, h ); + + for( int i = 0 ; i < ImageCount ; i++ ) + { + ImageHeader h = headers[ i ]; + if( h.Format == Format.Format20 ) + h.RefImage = headers[ i - 1 ]; + + else if( h.Format == Format.Format40 ) + { + if( !offsets.TryGetValue( h.RefOffset, out h.RefImage ) ) + throw new InvalidDataException( string.Format( "Reference doesnt point to image data {0}->{1}", h.Offset, h.RefOffset ) ); + } + } + + foreach( ImageHeader h in headers ) + Decompress( stream, h ); + } + + public ImageHeader this[ int index ] + { + get { return headers[ index ]; } + } + + void Decompress( Stream stream, ImageHeader h ) + { + if( recurseDepth > ImageCount ) + throw new InvalidDataException( "Format20/40 headers contain infinite loop" ); + + switch( h.Format ) + { + case Format.Format20: + case Format.Format40: + { + if( h.RefImage.Image == null ) + { + ++recurseDepth; + Decompress( stream, h.RefImage ); + --recurseDepth; + } + + h.Image = CopyImageData( h.RefImage.Image ); + Format40.DecodeInto(ReadCompressedData(stream, h), h.Image); + break; + } + case Format.Format80: + { + byte[] imageBytes = new byte[ Width * Height ]; + Format80.DecodeInto( ReadCompressedData( stream, h ), imageBytes ); + h.Image = imageBytes; + break; + } + default: + throw new InvalidDataException(); + } + } + + static byte[] ReadCompressedData( Stream stream, ImageHeader h ) + { + stream.Position = h.Offset; + // Actually, far too big. There's no length field with the correct length though :( + int compressedLength = (int)( stream.Length - stream.Position ); + + byte[] compressedBytes = new byte[ compressedLength ]; + stream.Read( compressedBytes, 0, compressedLength ); + + //MemoryStream ms = new MemoryStream( compressedBytes ); + return compressedBytes; + } + + private byte[] CopyImageData( byte[] baseImage ) + { + byte[] imageData = new byte[ Width * Height ]; + for( int i = 0 ; i < Width * Height ; i++ ) + imageData[ i ] = baseImage[ i ]; + + return imageData; + } + + public IEnumerator GetEnumerator() + { + return headers.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/OpenRA.FileFormats/Graphics/Vertex.cs b/OpenRA.FileFormats/Graphics/Vertex.cs index e6f6672293..e52231f3bc 100644 --- a/OpenRA.FileFormats/Graphics/Vertex.cs +++ b/OpenRA.FileFormats/Graphics/Vertex.cs @@ -1,28 +1,28 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Runtime.InteropServices; - -namespace OpenRA.FileFormats.Graphics -{ - [StructLayout(LayoutKind.Sequential)] - public struct Vertex - { - public float x, y, z, u, v; - public float p, c; - - public Vertex(float2 xy, float2 uv, float2 pc) - { - this.x = xy.X; this.y = xy.Y; this.z = 0; - this.u = uv.X; this.v = uv.Y; - this.p = pc.X; this.c = pc.Y; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Runtime.InteropServices; + +namespace OpenRA.FileFormats.Graphics +{ + [StructLayout(LayoutKind.Sequential)] + public struct Vertex + { + public float x, y, z, u, v; + public float p, c; + + public Vertex(float2 xy, float2 uv, float2 pc) + { + this.x = xy.X; this.y = xy.Y; this.z = 0; + this.u = uv.X; this.v = uv.Y; + this.p = pc.X; this.c = pc.Y; + } + } +} diff --git a/OpenRA.FileFormats/Graphics/VqaReader.cs b/OpenRA.FileFormats/Graphics/VqaReader.cs index d7e75d1f34..da0aaa48bb 100644 --- a/OpenRA.FileFormats/Graphics/VqaReader.cs +++ b/OpenRA.FileFormats/Graphics/VqaReader.cs @@ -1,16 +1,16 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System; -using System.IO; - +#endregion + +using System; +using System.IO; + namespace OpenRA.FileFormats { public class VqaReader @@ -40,10 +40,10 @@ namespace OpenRA.FileFormats byte[] origData; // Final frame output - uint[,] frameData; - byte[] audioData; // audio for this frame: 22050Hz 16bit mono pcm, uncompressed. - - public byte[] AudioData { get { return audioData; } } + uint[,] frameData; + byte[] audioData; // audio for this frame: 22050Hz 16bit mono pcm, uncompressed. + + public byte[] AudioData { get { return audioData; } } public int CurrentFrame { get { return currentFrame; } } public VqaReader( Stream stream ) @@ -108,62 +108,62 @@ namespace OpenRA.FileFormats offsets[i] = reader.ReadUInt32(); if (offsets[i] > 0x40000000) offsets[i] -= 0x40000000; offsets[i] <<= 1; - } - + } + CollectAudioData(); Reset(); - } + } public void Reset() { currentFrame = cbOffset = cbChunk = 0; LoadFrame(); } - - void CollectAudioData() - { - var ms = new MemoryStream(); - var adpcmIndex = 0; + + void CollectAudioData() + { + var ms = new MemoryStream(); + var adpcmIndex = 0; - bool compressed = false; - for (var i = 0; i < Frames; i++) - { - stream.Seek(offsets[i], SeekOrigin.Begin); - BinaryReader reader = new BinaryReader(stream); - var end = (i < Frames - 1) ? offsets[i + 1] : stream.Length; - - while (reader.BaseStream.Position < end) - { - var type = new String(reader.ReadChars(4)); - var length = int2.Swap(reader.ReadUInt32()); - - switch (type) - { + bool compressed = false; + for (var i = 0; i < Frames; i++) + { + stream.Seek(offsets[i], SeekOrigin.Begin); + BinaryReader reader = new BinaryReader(stream); + var end = (i < Frames - 1) ? offsets[i + 1] : stream.Length; + + while (reader.BaseStream.Position < end) + { + var type = new String(reader.ReadChars(4)); + var length = int2.Swap(reader.ReadUInt32()); + + switch (type) + { case "SND0": case "SND2": var rawAudio = reader.ReadBytes((int)length); ms.Write(rawAudio); compressed = (type == "SND2"); - break; - default: - reader.ReadBytes((int)length); - break; - } - - if (reader.PeekChar() == 0) reader.ReadByte(); - } - } - - audioData = (compressed) ? AudLoader.LoadSound(ms.ToArray(), ref adpcmIndex) : ms.ToArray(); - } + break; + default: + reader.ReadBytes((int)length); + break; + } + + if (reader.PeekChar() == 0) reader.ReadByte(); + } + } + + audioData = (compressed) ? AudLoader.LoadSound(ms.ToArray(), ref adpcmIndex) : ms.ToArray(); + } public void AdvanceFrame() { currentFrame++; LoadFrame(); } - + void LoadFrame() { if (currentFrame >= Frames) @@ -180,7 +180,7 @@ namespace OpenRA.FileFormats var length = int2.Swap(reader.ReadUInt32()); switch(type) - { + { case "VQFR": DecodeVQFR(reader); break; diff --git a/OpenRA.FileFormats/HttpUtil.cs b/OpenRA.FileFormats/HttpUtil.cs index e2a34d38df..1f3c1b22ab 100644 --- a/OpenRA.FileFormats/HttpUtil.cs +++ b/OpenRA.FileFormats/HttpUtil.cs @@ -1,97 +1,97 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.IO; -using System.Net; -using System.Net.Sockets; -using System.Text; - -namespace OpenRA.FileFormats -{ - public static class HttpUtil - { - public static byte[] DownloadData(string url, Action f, int chunkSize) - { - var uri = new Uri(url); - var ip = Dns.GetHostEntry(uri.DnsSafeHost).AddressList[0]; - - using (var s = new TcpClient()) - { - s.Connect(new IPEndPoint(ip, uri.Port)); - var ns = s.GetStream(); - var sw = new StreamWriter(ns); - - sw.Write("GET {0} HTTP/1.0\r\nHost:{1}\r\n\r\n", uri.PathAndQuery, uri.Host); - sw.Flush(); - - var br = new BinaryReader(ns); - var contentLength = 0; - var offset = 0; - for (; ; ) - { - var result = br.ReadLine(); - var kv = result.Split(new string[] { ": " }, StringSplitOptions.RemoveEmptyEntries); - - if (result == "") - { - /* data follows the blank line */ - - if (contentLength > 0) - { - if (f != null) - f(offset, contentLength); - - var data = new byte[contentLength]; - while (offset < contentLength) - { - var thisChunk = Math.Min(contentLength - offset, chunkSize); - br.Read(data, offset, thisChunk); - offset += thisChunk; - if (f != null) - f(offset, contentLength); - } - s.Close(); - return data; - } - else - { - s.Close(); - return new byte[] { }; - } - } - else if (kv[0] == "Content-Length") - contentLength = int.Parse(kv[1]); - } - } - } - - public static byte[] DownloadData(string url, Action f) - { - return DownloadData(url, f, 4096); - } - - public static byte[] DownloadData(string url) - { - return DownloadData(url, null); - } - - static string ReadLine(this BinaryReader br) - { - var sb = new StringBuilder(); - char c; - while ((c = br.ReadChar()) != '\n') - if (c != '\r' && c != '\n') - sb.Append(c); - - return sb.ToString(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace OpenRA.FileFormats +{ + public static class HttpUtil + { + public static byte[] DownloadData(string url, Action f, int chunkSize) + { + var uri = new Uri(url); + var ip = Dns.GetHostEntry(uri.DnsSafeHost).AddressList[0]; + + using (var s = new TcpClient()) + { + s.Connect(new IPEndPoint(ip, uri.Port)); + var ns = s.GetStream(); + var sw = new StreamWriter(ns); + + sw.Write("GET {0} HTTP/1.0\r\nHost:{1}\r\n\r\n", uri.PathAndQuery, uri.Host); + sw.Flush(); + + var br = new BinaryReader(ns); + var contentLength = 0; + var offset = 0; + for (; ; ) + { + var result = br.ReadLine(); + var kv = result.Split(new string[] { ": " }, StringSplitOptions.RemoveEmptyEntries); + + if (result == "") + { + /* data follows the blank line */ + + if (contentLength > 0) + { + if (f != null) + f(offset, contentLength); + + var data = new byte[contentLength]; + while (offset < contentLength) + { + var thisChunk = Math.Min(contentLength - offset, chunkSize); + br.Read(data, offset, thisChunk); + offset += thisChunk; + if (f != null) + f(offset, contentLength); + } + s.Close(); + return data; + } + else + { + s.Close(); + return new byte[] { }; + } + } + else if (kv[0] == "Content-Length") + contentLength = int.Parse(kv[1]); + } + } + } + + public static byte[] DownloadData(string url, Action f) + { + return DownloadData(url, f, 4096); + } + + public static byte[] DownloadData(string url) + { + return DownloadData(url, null); + } + + static string ReadLine(this BinaryReader br) + { + var sb = new StringBuilder(); + char c; + while ((c = br.ReadChar()) != '\n') + if (c != '\r' && c != '\n') + sb.Append(c); + + return sb.ToString(); + } + } +} diff --git a/OpenRA.FileFormats/Manifest.cs b/OpenRA.FileFormats/Manifest.cs index 905b30e055..01866720e9 100644 --- a/OpenRA.FileFormats/Manifest.cs +++ b/OpenRA.FileFormats/Manifest.cs @@ -1,65 +1,65 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.FileFormats -{ - /* describes what is to be loaded in order to run a set of mods */ - - public class Manifest - { - public readonly string[] - Mods, Folders, Packages, Rules, ServerTraits, - Sequences, Cursors, Chrome, Assemblies, ChromeLayout, - Weapons, Voices, Music, Movies, TileSets; - public readonly string LoadScreen; - public readonly int TileSize = 24; - - public Manifest(string[] mods) - { - Mods = mods; - var yaml = mods - .Select(m => MiniYaml.FromFile("mods/" + m + "/mod.yaml")) - .Aggregate(MiniYaml.Merge); - - // Todo: Use fieldloader - Folders = YamlList(yaml, "Folders"); - Packages = YamlList(yaml, "Packages"); - Rules = YamlList(yaml, "Rules"); - ServerTraits = YamlList(yaml, "ServerTraits"); - Sequences = YamlList(yaml, "Sequences"); - Cursors = YamlList(yaml, "Cursors"); - Chrome = YamlList(yaml, "Chrome"); - Assemblies = YamlList(yaml, "Assemblies"); - ChromeLayout = YamlList(yaml, "ChromeLayout"); - Weapons = YamlList(yaml, "Weapons"); - Voices = YamlList(yaml, "Voices"); - Music = YamlList(yaml, "Music"); - Movies = YamlList(yaml, "Movies"); - TileSets = YamlList(yaml, "TileSets"); - - LoadScreen = yaml.First( x => x.Key == "LoadScreen" ).Value.Value; - - if (yaml.FirstOrDefault( x => x.Key == "TileSize" ) != null) - TileSize = int.Parse(yaml.First( x => x.Key == "TileSize" ).Value.Value); - } - - static string[] YamlList(List ys, string key) - { - var y = ys.FirstOrDefault( x => x.Key == key ); - if( y == null ) - return new string[ 0 ]; - - return y.Value.NodesDict.Keys.ToArray(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.FileFormats +{ + /* describes what is to be loaded in order to run a set of mods */ + + public class Manifest + { + public readonly string[] + Mods, Folders, Packages, Rules, ServerTraits, + Sequences, Cursors, Chrome, Assemblies, ChromeLayout, + Weapons, Voices, Music, Movies, TileSets; + public readonly string LoadScreen; + public readonly int TileSize = 24; + + public Manifest(string[] mods) + { + Mods = mods; + var yaml = mods + .Select(m => MiniYaml.FromFile("mods/" + m + "/mod.yaml")) + .Aggregate(MiniYaml.Merge); + + // Todo: Use fieldloader + Folders = YamlList(yaml, "Folders"); + Packages = YamlList(yaml, "Packages"); + Rules = YamlList(yaml, "Rules"); + ServerTraits = YamlList(yaml, "ServerTraits"); + Sequences = YamlList(yaml, "Sequences"); + Cursors = YamlList(yaml, "Cursors"); + Chrome = YamlList(yaml, "Chrome"); + Assemblies = YamlList(yaml, "Assemblies"); + ChromeLayout = YamlList(yaml, "ChromeLayout"); + Weapons = YamlList(yaml, "Weapons"); + Voices = YamlList(yaml, "Voices"); + Music = YamlList(yaml, "Music"); + Movies = YamlList(yaml, "Movies"); + TileSets = YamlList(yaml, "TileSets"); + + LoadScreen = yaml.First( x => x.Key == "LoadScreen" ).Value.Value; + + if (yaml.FirstOrDefault( x => x.Key == "TileSize" ) != null) + TileSize = int.Parse(yaml.First( x => x.Key == "TileSize" ).Value.Value); + } + + static string[] YamlList(List ys, string key) + { + var y = ys.FirstOrDefault( x => x.Key == key ); + if( y == null ) + return new string[ 0 ]; + + return y.Value.NodesDict.Keys.ToArray(); + } + } +} diff --git a/OpenRA.FileFormats/Map/PlayerReference.cs b/OpenRA.FileFormats/Map/PlayerReference.cs index e7335cd765..3878e3679c 100644 --- a/OpenRA.FileFormats/Map/PlayerReference.cs +++ b/OpenRA.FileFormats/Map/PlayerReference.cs @@ -1,14 +1,14 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ #endregion -using System.Drawing; +using System.Drawing; using System; namespace OpenRA.FileFormats @@ -18,21 +18,21 @@ namespace OpenRA.FileFormats public string Name; public string Palette; public bool OwnsWorld = false; - public bool NonCombatant = false; - public bool Playable = false; + public bool NonCombatant = false; + public bool Playable = false; public bool DefaultStartingUnits = false; - public bool AllowBots = true; - - public bool LockRace = false; - public string Race; - - public bool LockColor = false; - public ColorRamp ColorRamp = new ColorRamp(75, 255, 180, 25); - - public int InitialCash = 0; - public string[] Allies = {}; + public bool AllowBots = true; + + public bool LockRace = false; + public string Race; + + public bool LockColor = false; + public ColorRamp ColorRamp = new ColorRamp(75, 255, 180, 25); + + public int InitialCash = 0; + public string[] Allies = {}; public string[] Enemies = {}; - + public PlayerReference() {} public PlayerReference(MiniYaml my) { diff --git a/OpenRA.FileFormats/Map/SmudgeReference.cs b/OpenRA.FileFormats/Map/SmudgeReference.cs index ec9816de47..fcacdc3adf 100644 --- a/OpenRA.FileFormats/Map/SmudgeReference.cs +++ b/OpenRA.FileFormats/Map/SmudgeReference.cs @@ -1,11 +1,11 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ #endregion namespace OpenRA.FileFormats diff --git a/OpenRA.FileFormats/Map/Terrain.cs b/OpenRA.FileFormats/Map/Terrain.cs index fce7f191e5..0707e3a71c 100644 --- a/OpenRA.FileFormats/Map/Terrain.cs +++ b/OpenRA.FileFormats/Map/Terrain.cs @@ -1,76 +1,76 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.IO; - -namespace OpenRA.FileFormats -{ - public class Terrain - { - public readonly List TileBitmapBytes = new List(); - - public Terrain( Stream stream, int size ) - { - // Try loading as a cnc .tem - BinaryReader reader = new BinaryReader( stream ); - int Width = reader.ReadUInt16(); - int Height = reader.ReadUInt16(); - - if( Width != size || Height != size ) - throw new InvalidDataException( "{0}x{1} != {2}x{2}".F(Width, Height, size ) ); - - /*NumTiles = */reader.ReadUInt16(); - /*Zero1 = */reader.ReadUInt16(); - /*uint Size = */reader.ReadUInt32(); - uint ImgStart = reader.ReadUInt32(); - /*Zero2 = */reader.ReadUInt32(); - - int IndexEnd, IndexStart; - if (reader.ReadUInt16() == 65535) // ID1 = FFFFh for cnc - { - /*ID2 = */reader.ReadUInt16(); - IndexEnd = reader.ReadInt32(); - IndexStart = reader.ReadInt32(); - } - else // Load as a ra .tem - { - stream.Position = 0; - reader = new BinaryReader( stream ); - Width = reader.ReadUInt16(); - Height = reader.ReadUInt16(); - - /*NumTiles = */reader.ReadUInt16(); - reader.ReadUInt16(); - /*XDim = */reader.ReadUInt16(); - /*YDim = */reader.ReadUInt16(); - /*uint FileSize = */reader.ReadUInt32(); - ImgStart = reader.ReadUInt32(); - reader.ReadUInt32(); - reader.ReadUInt32(); - IndexEnd = reader.ReadInt32(); - reader.ReadUInt32(); - IndexStart = reader.ReadInt32(); - } - stream.Position = IndexStart; - - foreach( byte b in new BinaryReader(stream).ReadBytes(IndexEnd - IndexStart) ) - { - if (b != 255) - { - stream.Position = ImgStart + b * size * size; - TileBitmapBytes.Add(new BinaryReader(stream).ReadBytes(size * size)); - } - else - TileBitmapBytes.Add(null); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.IO; + +namespace OpenRA.FileFormats +{ + public class Terrain + { + public readonly List TileBitmapBytes = new List(); + + public Terrain( Stream stream, int size ) + { + // Try loading as a cnc .tem + BinaryReader reader = new BinaryReader( stream ); + int Width = reader.ReadUInt16(); + int Height = reader.ReadUInt16(); + + if( Width != size || Height != size ) + throw new InvalidDataException( "{0}x{1} != {2}x{2}".F(Width, Height, size ) ); + + /*NumTiles = */reader.ReadUInt16(); + /*Zero1 = */reader.ReadUInt16(); + /*uint Size = */reader.ReadUInt32(); + uint ImgStart = reader.ReadUInt32(); + /*Zero2 = */reader.ReadUInt32(); + + int IndexEnd, IndexStart; + if (reader.ReadUInt16() == 65535) // ID1 = FFFFh for cnc + { + /*ID2 = */reader.ReadUInt16(); + IndexEnd = reader.ReadInt32(); + IndexStart = reader.ReadInt32(); + } + else // Load as a ra .tem + { + stream.Position = 0; + reader = new BinaryReader( stream ); + Width = reader.ReadUInt16(); + Height = reader.ReadUInt16(); + + /*NumTiles = */reader.ReadUInt16(); + reader.ReadUInt16(); + /*XDim = */reader.ReadUInt16(); + /*YDim = */reader.ReadUInt16(); + /*uint FileSize = */reader.ReadUInt32(); + ImgStart = reader.ReadUInt32(); + reader.ReadUInt32(); + reader.ReadUInt32(); + IndexEnd = reader.ReadInt32(); + reader.ReadUInt32(); + IndexStart = reader.ReadInt32(); + } + stream.Position = IndexStart; + + foreach( byte b in new BinaryReader(stream).ReadBytes(IndexEnd - IndexStart) ) + { + if (b != 255) + { + stream.Position = ImgStart + b * size * size; + TileBitmapBytes.Add(new BinaryReader(stream).ReadBytes(size * size)); + } + else + TileBitmapBytes.Add(null); + } + } + } +} diff --git a/OpenRA.FileFormats/Map/TileReference.cs b/OpenRA.FileFormats/Map/TileReference.cs index 91fd67c686..be12a97943 100644 --- a/OpenRA.FileFormats/Map/TileReference.cs +++ b/OpenRA.FileFormats/Map/TileReference.cs @@ -1,11 +1,11 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ #endregion namespace OpenRA.FileFormats diff --git a/OpenRA.FileFormats/Map/TileSet.cs b/OpenRA.FileFormats/Map/TileSet.cs index 6d28b854c9..26fec9b81d 100644 --- a/OpenRA.FileFormats/Map/TileSet.cs +++ b/OpenRA.FileFormats/Map/TileSet.cs @@ -1,157 +1,157 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Reflection; - -namespace OpenRA.FileFormats -{ - public class TerrainTypeInfo - { - public string Type; - public bool Buildable = true; - public bool AcceptSmudge = true; - public bool IsWater = false; - public Color Color; - - public TerrainTypeInfo() {} - public TerrainTypeInfo(MiniYaml my) { FieldLoader.Load(this, my); } - public MiniYaml Save() { return FieldSaver.Save(this); } - } - - public class TileTemplate - { - [FieldLoader.Load] public ushort Id; - [FieldLoader.Load] public string Image; - [FieldLoader.Load] public int2 Size; - [FieldLoader.Load] public bool PickAny; - - [FieldLoader.LoadUsing( "LoadTiles" )] - public Dictionary Tiles = new Dictionary(); - - public TileTemplate() {} - public TileTemplate(MiniYaml my) - { - FieldLoader.Load( this, my ); - } - - static object LoadTiles( MiniYaml y ) - { - return y.NodesDict["Tiles"].NodesDict.ToDictionary( - t => byte.Parse(t.Key), - t => t.Value.Value ); - } - - public MiniYaml Save() - { - var root = new List(); - foreach (var field in new string[] {"Id", "Image", "Size", "PickAny"}) - { - FieldInfo f = this.GetType().GetField(field); - if (f.GetValue(this) == null) continue; - root.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) ); - } - - root.Add( new MiniYamlNode( "Tiles", null, - Tiles.Select( x => new MiniYamlNode( x.Key.ToString(), x.Value ) ).ToList() ) ); - - return new MiniYaml(null, root); - } - } - - public class TileSet - { - public string Name; - public string Id; - public string Palette; - public int TileSize = 24; - public string[] Extensions; - public Dictionary Terrain = new Dictionary(); - public Dictionary Tiles = new Dictionary(); - public Dictionary Templates = new Dictionary(); - static List fields = new List() {"Name", "TileSize", "Id", "Palette", "Extensions"}; - - public TileSet() {} - public TileSet( string filepath ) - { - var yaml = MiniYaml.DictFromFile( filepath ); - - // General info - FieldLoader.Load(this, yaml["General"]); - - // TerrainTypes - Terrain = yaml["Terrain"].NodesDict.Values - .Select(y => new TerrainTypeInfo(y)).ToDictionary(t => t.Type); - - // Templates - Templates = yaml["Templates"].NodesDict.Values - .Select(y => new TileTemplate(y)).ToDictionary(t => t.Id); - } - - public void LoadTiles() - { - foreach (var t in Templates) - using( Stream s = FileSystem.OpenWithExts(t.Value.Image, Extensions) ) - { - if( !Tiles.ContainsKey( t.Key ) ) - Tiles.Add( t.Key, new Terrain( s, TileSize ) ); - } - } - - public void Save(string filepath) - { - var root = new List(); - var gen = new List(); - foreach (var field in fields) - { - FieldInfo f = this.GetType().GetField(field); - if (f.GetValue(this) == null) continue; - gen.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) ); - } - root.Add( new MiniYamlNode( "General", null, gen ) ); - - root.Add( new MiniYamlNode( "Terrain", null, - Terrain.Select( t => new MiniYamlNode( - "TerrainType@{0}".F( t.Value.Type ), - t.Value.Save() ) ).ToList() ) ); - - root.Add( new MiniYamlNode( "Templates", null, - Templates.Select( t => new MiniYamlNode( - "Template@{0}".F( t.Value.Id ), - t.Value.Save() ) ).ToList() ) ); - root.WriteToFile(filepath); - } - - public byte[] GetBytes(TileReference r) - { - Terrain tile; - if( Tiles.TryGetValue( r.type, out tile ) ) - return tile.TileBitmapBytes[ r.index ]; - - byte[] missingTile = new byte[ TileSize * TileSize ]; - for( int i = 0 ; i < missingTile.Length ; i++ ) - missingTile[ i ] = 0x36; - - return missingTile; - } - - public string GetTerrainType(TileReference r) - { - var tt = Templates[r.type].Tiles; - string ret; - if (!tt.TryGetValue(r.index, out ret)) - return "Clear"; // Default walkable - return ret; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace OpenRA.FileFormats +{ + public class TerrainTypeInfo + { + public string Type; + public bool Buildable = true; + public bool AcceptSmudge = true; + public bool IsWater = false; + public Color Color; + + public TerrainTypeInfo() {} + public TerrainTypeInfo(MiniYaml my) { FieldLoader.Load(this, my); } + public MiniYaml Save() { return FieldSaver.Save(this); } + } + + public class TileTemplate + { + [FieldLoader.Load] public ushort Id; + [FieldLoader.Load] public string Image; + [FieldLoader.Load] public int2 Size; + [FieldLoader.Load] public bool PickAny; + + [FieldLoader.LoadUsing( "LoadTiles" )] + public Dictionary Tiles = new Dictionary(); + + public TileTemplate() {} + public TileTemplate(MiniYaml my) + { + FieldLoader.Load( this, my ); + } + + static object LoadTiles( MiniYaml y ) + { + return y.NodesDict["Tiles"].NodesDict.ToDictionary( + t => byte.Parse(t.Key), + t => t.Value.Value ); + } + + public MiniYaml Save() + { + var root = new List(); + foreach (var field in new string[] {"Id", "Image", "Size", "PickAny"}) + { + FieldInfo f = this.GetType().GetField(field); + if (f.GetValue(this) == null) continue; + root.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) ); + } + + root.Add( new MiniYamlNode( "Tiles", null, + Tiles.Select( x => new MiniYamlNode( x.Key.ToString(), x.Value ) ).ToList() ) ); + + return new MiniYaml(null, root); + } + } + + public class TileSet + { + public string Name; + public string Id; + public string Palette; + public int TileSize = 24; + public string[] Extensions; + public Dictionary Terrain = new Dictionary(); + public Dictionary Tiles = new Dictionary(); + public Dictionary Templates = new Dictionary(); + static List fields = new List() {"Name", "TileSize", "Id", "Palette", "Extensions"}; + + public TileSet() {} + public TileSet( string filepath ) + { + var yaml = MiniYaml.DictFromFile( filepath ); + + // General info + FieldLoader.Load(this, yaml["General"]); + + // TerrainTypes + Terrain = yaml["Terrain"].NodesDict.Values + .Select(y => new TerrainTypeInfo(y)).ToDictionary(t => t.Type); + + // Templates + Templates = yaml["Templates"].NodesDict.Values + .Select(y => new TileTemplate(y)).ToDictionary(t => t.Id); + } + + public void LoadTiles() + { + foreach (var t in Templates) + using( Stream s = FileSystem.OpenWithExts(t.Value.Image, Extensions) ) + { + if( !Tiles.ContainsKey( t.Key ) ) + Tiles.Add( t.Key, new Terrain( s, TileSize ) ); + } + } + + public void Save(string filepath) + { + var root = new List(); + var gen = new List(); + foreach (var field in fields) + { + FieldInfo f = this.GetType().GetField(field); + if (f.GetValue(this) == null) continue; + gen.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) ); + } + root.Add( new MiniYamlNode( "General", null, gen ) ); + + root.Add( new MiniYamlNode( "Terrain", null, + Terrain.Select( t => new MiniYamlNode( + "TerrainType@{0}".F( t.Value.Type ), + t.Value.Save() ) ).ToList() ) ); + + root.Add( new MiniYamlNode( "Templates", null, + Templates.Select( t => new MiniYamlNode( + "Template@{0}".F( t.Value.Id ), + t.Value.Save() ) ).ToList() ) ); + root.WriteToFile(filepath); + } + + public byte[] GetBytes(TileReference r) + { + Terrain tile; + if( Tiles.TryGetValue( r.type, out tile ) ) + return tile.TileBitmapBytes[ r.index ]; + + byte[] missingTile = new byte[ TileSize * TileSize ]; + for( int i = 0 ; i < missingTile.Length ; i++ ) + missingTile[ i ] = 0x36; + + return missingTile; + } + + public string GetTerrainType(TileReference r) + { + var tt = Templates[r.type].Tiles; + string ret; + if (!tt.TryGetValue(r.index, out ret)) + return "Clear"; // Default walkable + return ret; + } + } +} diff --git a/OpenRA.FileFormats/MiniYaml.cs b/OpenRA.FileFormats/MiniYaml.cs index 3533108dc4..fd09ad4608 100755 --- a/OpenRA.FileFormats/MiniYaml.cs +++ b/OpenRA.FileFormats/MiniYaml.cs @@ -1,240 +1,240 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace OpenRA.FileFormats -{ - using MiniYamlNodes = List; - - public class MiniYamlNode - { - public struct SourceLocation - { - public string Filename; public int Line; - } - - public SourceLocation Location; - public string Key; - public MiniYaml Value; - - public MiniYamlNode( string k, MiniYaml v ) - { - Key = k; - Value = v; - } - - public MiniYamlNode( string k, MiniYaml v, SourceLocation loc ) - : this( k, v ) - { - Location = loc; - } - - public MiniYamlNode( string k, string v ) - : this( k, v, null ) - { - } - public MiniYamlNode( string k, string v, List n ) - : this( k, new MiniYaml( v, n ) ) - { - } - - public MiniYamlNode( string k, string v, List n, SourceLocation loc ) - : this( k, new MiniYaml( v, n ), loc ) - { - } - } - - public class MiniYaml - { - public string Value; - public List Nodes; - - public Dictionary NodesDict { get { return Nodes.ToDictionary( x => x.Key, x => x.Value ); } } - - public MiniYaml( string value ) : this( value, null ) { } - - public MiniYaml( string value, List nodes ) - { - Value = value; - Nodes = nodes ?? new List(); - } - - public static MiniYaml FromDictionary( Dictionary dict ) - { - return new MiniYaml( null, dict.Select( x => new MiniYamlNode( x.Key.ToString(), new MiniYaml( x.Value.ToString() ) ) ).ToList() ); - } - - public static MiniYaml FromList( List list ) - { - return new MiniYaml( null, list.Select( x => new MiniYamlNode( x.ToString(), new MiniYaml( null ) ) ).ToList() ); - } - - static List FromLines(string[] lines, string filename) - { - var levels = new List>(); - levels.Add(new List()); - - var lineNo = 0; - foreach (var line in lines) - { - ++lineNo; - var t = line.TrimStart(' ', '\t'); - if (t.Length == 0 || t[0] == '#') - continue; - var level = line.Length - t.Length; - - if (levels.Count <= level) - throw new InvalidOperationException("Bad indent in miniyaml"); - while (levels.Count > level + 1) - levels.RemoveAt(levels.Count - 1); - - var d = new List(); - var rhs = SplitAtColon( ref t ); - levels[ level ].Add( new MiniYamlNode( t, rhs, d, new MiniYamlNode.SourceLocation { Filename = filename, Line = lineNo } ) ); - - levels.Add(d); - } - return levels[ 0 ]; - } - - static string SplitAtColon( ref string t ) - { - var colon = t.IndexOf(':'); - if( colon == -1 ) - return null; - var ret = t.Substring( colon + 1 ).Trim(); - if( ret.Length == 0 ) - ret = null; - t = t.Substring( 0, colon ).Trim(); - return ret; - } - - public static List FromFileInPackage( string path ) - { - StreamReader reader = new StreamReader( FileSystem.Open(path) ); - List lines = new List(); - - while( !reader.EndOfStream ) - lines.Add(reader.ReadLine()); - reader.Close(); - - return FromLines(lines.ToArray(), path); - } - - public static Dictionary DictFromFile( string path ) - { - return FromFile( path ).ToDictionary( x => x.Key, x => x.Value ); - } - - public static Dictionary DictFromStream( Stream stream ) - { - return FromStream( stream ).ToDictionary( x => x.Key, x => x.Value ); - } - - public static List FromFile( string path ) - { - return FromLines(File.ReadAllLines( path ), path); - } - - public static List FromStream(Stream s) - { - using (var reader = new StreamReader(s)) - return FromString(reader.ReadToEnd()); - } - - public static List FromString(string text) - { - return FromLines(text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries), ""); - } - - public static List Merge( List a, List b ) - { - if( a.Count == 0 ) - return b; - if( b.Count == 0 ) - return a; - - var ret = new List(); - - var aDict = a.ToDictionary( x => x.Key ); - var bDict = b.ToDictionary( x => x.Key ); - var keys = aDict.Keys.Union( bDict.Keys ).ToList(); - - var noInherit = keys.Where( x => x.Length > 0 && x[ 0 ] == '-' ).Select( x => x.Substring( 1 ) ).ToList(); - - foreach( var key in keys ) - { - MiniYamlNode aa, bb; - aDict.TryGetValue( key, out aa ); - bDict.TryGetValue( key, out bb ); - - if( noInherit.Contains( key ) ) - { - if( aa != null ) - ret.Add( aa ); - } - else - { - var loc = aa == null ? default( MiniYamlNode.SourceLocation ) : aa.Location; - var merged = ( aa == null || bb == null ) ? aa ?? bb : new MiniYamlNode( key, Merge( aa.Value, bb.Value ), loc ); - ret.Add( merged ); - } - } - - return ret; - } - - public static MiniYaml Merge( MiniYaml a, MiniYaml b ) - { - if( a == null ) - return b; - if( b == null ) - return a; - - return new MiniYaml( a.Value ?? b.Value, Merge( a.Nodes, b.Nodes ) ); - } - - public IEnumerable ToLines(string name) - { - yield return name + ": " + Value; - if (Nodes != null) - foreach (var line in Nodes.ToLines(false)) - yield return "\t" + line; - } - } - - public static class MiniYamlExts - { - public static void WriteToFile(this MiniYamlNodes y, string filename) - { - File.WriteAllLines(filename, y.ToLines(true).Select(x => x.TrimEnd()).ToArray()); - } - - public static string WriteToString(this MiniYamlNodes y) - { - return string.Join("\n", y.ToLines(true).Select(x => x.TrimEnd()).ToArray()); - } - - public static IEnumerable ToLines(this MiniYamlNodes y, bool lowest) - { - foreach (var kv in y) - { - foreach (var line in kv.Value.ToLines(kv.Key)) - yield return line; - if (lowest) - yield return ""; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace OpenRA.FileFormats +{ + using MiniYamlNodes = List; + + public class MiniYamlNode + { + public struct SourceLocation + { + public string Filename; public int Line; + } + + public SourceLocation Location; + public string Key; + public MiniYaml Value; + + public MiniYamlNode( string k, MiniYaml v ) + { + Key = k; + Value = v; + } + + public MiniYamlNode( string k, MiniYaml v, SourceLocation loc ) + : this( k, v ) + { + Location = loc; + } + + public MiniYamlNode( string k, string v ) + : this( k, v, null ) + { + } + public MiniYamlNode( string k, string v, List n ) + : this( k, new MiniYaml( v, n ) ) + { + } + + public MiniYamlNode( string k, string v, List n, SourceLocation loc ) + : this( k, new MiniYaml( v, n ), loc ) + { + } + } + + public class MiniYaml + { + public string Value; + public List Nodes; + + public Dictionary NodesDict { get { return Nodes.ToDictionary( x => x.Key, x => x.Value ); } } + + public MiniYaml( string value ) : this( value, null ) { } + + public MiniYaml( string value, List nodes ) + { + Value = value; + Nodes = nodes ?? new List(); + } + + public static MiniYaml FromDictionary( Dictionary dict ) + { + return new MiniYaml( null, dict.Select( x => new MiniYamlNode( x.Key.ToString(), new MiniYaml( x.Value.ToString() ) ) ).ToList() ); + } + + public static MiniYaml FromList( List list ) + { + return new MiniYaml( null, list.Select( x => new MiniYamlNode( x.ToString(), new MiniYaml( null ) ) ).ToList() ); + } + + static List FromLines(string[] lines, string filename) + { + var levels = new List>(); + levels.Add(new List()); + + var lineNo = 0; + foreach (var line in lines) + { + ++lineNo; + var t = line.TrimStart(' ', '\t'); + if (t.Length == 0 || t[0] == '#') + continue; + var level = line.Length - t.Length; + + if (levels.Count <= level) + throw new InvalidOperationException("Bad indent in miniyaml"); + while (levels.Count > level + 1) + levels.RemoveAt(levels.Count - 1); + + var d = new List(); + var rhs = SplitAtColon( ref t ); + levels[ level ].Add( new MiniYamlNode( t, rhs, d, new MiniYamlNode.SourceLocation { Filename = filename, Line = lineNo } ) ); + + levels.Add(d); + } + return levels[ 0 ]; + } + + static string SplitAtColon( ref string t ) + { + var colon = t.IndexOf(':'); + if( colon == -1 ) + return null; + var ret = t.Substring( colon + 1 ).Trim(); + if( ret.Length == 0 ) + ret = null; + t = t.Substring( 0, colon ).Trim(); + return ret; + } + + public static List FromFileInPackage( string path ) + { + StreamReader reader = new StreamReader( FileSystem.Open(path) ); + List lines = new List(); + + while( !reader.EndOfStream ) + lines.Add(reader.ReadLine()); + reader.Close(); + + return FromLines(lines.ToArray(), path); + } + + public static Dictionary DictFromFile( string path ) + { + return FromFile( path ).ToDictionary( x => x.Key, x => x.Value ); + } + + public static Dictionary DictFromStream( Stream stream ) + { + return FromStream( stream ).ToDictionary( x => x.Key, x => x.Value ); + } + + public static List FromFile( string path ) + { + return FromLines(File.ReadAllLines( path ), path); + } + + public static List FromStream(Stream s) + { + using (var reader = new StreamReader(s)) + return FromString(reader.ReadToEnd()); + } + + public static List FromString(string text) + { + return FromLines(text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries), ""); + } + + public static List Merge( List a, List b ) + { + if( a.Count == 0 ) + return b; + if( b.Count == 0 ) + return a; + + var ret = new List(); + + var aDict = a.ToDictionary( x => x.Key ); + var bDict = b.ToDictionary( x => x.Key ); + var keys = aDict.Keys.Union( bDict.Keys ).ToList(); + + var noInherit = keys.Where( x => x.Length > 0 && x[ 0 ] == '-' ).Select( x => x.Substring( 1 ) ).ToList(); + + foreach( var key in keys ) + { + MiniYamlNode aa, bb; + aDict.TryGetValue( key, out aa ); + bDict.TryGetValue( key, out bb ); + + if( noInherit.Contains( key ) ) + { + if( aa != null ) + ret.Add( aa ); + } + else + { + var loc = aa == null ? default( MiniYamlNode.SourceLocation ) : aa.Location; + var merged = ( aa == null || bb == null ) ? aa ?? bb : new MiniYamlNode( key, Merge( aa.Value, bb.Value ), loc ); + ret.Add( merged ); + } + } + + return ret; + } + + public static MiniYaml Merge( MiniYaml a, MiniYaml b ) + { + if( a == null ) + return b; + if( b == null ) + return a; + + return new MiniYaml( a.Value ?? b.Value, Merge( a.Nodes, b.Nodes ) ); + } + + public IEnumerable ToLines(string name) + { + yield return name + ": " + Value; + if (Nodes != null) + foreach (var line in Nodes.ToLines(false)) + yield return "\t" + line; + } + } + + public static class MiniYamlExts + { + public static void WriteToFile(this MiniYamlNodes y, string filename) + { + File.WriteAllLines(filename, y.ToLines(true).Select(x => x.TrimEnd()).ToArray()); + } + + public static string WriteToString(this MiniYamlNodes y) + { + return string.Join("\n", y.ToLines(true).Select(x => x.TrimEnd()).ToArray()); + } + + public static IEnumerable ToLines(this MiniYamlNodes y, bool lowest) + { + foreach (var kv in y) + { + foreach (var line in kv.Value.ToLines(kv.Key)) + yield return line; + if (lowest) + yield return ""; + } + } + } +} diff --git a/OpenRA.FileFormats/PackageEntry.cs b/OpenRA.FileFormats/PackageEntry.cs index 2e671f0016..8cb6b14ed9 100644 --- a/OpenRA.FileFormats/PackageEntry.cs +++ b/OpenRA.FileFormats/PackageEntry.cs @@ -1,85 +1,85 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace OpenRA.FileFormats -{ - public class PackageEntry - { - public readonly uint Hash; - public readonly uint Offset; - public readonly uint Length; - - - public PackageEntry(uint hash, uint offset, uint length) - { - Hash = hash; - Offset = offset; - Length = length; - } - - public PackageEntry(BinaryReader r) - { - Hash = r.ReadUInt32(); - Offset = r.ReadUInt32(); - Length = r.ReadUInt32(); - } - - public void Write(BinaryWriter w) - { - w.Write(Hash); - w.Write(Offset); - w.Write(Length); - } - - public override string ToString() - { - string filename; - if (Names.TryGetValue(Hash, out filename)) - return string.Format("{0} - offset 0x{1:x8} - length 0x{2:x8}", filename, Offset, Length); - else - return string.Format("0x{0:x8} - offset 0x{1:x8} - length 0x{2:x8}", Hash, Offset, Length); - } - - public static uint HashFilename(string name) - { - if (name.Length > 12) - name = name.Substring(0, 12); - - name = name.ToUpperInvariant(); - if (name.Length % 4 != 0) - name = name.PadRight(name.Length + (4 - name.Length % 4), '\0'); - - MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(name)); - BinaryReader reader = new BinaryReader(ms); - - int len = name.Length >> 2; - uint result = 0; - - while (len-- != 0) - result = ((result << 1) | (result >> 31)) + reader.ReadUInt32(); - - return result; - } - - static Dictionary Names = new Dictionary(); - - public static void AddStandardName(string s) - { - uint hash = HashFilename(s); - Names.Add(hash, s); - } - - public const int Size = 12; - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace OpenRA.FileFormats +{ + public class PackageEntry + { + public readonly uint Hash; + public readonly uint Offset; + public readonly uint Length; + + + public PackageEntry(uint hash, uint offset, uint length) + { + Hash = hash; + Offset = offset; + Length = length; + } + + public PackageEntry(BinaryReader r) + { + Hash = r.ReadUInt32(); + Offset = r.ReadUInt32(); + Length = r.ReadUInt32(); + } + + public void Write(BinaryWriter w) + { + w.Write(Hash); + w.Write(Offset); + w.Write(Length); + } + + public override string ToString() + { + string filename; + if (Names.TryGetValue(Hash, out filename)) + return string.Format("{0} - offset 0x{1:x8} - length 0x{2:x8}", filename, Offset, Length); + else + return string.Format("0x{0:x8} - offset 0x{1:x8} - length 0x{2:x8}", Hash, Offset, Length); + } + + public static uint HashFilename(string name) + { + if (name.Length > 12) + name = name.Substring(0, 12); + + name = name.ToUpperInvariant(); + if (name.Length % 4 != 0) + name = name.PadRight(name.Length + (4 - name.Length % 4), '\0'); + + MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(name)); + BinaryReader reader = new BinaryReader(ms); + + int len = name.Length >> 2; + uint result = 0; + + while (len-- != 0) + result = ((result << 1) | (result >> 31)) + reader.ReadUInt32(); + + return result; + } + + static Dictionary Names = new Dictionary(); + + public static void AddStandardName(string s) + { + uint hash = HashFilename(s); + Names.Add(hash, s); + } + + public const int Size = 12; + } +} diff --git a/OpenRA.FileFormats/Palette.cs b/OpenRA.FileFormats/Palette.cs index e01ea24bd0..b577fb56cc 100644 --- a/OpenRA.FileFormats/Palette.cs +++ b/OpenRA.FileFormats/Palette.cs @@ -1,77 +1,77 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using System.IO; - -namespace OpenRA.FileFormats -{ - public class Palette - { - uint[] colors; - public Color GetColor(int index) - { - return Color.FromArgb((int)colors[index]); - } - - public void SetColor(int index, Color color) - { - colors[index] = (uint)color.ToArgb(); - } - - public void SetColor(int index, uint color) - { - colors[index] = (uint)color; - } - - public uint[] Values - { - get { return colors; } - } - - public Palette(Stream s, bool remapTransparent) - { - colors = new uint[256]; - - using (BinaryReader reader = new BinaryReader(s)) - { - for (int i = 0; i < 256; i++) - { - byte r = (byte)(reader.ReadByte() << 2); - byte g = (byte)(reader.ReadByte() << 2); - byte b = (byte)(reader.ReadByte() << 2); - colors[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b); - } - } - - colors[0] = 0; - if (remapTransparent) - { - colors[1] = 178u << 24; // Hack for d2k; may have side effects - colors[3] = 178u << 24; - colors[4] = 140u << 24; - } - } - - public Palette(Palette p, IPaletteRemap r) - { - colors = new uint[256]; - for(int i = 0; i < 256; i++) - colors[i] = (uint)r.GetRemappedColor(Color.FromArgb((int)p.colors[i]),i).ToArgb(); - } - - public Palette(Palette p) - { - colors = (uint[])p.colors.Clone(); - } - } - - public interface IPaletteRemap { Color GetRemappedColor(Color original, int index); } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using System.IO; + +namespace OpenRA.FileFormats +{ + public class Palette + { + uint[] colors; + public Color GetColor(int index) + { + return Color.FromArgb((int)colors[index]); + } + + public void SetColor(int index, Color color) + { + colors[index] = (uint)color.ToArgb(); + } + + public void SetColor(int index, uint color) + { + colors[index] = (uint)color; + } + + public uint[] Values + { + get { return colors; } + } + + public Palette(Stream s, bool remapTransparent) + { + colors = new uint[256]; + + using (BinaryReader reader = new BinaryReader(s)) + { + for (int i = 0; i < 256; i++) + { + byte r = (byte)(reader.ReadByte() << 2); + byte g = (byte)(reader.ReadByte() << 2); + byte b = (byte)(reader.ReadByte() << 2); + colors[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b); + } + } + + colors[0] = 0; + if (remapTransparent) + { + colors[1] = 178u << 24; // Hack for d2k; may have side effects + colors[3] = 178u << 24; + colors[4] = 140u << 24; + } + } + + public Palette(Palette p, IPaletteRemap r) + { + colors = new uint[256]; + for(int i = 0; i < 256; i++) + colors[i] = (uint)r.GetRemappedColor(Color.FromArgb((int)p.colors[i]),i).ToArgb(); + } + + public Palette(Palette p) + { + colors = (uint[])p.colors.Clone(); + } + } + + public interface IPaletteRemap { Color GetRemappedColor(Color original, int index); } +} diff --git a/OpenRA.FileFormats/PlayerColorRemap.cs b/OpenRA.FileFormats/PlayerColorRemap.cs index 82026028ff..6470f756cd 100755 --- a/OpenRA.FileFormats/PlayerColorRemap.cs +++ b/OpenRA.FileFormats/PlayerColorRemap.cs @@ -1,53 +1,53 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; - -namespace OpenRA.FileFormats -{ - // TODO: ship this out of here. - public enum PaletteFormat { ra, cnc, d2k } - - public class PlayerColorRemap : IPaletteRemap - { - Dictionary remapColors; - - public PlayerColorRemap(ColorRamp c, PaletteFormat fmt) - { - var c1 = c.GetColor(0); - var c2 = c.GetColor(1); /* temptemp: this can be expressed better */ - - var baseIndex = (fmt == PaletteFormat.cnc) ? 0xb0 : (fmt == PaletteFormat.d2k) ? 240 : 80; - var ramp = (fmt == PaletteFormat.cnc) - ? new[] { 0, 2, 4, 6, 8, 10, 13, 15, 1, 3, 5, 7, 9, 11, 12, 14 } - : new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - - remapColors = ramp.Select((x, i) => Pair.New(baseIndex + i, ColorLerp(x / 16f, c1, c2))) - .ToDictionary(u => u.First, u => u.Second); - } - - public static Color ColorLerp(float t, Color c1, Color c2) - { - return Color.FromArgb(255, - (int)(t * c2.R + (1 - t) * c1.R), - (int)(t * c2.G + (1 - t) * c1.G), - (int)(t * c2.B + (1 - t) * c1.B)); - } - - public Color GetRemappedColor(Color original, int index) - { - Color c; - return remapColors.TryGetValue(index, out c) - ? c : original; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace OpenRA.FileFormats +{ + // TODO: ship this out of here. + public enum PaletteFormat { ra, cnc, d2k } + + public class PlayerColorRemap : IPaletteRemap + { + Dictionary remapColors; + + public PlayerColorRemap(ColorRamp c, PaletteFormat fmt) + { + var c1 = c.GetColor(0); + var c2 = c.GetColor(1); /* temptemp: this can be expressed better */ + + var baseIndex = (fmt == PaletteFormat.cnc) ? 0xb0 : (fmt == PaletteFormat.d2k) ? 240 : 80; + var ramp = (fmt == PaletteFormat.cnc) + ? new[] { 0, 2, 4, 6, 8, 10, 13, 15, 1, 3, 5, 7, 9, 11, 12, 14 } + : new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + + remapColors = ramp.Select((x, i) => Pair.New(baseIndex + i, ColorLerp(x / 16f, c1, c2))) + .ToDictionary(u => u.First, u => u.Second); + } + + public static Color ColorLerp(float t, Color c1, Color c2) + { + return Color.FromArgb(255, + (int)(t * c2.R + (1 - t) * c1.R), + (int)(t * c2.G + (1 - t) * c1.G), + (int)(t * c2.B + (1 - t) * c1.B)); + } + + public Color GetRemappedColor(Color original, int index) + { + Color c; + return remapColors.TryGetValue(index, out c) + ? c : original; + } + } +} diff --git a/OpenRA.FileFormats/Primitives/ActionQueue.cs b/OpenRA.FileFormats/Primitives/ActionQueue.cs index 9ed04c0f86..6396085d8d 100644 --- a/OpenRA.FileFormats/Primitives/ActionQueue.cs +++ b/OpenRA.FileFormats/Primitives/ActionQueue.cs @@ -1,40 +1,40 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; - -namespace OpenRA.FileFormats -{ - /// - /// A thread-safe action queue, suitable for passing units of work between threads. - /// - public class ActionQueue - { - object syncRoot = new object(); - Action actions = () => { }; - - public void Add(Action a) - { - lock (syncRoot) - actions += a; - } - - public void PerformActions() - { - Action a; - lock (syncRoot) - { - a = actions; - actions = () => { }; - } - a(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; + +namespace OpenRA.FileFormats +{ + /// + /// A thread-safe action queue, suitable for passing units of work between threads. + /// + public class ActionQueue + { + object syncRoot = new object(); + Action actions = () => { }; + + public void Add(Action a) + { + lock (syncRoot) + actions += a; + } + + public void PerformActions() + { + Action a; + lock (syncRoot) + { + a = actions; + actions = () => { }; + } + a(); + } + } +} diff --git a/OpenRA.FileFormats/Primitives/Cache.cs b/OpenRA.FileFormats/Primitives/Cache.cs index a5681a3bd7..ec76e76ecc 100644 --- a/OpenRA.FileFormats/Primitives/Cache.cs +++ b/OpenRA.FileFormats/Primitives/Cache.cs @@ -1,49 +1,49 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace OpenRA.FileFormats -{ - public class Cache : IEnumerable> - { - Dictionary hax = new Dictionary(); - Func loader; - - public Cache(Func loader) - { - if (loader == null) - throw new ArgumentNullException(); - - this.loader = loader; - } - - public U this[T key] - { - get - { - U result; - if (!hax.TryGetValue(key, out result)) - hax.Add(key, result = loader(key)); - - return result; - } - } - - public IEnumerator> GetEnumerator() { return hax.GetEnumerator(); } - - IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - - public IEnumerable Keys { get { return hax.Keys; } } - public IEnumerable Values { get { return hax.Values; } } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace OpenRA.FileFormats +{ + public class Cache : IEnumerable> + { + Dictionary hax = new Dictionary(); + Func loader; + + public Cache(Func loader) + { + if (loader == null) + throw new ArgumentNullException(); + + this.loader = loader; + } + + public U this[T key] + { + get + { + U result; + if (!hax.TryGetValue(key, out result)) + hax.Add(key, result = loader(key)); + + return result; + } + } + + public IEnumerator> GetEnumerator() { return hax.GetEnumerator(); } + + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + + public IEnumerable Keys { get { return hax.Keys; } } + public IEnumerable Values { get { return hax.Values; } } + } +} diff --git a/OpenRA.FileFormats/Primitives/DisposableAction.cs b/OpenRA.FileFormats/Primitives/DisposableAction.cs index 938b8220b6..78ed9ea942 100644 --- a/OpenRA.FileFormats/Primitives/DisposableAction.cs +++ b/OpenRA.FileFormats/Primitives/DisposableAction.cs @@ -1,35 +1,35 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; - -namespace OpenRA -{ - public class DisposableAction : IDisposable - { - public DisposableAction(Action a) { this.a = a; } - - Action a; - bool disposed; - - public void Dispose() - { - if (disposed) return; - disposed = true; - a(); - GC.SuppressFinalize(this); - } - - ~DisposableAction() - { - Dispose(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; + +namespace OpenRA +{ + public class DisposableAction : IDisposable + { + public DisposableAction(Action a) { this.a = a; } + + Action a; + bool disposed; + + public void Dispose() + { + if (disposed) return; + disposed = true; + a(); + GC.SuppressFinalize(this); + } + + ~DisposableAction() + { + Dispose(); + } + } +} diff --git a/OpenRA.FileFormats/Primitives/Lazy.cs b/OpenRA.FileFormats/Primitives/Lazy.cs index 80feeca0bb..b7fb3bbe40 100644 --- a/OpenRA.FileFormats/Primitives/Lazy.cs +++ b/OpenRA.FileFormats/Primitives/Lazy.cs @@ -1,46 +1,46 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; - -namespace OpenRA.FileFormats -{ - public class Lazy - { - Func p; - T value; - - public Lazy(Func p) - { - if (p == null) - throw new ArgumentNullException(); - - this.p = p; - } - - public T Value - { - get - { - if (p == null) - return value; - - value = p(); - p = null; - return value; - } - } - } - - public static class Lazy - { - public static Lazy New(Func p) { return new Lazy(p); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; + +namespace OpenRA.FileFormats +{ + public class Lazy + { + Func p; + T value; + + public Lazy(Func p) + { + if (p == null) + throw new ArgumentNullException(); + + this.p = p; + } + + public T Value + { + get + { + if (p == null) + return value; + + value = p(); + p = null; + return value; + } + } + } + + public static class Lazy + { + public static Lazy New(Func p) { return new Lazy(p); } + } +} diff --git a/OpenRA.FileFormats/Primitives/Pair.cs b/OpenRA.FileFormats/Primitives/Pair.cs index b503835ecc..1f3ac031dc 100644 --- a/OpenRA.FileFormats/Primitives/Pair.cs +++ b/OpenRA.FileFormats/Primitives/Pair.cs @@ -1,70 +1,70 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; - -namespace OpenRA.FileFormats -{ - public struct Pair - { - public T First; - public U Second; - - public Pair(T first, U second) - { - First = first; - Second = second; - } - - static IEqualityComparer tc = EqualityComparer.Default; - static IEqualityComparer uc = EqualityComparer.Default; - - public static bool operator ==(Pair a, Pair b) - { - return tc.Equals(a.First, b.First) && uc.Equals(a.Second, b.Second); - } - - public static bool operator !=(Pair a, Pair b) - { - return !(a == b); - } - - public override bool Equals(object obj) - { - if (!(obj is Pair)) - return false; - - return (Pair)obj == this; - } - - public override int GetHashCode() - { - return First.GetHashCode() ^ Second.GetHashCode(); - } - - public Pair WithFirst(T t) { return new Pair(t, Second); } - public Pair WithSecond(U u) { return new Pair(First, u); } - - public static T AsFirst(Pair p) { return p.First; } - public static U AsSecond(Pair p) { return p.Second; } - - public Pair Swap() { return Pair.New(Second, First); } - - public override string ToString() - { - return "({0},{1})".F(First, Second); - } - } - - public static class Pair - { - public static Pair New(T t, U u) { return new Pair(t, u); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.FileFormats +{ + public struct Pair + { + public T First; + public U Second; + + public Pair(T first, U second) + { + First = first; + Second = second; + } + + static IEqualityComparer tc = EqualityComparer.Default; + static IEqualityComparer uc = EqualityComparer.Default; + + public static bool operator ==(Pair a, Pair b) + { + return tc.Equals(a.First, b.First) && uc.Equals(a.Second, b.Second); + } + + public static bool operator !=(Pair a, Pair b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + if (!(obj is Pair)) + return false; + + return (Pair)obj == this; + } + + public override int GetHashCode() + { + return First.GetHashCode() ^ Second.GetHashCode(); + } + + public Pair WithFirst(T t) { return new Pair(t, Second); } + public Pair WithSecond(U u) { return new Pair(First, u); } + + public static T AsFirst(Pair p) { return p.First; } + public static U AsSecond(Pair p) { return p.Second; } + + public Pair Swap() { return Pair.New(Second, First); } + + public override string ToString() + { + return "({0},{1})".F(First, Second); + } + } + + public static class Pair + { + public static Pair New(T t, U u) { return new Pair(t, u); } + } +} diff --git a/OpenRA.FileFormats/Primitives/PriorityQueue.cs b/OpenRA.FileFormats/Primitives/PriorityQueue.cs index 763797fcb7..cffe23a32a 100644 --- a/OpenRA.FileFormats/Primitives/PriorityQueue.cs +++ b/OpenRA.FileFormats/Primitives/PriorityQueue.cs @@ -1,103 +1,103 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; - -namespace OpenRA.FileFormats -{ - public class PriorityQueue - where T : IComparable - { - List items = new List(); - int level, index; - - public PriorityQueue() - { - items.Add(new T[1]); - } - - public void Add(T item) - { - int addLevel = level; - int addIndex = index; - - while (addLevel >= 1 && Above(addLevel, addIndex).CompareTo(item) > 0) - { - items[addLevel][addIndex] = Above(addLevel, addIndex); - --addLevel; - addIndex >>= 1; - } - - items[addLevel][addIndex] = item; - - if (++index >= (1 << level)) - { - index = 0; - if (items.Count <= ++level) - items.Add(new T[1 << level]); - } - } - - public bool Empty { get { return (level == 0); } } - - T At(int level, int index) { return items[level][index]; } - T Above(int level, int index) { return items[level - 1][index >> 1]; } - - T Last() - { - int lastLevel = level; - int lastIndex = index; - - if (--lastIndex < 0) - lastIndex = (1 << --lastLevel) - 1; - - return At(lastLevel, lastIndex); - } - - public T Pop() - { - if (level == 0 && index == 0) - throw new InvalidOperationException("Attempting to pop empty PriorityQueue"); - - T ret = At(0, 0); - BubbleInto(0, 0, Last()); - if (--index < 0) - index = (1 << --level) - 1; - - return ret; - } - - void BubbleInto(int intoLevel, int intoIndex, T val) - { - int downLevel = intoLevel + 1; - int downIndex = intoIndex << 1; - - if (downLevel > level || (downLevel == level && downIndex >= index)) - { - items[intoLevel][intoIndex] = val; - return; - } - - if (downLevel <= level && downIndex < index - 1 && - At(downLevel, downIndex).CompareTo(At(downLevel, downIndex + 1)) >= 0) - ++downIndex; - - if (val.CompareTo(At(downLevel, downIndex)) <= 0) - { - items[intoLevel][intoIndex] = val; - return; - } - - items[intoLevel][intoIndex] = At(downLevel, downIndex); - BubbleInto(downLevel, downIndex, val); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; + +namespace OpenRA.FileFormats +{ + public class PriorityQueue + where T : IComparable + { + List items = new List(); + int level, index; + + public PriorityQueue() + { + items.Add(new T[1]); + } + + public void Add(T item) + { + int addLevel = level; + int addIndex = index; + + while (addLevel >= 1 && Above(addLevel, addIndex).CompareTo(item) > 0) + { + items[addLevel][addIndex] = Above(addLevel, addIndex); + --addLevel; + addIndex >>= 1; + } + + items[addLevel][addIndex] = item; + + if (++index >= (1 << level)) + { + index = 0; + if (items.Count <= ++level) + items.Add(new T[1 << level]); + } + } + + public bool Empty { get { return (level == 0); } } + + T At(int level, int index) { return items[level][index]; } + T Above(int level, int index) { return items[level - 1][index >> 1]; } + + T Last() + { + int lastLevel = level; + int lastIndex = index; + + if (--lastIndex < 0) + lastIndex = (1 << --lastLevel) - 1; + + return At(lastLevel, lastIndex); + } + + public T Pop() + { + if (level == 0 && index == 0) + throw new InvalidOperationException("Attempting to pop empty PriorityQueue"); + + T ret = At(0, 0); + BubbleInto(0, 0, Last()); + if (--index < 0) + index = (1 << --level) - 1; + + return ret; + } + + void BubbleInto(int intoLevel, int intoIndex, T val) + { + int downLevel = intoLevel + 1; + int downIndex = intoIndex << 1; + + if (downLevel > level || (downLevel == level && downIndex >= index)) + { + items[intoLevel][intoIndex] = val; + return; + } + + if (downLevel <= level && downIndex < index - 1 && + At(downLevel, downIndex).CompareTo(At(downLevel, downIndex + 1)) >= 0) + ++downIndex; + + if (val.CompareTo(At(downLevel, downIndex)) <= 0) + { + items[intoLevel][intoIndex] = val; + return; + } + + items[intoLevel][intoIndex] = At(downLevel, downIndex); + BubbleInto(downLevel, downIndex, val); + } + } +} diff --git a/OpenRA.FileFormats/Primitives/Set.cs b/OpenRA.FileFormats/Primitives/Set.cs index 26a0904789..176aba7c21 100755 --- a/OpenRA.FileFormats/Primitives/Set.cs +++ b/OpenRA.FileFormats/Primitives/Set.cs @@ -1,66 +1,66 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace OpenRA.Collections -{ - public class Set : IEnumerable - { - Dictionary data = new Dictionary(); - - public void Add( T obj ) - { - data.Add( obj, false ); - if( OnAdd != null ) - OnAdd( obj ); - } - - public void Remove( T obj ) - { - data.Remove( obj ); - if( OnRemove != null ) - OnRemove( obj ); - } - - public event Action OnAdd; - public event Action OnRemove; - - public IEnumerator GetEnumerator() - { - return data.Keys.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } - - public class CachedView : Set - { - public CachedView( Set set, Func include, Func store ) - : this( set, include, x => new[] { store( x ) } ) - { - } - - public CachedView( Set set, Func include, Func> store ) - { - foreach( var t in set ) - if( include( t ) ) - store( t ).Do( x => Add( x ) ); - - set.OnAdd += obj => { if( include( obj ) ) store( obj ).Do( x => Add( x ) ); }; - set.OnRemove += obj => { if( include( obj ) ) store( obj ).Do( x => Remove( x ) ); }; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace OpenRA.Collections +{ + public class Set : IEnumerable + { + Dictionary data = new Dictionary(); + + public void Add( T obj ) + { + data.Add( obj, false ); + if( OnAdd != null ) + OnAdd( obj ); + } + + public void Remove( T obj ) + { + data.Remove( obj ); + if( OnRemove != null ) + OnRemove( obj ); + } + + public event Action OnAdd; + public event Action OnRemove; + + public IEnumerator GetEnumerator() + { + return data.Keys.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + public class CachedView : Set + { + public CachedView( Set set, Func include, Func store ) + : this( set, include, x => new[] { store( x ) } ) + { + } + + public CachedView( Set set, Func include, Func> store ) + { + foreach( var t in set ) + if( include( t ) ) + store( t ).Do( x => Add( x ) ); + + set.OnAdd += obj => { if( include( obj ) ) store( obj ).Do( x => Add( x ) ); }; + set.OnRemove += obj => { if( include( obj ) ) store( obj ).Do( x => Remove( x ) ); }; + } + } +} diff --git a/OpenRA.FileFormats/Primitives/float2.cs b/OpenRA.FileFormats/Primitives/float2.cs index 0b030bc3b7..c333b56598 100644 --- a/OpenRA.FileFormats/Primitives/float2.cs +++ b/OpenRA.FileFormats/Primitives/float2.cs @@ -1,104 +1,104 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace OpenRA -{ - [StructLayout(LayoutKind.Sequential)] - public struct float2 - { - public float X, Y; - - public float2(float x, float y) { X = x; Y = y; } - public float2(PointF p) { X = p.X; Y = p.Y; } - public float2(Point p) { X = p.X; Y = p.Y; } - public float2(Size p) { X = p.Width; Y = p.Height; } - public float2(SizeF p) { X = p.Width; Y = p.Height; } - - public PointF ToPointF() { return new PointF(X, Y); } - public SizeF ToSizeF() { return new SizeF(X, Y); } - - public static implicit operator float2(int2 src) { return new float2(src.X, src.Y); } - - public static float2 operator +(float2 a, float2 b) { return new float2(a.X + b.X, a.Y + b.Y); } - public static float2 operator -(float2 a, float2 b) { return new float2(a.X - b.X, a.Y - b.Y); } - - public static float2 operator -(float2 a) { return new float2(-a.X, -a.Y); } - - public static float Lerp(float a, float b, float t) { return a + t * (b - a); } - - public static float2 Lerp(float2 a, float2 b, float t) - { - return new float2( - Lerp(a.X, b.X, t), - Lerp(a.Y, b.Y, t)); - } - - public static float2 Lerp(float2 a, float2 b, float2 t) - { - return new float2( - Lerp(a.X, b.X, t.X), - Lerp(a.Y, b.Y, t.Y)); - } - - public static float2 FromAngle(float a) { return new float2((float)Math.Sin(a), (float)Math.Cos(a)); } - - static float Constrain(float x, float a, float b) { return x < a ? a : x > b ? b : x; } - - public float2 Constrain(float2 min, float2 max) - { - return new float2( - Constrain(X, min.X, max.X), - Constrain(Y, min.Y, max.Y)); - } - - public static float2 operator *(float a, float2 b) { return new float2(a * b.X, a * b.Y); } - public static float2 operator *(float2 b, float a) { return new float2(a * b.X, a * b.Y); } - public static float2 operator *( float2 a, float2 b ) { return new float2( a.X * b.X, a.Y * b.Y ); } - public static float2 operator /( float2 a, float2 b ) { return new float2( a.X / b.X, a.Y / b.Y ); } - - public static bool operator ==(float2 me, float2 other) { return (me.X == other.X && me.Y == other.Y); } - public static bool operator !=(float2 me, float2 other) { return !(me == other); } - public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); } - - public override bool Equals(object obj) - { - if (obj == null) - return false; - - float2 o = (float2)obj; - return o == this; - } - - public static readonly float2 Zero = new float2(0, 0); - - public static bool WithinEpsilon(float2 a, float2 b, float e) - { - float2 d = a - b; - return Math.Abs(d.X) < e && Math.Abs(d.Y) < e; - } - - public float2 Sign() { return new float2(Math.Sign(X), Math.Sign(Y)); } - public static float Dot(float2 a, float2 b) { return a.X * b.X + a.Y * b.Y; } - public float2 Round() { return new float2((float)Math.Round(X), (float)Math.Round(Y)); } - - public override string ToString() { return string.Format("({0},{1})", X, Y); } - public int2 ToInt2() { return new int2((int)X, (int)Y); } - - public static float2 Max(float2 a, float2 b) { return new float2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); } - public static float2 Min(float2 a, float2 b) { return new float2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); } - - public float LengthSquared { get { return X * X + Y * Y; } } - public float Length { get { return (float)Math.Sqrt(LengthSquared); } } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace OpenRA +{ + [StructLayout(LayoutKind.Sequential)] + public struct float2 + { + public float X, Y; + + public float2(float x, float y) { X = x; Y = y; } + public float2(PointF p) { X = p.X; Y = p.Y; } + public float2(Point p) { X = p.X; Y = p.Y; } + public float2(Size p) { X = p.Width; Y = p.Height; } + public float2(SizeF p) { X = p.Width; Y = p.Height; } + + public PointF ToPointF() { return new PointF(X, Y); } + public SizeF ToSizeF() { return new SizeF(X, Y); } + + public static implicit operator float2(int2 src) { return new float2(src.X, src.Y); } + + public static float2 operator +(float2 a, float2 b) { return new float2(a.X + b.X, a.Y + b.Y); } + public static float2 operator -(float2 a, float2 b) { return new float2(a.X - b.X, a.Y - b.Y); } + + public static float2 operator -(float2 a) { return new float2(-a.X, -a.Y); } + + public static float Lerp(float a, float b, float t) { return a + t * (b - a); } + + public static float2 Lerp(float2 a, float2 b, float t) + { + return new float2( + Lerp(a.X, b.X, t), + Lerp(a.Y, b.Y, t)); + } + + public static float2 Lerp(float2 a, float2 b, float2 t) + { + return new float2( + Lerp(a.X, b.X, t.X), + Lerp(a.Y, b.Y, t.Y)); + } + + public static float2 FromAngle(float a) { return new float2((float)Math.Sin(a), (float)Math.Cos(a)); } + + static float Constrain(float x, float a, float b) { return x < a ? a : x > b ? b : x; } + + public float2 Constrain(float2 min, float2 max) + { + return new float2( + Constrain(X, min.X, max.X), + Constrain(Y, min.Y, max.Y)); + } + + public static float2 operator *(float a, float2 b) { return new float2(a * b.X, a * b.Y); } + public static float2 operator *(float2 b, float a) { return new float2(a * b.X, a * b.Y); } + public static float2 operator *( float2 a, float2 b ) { return new float2( a.X * b.X, a.Y * b.Y ); } + public static float2 operator /( float2 a, float2 b ) { return new float2( a.X / b.X, a.Y / b.Y ); } + + public static bool operator ==(float2 me, float2 other) { return (me.X == other.X && me.Y == other.Y); } + public static bool operator !=(float2 me, float2 other) { return !(me == other); } + public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); } + + public override bool Equals(object obj) + { + if (obj == null) + return false; + + float2 o = (float2)obj; + return o == this; + } + + public static readonly float2 Zero = new float2(0, 0); + + public static bool WithinEpsilon(float2 a, float2 b, float e) + { + float2 d = a - b; + return Math.Abs(d.X) < e && Math.Abs(d.Y) < e; + } + + public float2 Sign() { return new float2(Math.Sign(X), Math.Sign(Y)); } + public static float Dot(float2 a, float2 b) { return a.X * b.X + a.Y * b.Y; } + public float2 Round() { return new float2((float)Math.Round(X), (float)Math.Round(Y)); } + + public override string ToString() { return string.Format("({0},{1})", X, Y); } + public int2 ToInt2() { return new int2((int)X, (int)Y); } + + public static float2 Max(float2 a, float2 b) { return new float2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); } + public static float2 Min(float2 a, float2 b) { return new float2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); } + + public float LengthSquared { get { return X * X + Y * Y; } } + public float Length { get { return (float)Math.Sqrt(LengthSquared); } } + } +} diff --git a/OpenRA.FileFormats/Primitives/int2.cs b/OpenRA.FileFormats/Primitives/int2.cs index ebaddde75f..86a5b53460 100644 --- a/OpenRA.FileFormats/Primitives/int2.cs +++ b/OpenRA.FileFormats/Primitives/int2.cs @@ -1,85 +1,85 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; - -namespace OpenRA -{ - public struct int2 - { - public int X,Y; - - public int2( int x, int y ) { this.X = x; this.Y = y; } - public int2( Point p ) { X = p.X; Y = p.Y; } - public int2( Size p ) { X = p.Width; Y = p.Height; } - - public static int2 operator +(int2 a, int2 b) { return new int2(a.X + b.X, a.Y + b.Y); } - public static int2 operator -(int2 a, int2 b) { return new int2(a.X - b.X, a.Y - b.Y); } - public static int2 operator *(int a, int2 b) { return new int2(a * b.X, a * b.Y); } - public static int2 operator *(int2 b, int a) { return new int2(a * b.X, a * b.Y); } - public static int2 operator /(int2 a, int b) { return new int2(a.X / b, a.Y / b); } - - public static int2 operator -(int2 a) { return new int2(-a.X, -a.Y); } - - public static bool operator ==(int2 me, int2 other) { return (me.X == other.X && me.Y == other.Y); } - public static bool operator !=(int2 me, int2 other) { return !(me == other); } - - public int2 Sign() { return new int2(Math.Sign(X), Math.Sign(Y)); } - public int2 Abs() { return new int2( Math.Abs( X ), Math.Abs( Y ) ); } - public int LengthSquared { get { return X * X + Y * Y; } } - public int Length { get { return (int)Math.Sqrt(LengthSquared); } } - public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); } - - public static int2 Max(int2 a, int2 b) { return new int2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); } - public static int2 Min(int2 a, int2 b) { return new int2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); } - - public override bool Equals(object obj) - { - if (obj == null) - return false; - - int2 o = (int2)obj; - return o == this; - } - - public static readonly int2 Zero = new int2(0, 0); - public Point ToPoint() { return new Point(X, Y); } - public PointF ToPointF() { return new PointF(X, Y); } - public float2 ToFloat2() { return new float2(X, Y); } - - public override string ToString() { return string.Format("{0},{1}", X, Y); } - - // Change endianness of a uint32 - public static uint Swap(uint orig) - { - return (uint)((orig & 0xff000000) >> 24) | ((orig & 0x00ff0000) >> 8) | ((orig & 0x0000ff00) << 8) | ((orig & 0x000000ff) << 24); - } - - public static int Lerp( int a, int b, int mul, int div ) - { - return a + ( b - a ) * mul / div; - } - - public static int2 Lerp( int2 a, int2 b, int mul, int div ) - { - return a + ( b - a ) * mul / div; - } - - public int2 Clamp(Rectangle r) - { - return new int2(Math.Min(r.Right, Math.Max(X, r.Left)), - Math.Min(r.Bottom, Math.Max(Y, r.Top))); - } - - public static int Dot(int2 a, int2 b) { return a.X * b.X + a.Y * b.Y; } - - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; + +namespace OpenRA +{ + public struct int2 + { + public int X,Y; + + public int2( int x, int y ) { this.X = x; this.Y = y; } + public int2( Point p ) { X = p.X; Y = p.Y; } + public int2( Size p ) { X = p.Width; Y = p.Height; } + + public static int2 operator +(int2 a, int2 b) { return new int2(a.X + b.X, a.Y + b.Y); } + public static int2 operator -(int2 a, int2 b) { return new int2(a.X - b.X, a.Y - b.Y); } + public static int2 operator *(int a, int2 b) { return new int2(a * b.X, a * b.Y); } + public static int2 operator *(int2 b, int a) { return new int2(a * b.X, a * b.Y); } + public static int2 operator /(int2 a, int b) { return new int2(a.X / b, a.Y / b); } + + public static int2 operator -(int2 a) { return new int2(-a.X, -a.Y); } + + public static bool operator ==(int2 me, int2 other) { return (me.X == other.X && me.Y == other.Y); } + public static bool operator !=(int2 me, int2 other) { return !(me == other); } + + public int2 Sign() { return new int2(Math.Sign(X), Math.Sign(Y)); } + public int2 Abs() { return new int2( Math.Abs( X ), Math.Abs( Y ) ); } + public int LengthSquared { get { return X * X + Y * Y; } } + public int Length { get { return (int)Math.Sqrt(LengthSquared); } } + public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); } + + public static int2 Max(int2 a, int2 b) { return new int2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); } + public static int2 Min(int2 a, int2 b) { return new int2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); } + + public override bool Equals(object obj) + { + if (obj == null) + return false; + + int2 o = (int2)obj; + return o == this; + } + + public static readonly int2 Zero = new int2(0, 0); + public Point ToPoint() { return new Point(X, Y); } + public PointF ToPointF() { return new PointF(X, Y); } + public float2 ToFloat2() { return new float2(X, Y); } + + public override string ToString() { return string.Format("{0},{1}", X, Y); } + + // Change endianness of a uint32 + public static uint Swap(uint orig) + { + return (uint)((orig & 0xff000000) >> 24) | ((orig & 0x00ff0000) >> 8) | ((orig & 0x0000ff00) << 8) | ((orig & 0x000000ff) << 24); + } + + public static int Lerp( int a, int b, int mul, int div ) + { + return a + ( b - a ) * mul / div; + } + + public static int2 Lerp( int2 a, int2 b, int mul, int div ) + { + return a + ( b - a ) * mul / div; + } + + public int2 Clamp(Rectangle r) + { + return new int2(Math.Min(r.Right, Math.Max(X, r.Left)), + Math.Min(r.Bottom, Math.Max(Y, r.Top))); + } + + public static int Dot(int2 a, int2 b) { return a.X * b.X + a.Y * b.Y; } + + } +} diff --git a/OpenRA.FileFormats/Support/Log.cs b/OpenRA.FileFormats/Support/Log.cs index 1570c996de..f66f9497d4 100755 --- a/OpenRA.FileFormats/Support/Log.cs +++ b/OpenRA.FileFormats/Support/Log.cs @@ -1,74 +1,74 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net; - -namespace OpenRA -{ - public struct ChannelInfo - { - public string Filename; - public StreamWriter Writer; - } - - public static class Log - { - static string LogPathPrefix = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + Path.DirectorySeparatorChar; - static Dictionary channels = new Dictionary(); - - public static string LogPath - { - get { return LogPathPrefix; } - set - { - LogPathPrefix = value; - if (!Directory.Exists(LogPathPrefix)) - Directory.CreateDirectory(LogPathPrefix); - } - } - - public static void AddChannel(string channelName, string filename) - { - if (channels.ContainsKey(channelName)) return; - - var i = 0; - var f = filename; - while (File.Exists(LogPathPrefix + filename)) - try - { - StreamWriter writer = File.CreateText(LogPathPrefix + filename); - writer.AutoFlush = true; - channels.Add(channelName, new ChannelInfo() { Filename = filename, Writer = writer }); - return; - } - catch (IOException) { filename = f + ".{0}".F(++i); } - - //if no logs exist, just make it - StreamWriter w = File.CreateText(LogPathPrefix + filename); - w.AutoFlush = true; - channels.Add(channelName, new ChannelInfo() { Filename = filename, Writer = w }); - - } - - public static void Write(string channel, string format, params object[] args) - { - ChannelInfo info; - if (!channels.TryGetValue(channel, out info)) - throw new Exception("Tried logging to non-existant channel " + channel); - - info.Writer.WriteLine(format, args); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net; + +namespace OpenRA +{ + public struct ChannelInfo + { + public string Filename; + public StreamWriter Writer; + } + + public static class Log + { + static string LogPathPrefix = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + Path.DirectorySeparatorChar; + static Dictionary channels = new Dictionary(); + + public static string LogPath + { + get { return LogPathPrefix; } + set + { + LogPathPrefix = value; + if (!Directory.Exists(LogPathPrefix)) + Directory.CreateDirectory(LogPathPrefix); + } + } + + public static void AddChannel(string channelName, string filename) + { + if (channels.ContainsKey(channelName)) return; + + var i = 0; + var f = filename; + while (File.Exists(LogPathPrefix + filename)) + try + { + StreamWriter writer = File.CreateText(LogPathPrefix + filename); + writer.AutoFlush = true; + channels.Add(channelName, new ChannelInfo() { Filename = filename, Writer = writer }); + return; + } + catch (IOException) { filename = f + ".{0}".F(++i); } + + //if no logs exist, just make it + StreamWriter w = File.CreateText(LogPathPrefix + filename); + w.AutoFlush = true; + channels.Add(channelName, new ChannelInfo() { Filename = filename, Writer = w }); + + } + + public static void Write(string channel, string format, params object[] args) + { + ChannelInfo info; + if (!channels.TryGetValue(channel, out info)) + throw new Exception("Tried logging to non-existant channel " + channel); + + info.Writer.WriteLine(format, args); + } + } +} diff --git a/OpenRA.FileFormats/Support/Stopwatch.cs b/OpenRA.FileFormats/Support/Stopwatch.cs index f349fb68de..e2907fab5c 100755 --- a/OpenRA.FileFormats/Support/Stopwatch.cs +++ b/OpenRA.FileFormats/Support/Stopwatch.cs @@ -1,31 +1,31 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.Support -{ - public class Stopwatch - { - System.Diagnostics.Stopwatch sw; - public Stopwatch () - { - Reset(); - } - - public double ElapsedTime() - { - return sw.Elapsed.TotalMilliseconds / 1000.0; - } - - public void Reset() - { - sw = System.Diagnostics.Stopwatch.StartNew(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.Support +{ + public class Stopwatch + { + System.Diagnostics.Stopwatch sw; + public Stopwatch () + { + Reset(); + } + + public double ElapsedTime() + { + return sw.Elapsed.TotalMilliseconds / 1000.0; + } + + public void Reset() + { + sw = System.Diagnostics.Stopwatch.StartNew(); + } + } +} diff --git a/OpenRA.FileFormats/Support/Timer.cs b/OpenRA.FileFormats/Support/Timer.cs index 5083b330a5..9b060a4b07 100755 --- a/OpenRA.FileFormats/Support/Timer.cs +++ b/OpenRA.FileFormats/Support/Timer.cs @@ -1,27 +1,27 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.Support -{ - public static class Timer - { - static Stopwatch sw = new Stopwatch(); - static double lastTime = 0; - - public static void Time( string message ) - { - var time = sw.ElapsedTime(); - var dt = time - lastTime; - if( dt > 0.0001 ) - Log.Write("perf", message, dt ); - lastTime = time; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.Support +{ + public static class Timer + { + static Stopwatch sw = new Stopwatch(); + static double lastTime = 0; + + public static void Time( string message ) + { + var time = sw.ElapsedTime(); + var dt = time - lastTime; + if( dt > 0.0001 ) + Log.Write("perf", message, dt ); + lastTime = time; + } + } +} diff --git a/OpenRA.FileFormats/Thirdparty/Random.cs b/OpenRA.FileFormats/Thirdparty/Random.cs index 152892b6dd..ce1cd65841 100644 --- a/OpenRA.FileFormats/Thirdparty/Random.cs +++ b/OpenRA.FileFormats/Thirdparty/Random.cs @@ -1,66 +1,66 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; - -namespace OpenRA.Thirdparty -{ - // quick & dirty Mersenne Twister [MT19937] implementation - - public class Random - { - uint[] mt = new uint[624]; - int index = 0; - - public int Last; - - public Random() : this(Environment.TickCount) { } - - public Random(int seed) - { - mt[0] = (uint)seed; - for (var i = 1u; i < mt.Length; i++) - mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i; - } - - public int Next() - { - if (index == 0) Generate(); - - var y = mt[index]; - y ^= (y >> 11); - y ^= ((y << 7) & 2636928640); - y ^= ((y << 15) & 4022730752); - y ^= y >> 18; - - index = (index + 1) % 624; - Last = (int)(y % int.MaxValue); - return Last; - } - - public int Next(int low, int high) { return low + Next() % (high - low); } - public int Next(int high) { return Next() % high; } - public double NextDouble() { return Math.Abs(Next() / (double)0x7fffffff); } - - void Generate() - { - unchecked - { - for (var i = 0u; i < mt.Length; i++) - { - var y = (mt[i] & 0x80000000) | (mt[(i + 1) % 624] & 0x7fffffff); - mt[i] = mt[(i + 397u) % 624u] ^ (y >> 1); - if ((y & 1) == 1) - mt[i] = (mt[i] ^ 2567483615); - } - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; + +namespace OpenRA.Thirdparty +{ + // quick & dirty Mersenne Twister [MT19937] implementation + + public class Random + { + uint[] mt = new uint[624]; + int index = 0; + + public int Last; + + public Random() : this(Environment.TickCount) { } + + public Random(int seed) + { + mt[0] = (uint)seed; + for (var i = 1u; i < mt.Length; i++) + mt[i] = 1812433253u * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i; + } + + public int Next() + { + if (index == 0) Generate(); + + var y = mt[index]; + y ^= (y >> 11); + y ^= ((y << 7) & 2636928640); + y ^= ((y << 15) & 4022730752); + y ^= y >> 18; + + index = (index + 1) % 624; + Last = (int)(y % int.MaxValue); + return Last; + } + + public int Next(int low, int high) { return low + Next() % (high - low); } + public int Next(int high) { return Next() % high; } + public double NextDouble() { return Math.Abs(Next() / (double)0x7fffffff); } + + void Generate() + { + unchecked + { + for (var i = 0u; i < mt.Length; i++) + { + var y = (mt[i] & 0x80000000) | (mt[(i + 1) % 624] & 0x7fffffff); + mt[i] = mt[(i + 397u) % 624u] ^ (y >> 1); + if ((y & 1) == 1) + mt[i] = (mt[i] ^ 2567483615); + } + } + } + } +} diff --git a/OpenRA.FileFormats/TypeDictionary.cs b/OpenRA.FileFormats/TypeDictionary.cs index c751e41bb8..e4dcd1d6b7 100644 --- a/OpenRA.FileFormats/TypeDictionary.cs +++ b/OpenRA.FileFormats/TypeDictionary.cs @@ -1,106 +1,106 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.FileFormats -{ - public class TypeDictionary : IEnumerable - { - Dictionary dataSingular = new Dictionary(); - Dictionary> dataMultiple = new Dictionary>(); - - public void Add( object val ) - { - var t = val.GetType(); - - foreach( var i in t.GetInterfaces() ) - InnerAdd( i, val ); - foreach( var tt in t.BaseTypes() ) - InnerAdd( tt, val ); - } - - void InnerAdd( Type t, object val ) - { - List objs; - object obj; - - if( dataMultiple.TryGetValue( t, out objs ) ) - objs.Add( val ); - else if( dataSingular.TryGetValue( t, out obj ) ) - { - dataSingular.Remove( t ); - dataMultiple.Add( t, new List { obj, val } ); - } - else - dataSingular.Add( t, val ); - } - - public bool Contains() - { - return dataSingular.ContainsKey( typeof( T ) ) || dataMultiple.ContainsKey( typeof( T ) ); - } - - public T Get() - { - if( dataMultiple.ContainsKey( typeof( T ) ) ) - throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); - - object ret; - if( !dataSingular.TryGetValue( typeof( T ), out ret ) ) - throw new InvalidOperationException(string.Format("TypeDictionary does not contain instance of type `{0}`", typeof(T))); - return (T)ret; - } - - public T GetOrDefault() - { - if( dataMultiple.ContainsKey( typeof( T ) ) ) - throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); - - object ret; - if( !dataSingular.TryGetValue( typeof( T ), out ret ) ) - return default( T ); - return (T)ret; - } - - public IEnumerable WithInterface() - { - List objs; - object obj; - - if( dataMultiple.TryGetValue( typeof( T ), out objs ) ) - return objs.Cast(); - else if( dataSingular.TryGetValue( typeof( T ), out obj ) ) - return new T[] { (T)obj }; - else - return new T[ 0 ]; - } - - public IEnumerator GetEnumerator() - { - return WithInterface().GetEnumerator(); - } - } - - public static class TypeExts - { - public static IEnumerable BaseTypes( this Type t ) - { - while( t != null ) - { - yield return t; - t = t.BaseType; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.FileFormats +{ + public class TypeDictionary : IEnumerable + { + Dictionary dataSingular = new Dictionary(); + Dictionary> dataMultiple = new Dictionary>(); + + public void Add( object val ) + { + var t = val.GetType(); + + foreach( var i in t.GetInterfaces() ) + InnerAdd( i, val ); + foreach( var tt in t.BaseTypes() ) + InnerAdd( tt, val ); + } + + void InnerAdd( Type t, object val ) + { + List objs; + object obj; + + if( dataMultiple.TryGetValue( t, out objs ) ) + objs.Add( val ); + else if( dataSingular.TryGetValue( t, out obj ) ) + { + dataSingular.Remove( t ); + dataMultiple.Add( t, new List { obj, val } ); + } + else + dataSingular.Add( t, val ); + } + + public bool Contains() + { + return dataSingular.ContainsKey( typeof( T ) ) || dataMultiple.ContainsKey( typeof( T ) ); + } + + public T Get() + { + if( dataMultiple.ContainsKey( typeof( T ) ) ) + throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); + + object ret; + if( !dataSingular.TryGetValue( typeof( T ), out ret ) ) + throw new InvalidOperationException(string.Format("TypeDictionary does not contain instance of type `{0}`", typeof(T))); + return (T)ret; + } + + public T GetOrDefault() + { + if( dataMultiple.ContainsKey( typeof( T ) ) ) + throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); + + object ret; + if( !dataSingular.TryGetValue( typeof( T ), out ret ) ) + return default( T ); + return (T)ret; + } + + public IEnumerable WithInterface() + { + List objs; + object obj; + + if( dataMultiple.TryGetValue( typeof( T ), out objs ) ) + return objs.Cast(); + else if( dataSingular.TryGetValue( typeof( T ), out obj ) ) + return new T[] { (T)obj }; + else + return new T[ 0 ]; + } + + public IEnumerator GetEnumerator() + { + return WithInterface().GetEnumerator(); + } + } + + public static class TypeExts + { + public static IEnumerable BaseTypes( this Type t ) + { + while( t != null ) + { + yield return t; + t = t.BaseType; + } + } + } +} diff --git a/OpenRA.Game/Actor.cs b/OpenRA.Game/Actor.cs index a066e805b8..611469105b 100755 --- a/OpenRA.Game/Actor.cs +++ b/OpenRA.Game/Actor.cs @@ -1,20 +1,20 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Support; -using OpenRA.Traits; +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Support; +using OpenRA.Traits; using OpenRA.Traits.Activities; namespace OpenRA @@ -24,23 +24,23 @@ namespace OpenRA public readonly ActorInfo Info; public readonly World World; - public readonly uint ActorID; - - public int2 Location { get { return Trait().TopLeft; } } + public readonly uint ActorID; + + public int2 Location { get { return Trait().TopLeft; } } public int2 CenterLocation { get { return Trait().PxPosition; } } [Sync] public Player Owner; - private IActivity currentActivity; - public Group Group; - + private IActivity currentActivity; + public Group Group; + internal Actor(World world, string name, TypeDictionary initDict ) - { + { var init = new ActorInitializer( this, initDict ); World = world; - ActorID = world.NextAID(); - if( initDict.Contains() ) + ActorID = world.NextAID(); + if( initDict.Contains() ) Owner = init.Get(); if (name != null) @@ -51,8 +51,8 @@ namespace OpenRA Info = Rules.Info[name.ToLowerInvariant()]; foreach (var trait in Info.TraitsInConstructOrder()) AddTrait(trait.Create(init)); - } - + } + Size = Lazy.New(() => { var si = Info.Traits.GetOrDefault(); @@ -61,13 +61,13 @@ namespace OpenRA // auto size from render var firstSprite = TraitsImplementing().SelectMany(x => x.Render(this)).FirstOrDefault(); - if (firstSprite.Sprite == null) return float2.Zero; + if (firstSprite.Sprite == null) return float2.Zero; return firstSprite.Sprite.size * firstSprite.Scale; }); } public void Tick() - { + { if (currentActivity == null) foreach (var ni in TraitsImplementing()) ni.TickIdle(this); @@ -88,38 +88,38 @@ namespace OpenRA var sprites = TraitsImplementing().SelectMany(x => x.Render(this)); return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m)); } - - // When useAltitude = true, the bounding box is extended - // vertically to altitude = 0 to support FindUnitsInCircle queries - // When false, the bounding box is given for the actor + + // When useAltitude = true, the bounding box is extended + // vertically to altitude = 0 to support FindUnitsInCircle queries + // When false, the bounding box is given for the actor // at its current altitude public RectangleF GetBounds(bool useAltitude) { var size = Size.Value; - var loc = CenterLocation - 0.5f * size; + var loc = CenterLocation - 0.5f * size; var si = Info.Traits.GetOrDefault(); if (si != null && si.Bounds != null && si.Bounds.Length > 2) loc += new float2(si.Bounds[2], si.Bounds[3]); var move = TraitOrDefault(); - if (move != null) - { - loc -= new float2(0, move.Altitude); - if (useAltitude) - size = new float2(size.X, size.Y + move.Altitude); + if (move != null) + { + loc -= new float2(0, move.Altitude); + if (useAltitude) + size = new float2(size.X, size.Y + move.Altitude); } return new RectangleF(loc.X, loc.Y, size.X, size.Y); } - public bool IsInWorld { get; internal set; } - - public void QueueActivity( bool queued, IActivity nextActivity ) - { - if( !queued ) - CancelActivity(); - QueueActivity( nextActivity ); + public bool IsInWorld { get; internal set; } + + public void QueueActivity( bool queued, IActivity nextActivity ) + { + if( !queued ) + CancelActivity(); + QueueActivity( nextActivity ); } public void QueueActivity( IActivity nextActivity ) @@ -152,60 +152,60 @@ namespace OpenRA return ( o != null && o.ActorID == ActorID ); } - public override string ToString() - { - return "{0} {1}{2}".F( Info.Name, ActorID, IsInWorld ? "" : " (not in world)" ); + public override string ToString() + { + return "{0} {1}{2}".F( Info.Name, ActorID, IsInWorld ? "" : " (not in world)" ); } - public T Trait() - { - return World.traitDict.Get( this ); - } - - public T TraitOrDefault() - { - return World.traitDict.GetOrDefault( this ); - } - - public IEnumerable TraitsImplementing() - { - return World.traitDict.WithInterface( this ); - } - - public bool HasTrait() - { - return World.traitDict.Contains( this ); - } - - public void AddTrait( object trait ) - { - World.traitDict.AddTrait( this, trait ); - } - - public bool Destroyed { get; private set; } - - public void Destroy() - { - World.AddFrameEndTask( w => - { - if (Destroyed) return; - - World.Remove( this ); - World.traitDict.RemoveActor( this ); - Destroyed = true; - } ); - } - - // todo: move elsewhere. - public void ChangeOwner(Player newOwner) - { - World.AddFrameEndTask(w => - { - // momentarily remove from world so the ownership queries don't get confused - w.Remove(this); - Owner = newOwner; - w.Add(this); - }); - } - } + public T Trait() + { + return World.traitDict.Get( this ); + } + + public T TraitOrDefault() + { + return World.traitDict.GetOrDefault( this ); + } + + public IEnumerable TraitsImplementing() + { + return World.traitDict.WithInterface( this ); + } + + public bool HasTrait() + { + return World.traitDict.Contains( this ); + } + + public void AddTrait( object trait ) + { + World.traitDict.AddTrait( this, trait ); + } + + public bool Destroyed { get; private set; } + + public void Destroy() + { + World.AddFrameEndTask( w => + { + if (Destroyed) return; + + World.Remove( this ); + World.traitDict.RemoveActor( this ); + Destroyed = true; + } ); + } + + // todo: move elsewhere. + public void ChangeOwner(Player newOwner) + { + World.AddFrameEndTask(w => + { + // momentarily remove from world so the ownership queries don't get confused + w.Remove(this); + Owner = newOwner; + w.Add(this); + }); + } + } } diff --git a/OpenRA.Game/ActorInitializer.cs b/OpenRA.Game/ActorInitializer.cs index a22cb51650..06979a729c 100755 --- a/OpenRA.Game/ActorInitializer.cs +++ b/OpenRA.Game/ActorInitializer.cs @@ -1,134 +1,134 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.FileFormats; - -namespace OpenRA -{ - public class ActorInitializer - { - public readonly Actor self; - public World world { get { return self.World; } } - internal TypeDictionary dict; - - public ActorInitializer( Actor actor, TypeDictionary dict ) - { - this.self = actor; - this.dict = dict; - } - - public T Get() - where T : IActorInit - { - return dict.Get(); - } - - public U Get() - where T : IActorInit - { - return dict.Get().Value( world ); - } - - public bool Contains() - where T : IActorInit - { - return dict.Contains(); - } - } - - public interface IActorInit {} - - public interface IActorInit : IActorInit - { - T Value( World world ); - } - - public class FacingInit : IActorInit - { - [FieldFromYamlKey] - public readonly int value = 128; - - public FacingInit() { } - - public FacingInit( int init ) - { - value = init; - } - - public int Value( World world ) - { - return value; - } - } - - public class AltitudeInit : IActorInit - { - [FieldFromYamlKey] - public readonly int value = 0; - - public AltitudeInit() { } - - public AltitudeInit( int init ) - { - value = init; - } - - public int Value( World world ) - { - return value; - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.FileFormats; + +namespace OpenRA +{ + public class ActorInitializer + { + public readonly Actor self; + public World world { get { return self.World; } } + internal TypeDictionary dict; + + public ActorInitializer( Actor actor, TypeDictionary dict ) + { + this.self = actor; + this.dict = dict; + } + + public T Get() + where T : IActorInit + { + return dict.Get(); + } + + public U Get() + where T : IActorInit + { + return dict.Get().Value( world ); + } + + public bool Contains() + where T : IActorInit + { + return dict.Contains(); + } } - - public class LocationInit : IActorInit - { - [FieldFromYamlKey] - public readonly int2 value = int2.Zero; - - public LocationInit() { } - - public LocationInit( int2 init ) - { - value = init; - } - - public int2 Value( World world ) - { - return value; - } - } - - public class OwnerInit : IActorInit - { - [FieldFromYamlKey] - public readonly string PlayerName = "Neutral"; - Player player; - - public OwnerInit() { } - - public OwnerInit( string playerName ) - { - this.PlayerName = playerName; - } - - public OwnerInit( Player player ) - { - this.player = player; - this.PlayerName = player.InternalName; - } - - public Player Value( World world ) - { - if( player != null ) - return player; - return world.players.Values.First( x => x.InternalName == PlayerName ); - } - } -} + + public interface IActorInit {} + + public interface IActorInit : IActorInit + { + T Value( World world ); + } + + public class FacingInit : IActorInit + { + [FieldFromYamlKey] + public readonly int value = 128; + + public FacingInit() { } + + public FacingInit( int init ) + { + value = init; + } + + public int Value( World world ) + { + return value; + } + } + + public class AltitudeInit : IActorInit + { + [FieldFromYamlKey] + public readonly int value = 0; + + public AltitudeInit() { } + + public AltitudeInit( int init ) + { + value = init; + } + + public int Value( World world ) + { + return value; + } + } + + public class LocationInit : IActorInit + { + [FieldFromYamlKey] + public readonly int2 value = int2.Zero; + + public LocationInit() { } + + public LocationInit( int2 init ) + { + value = init; + } + + public int2 Value( World world ) + { + return value; + } + } + + public class OwnerInit : IActorInit + { + [FieldFromYamlKey] + public readonly string PlayerName = "Neutral"; + Player player; + + public OwnerInit() { } + + public OwnerInit( string playerName ) + { + this.PlayerName = playerName; + } + + public OwnerInit( Player player ) + { + this.player = player; + this.PlayerName = player.InternalName; + } + + public Player Value( World world ) + { + if( player != null ) + return player; + return world.players.Values.First( x => x.InternalName == PlayerName ); + } + } +} diff --git a/OpenRA.Game/ActorReference.cs b/OpenRA.Game/ActorReference.cs index 3d09a53e64..b85925427e 100755 --- a/OpenRA.Game/ActorReference.cs +++ b/OpenRA.Game/ActorReference.cs @@ -1,54 +1,54 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections; -using System.Collections.Generic; -using System.IO; - -namespace OpenRA.FileFormats -{ - public class ActorReference : IEnumerable - { - public readonly string Type; - public readonly TypeDictionary InitDict; - - public ActorReference( string type ) : this( type, new Dictionary() ) { } - - public ActorReference( string type, Dictionary inits ) - { - Type = type; - InitDict = new TypeDictionary(); - foreach( var i in inits ) - InitDict.Add( LoadInit( i.Key, i.Value ) ); - } - - static IActorInit LoadInit(string traitName, MiniYaml my) - { - var info = Game.CreateObject(traitName + "Init"); - FieldLoader.Load(info, my); - return info; - } - - public MiniYaml Save() - { - var ret = new MiniYaml( Type ); - foreach( var init in InitDict ) - { - var initName = init.GetType().Name; - ret.Nodes.Add( new MiniYamlNode( initName.Substring( 0, initName.Length - 4 ), FieldSaver.Save( init ) ) ); - } - return ret; - } - - // for initialization syntax - public void Add( object o ) { InitDict.Add( o ); } - public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections; +using System.Collections.Generic; +using System.IO; + +namespace OpenRA.FileFormats +{ + public class ActorReference : IEnumerable + { + public readonly string Type; + public readonly TypeDictionary InitDict; + + public ActorReference( string type ) : this( type, new Dictionary() ) { } + + public ActorReference( string type, Dictionary inits ) + { + Type = type; + InitDict = new TypeDictionary(); + foreach( var i in inits ) + InitDict.Add( LoadInit( i.Key, i.Value ) ); + } + + static IActorInit LoadInit(string traitName, MiniYaml my) + { + var info = Game.CreateObject(traitName + "Init"); + FieldLoader.Load(info, my); + return info; + } + + public MiniYaml Save() + { + var ret = new MiniYaml( Type ); + foreach( var init in InitDict ) + { + var initName = init.GetType().Name; + ret.Nodes.Add( new MiniYamlNode( initName.Substring( 0, initName.Length - 4 ), FieldSaver.Save( init ) ) ); + } + return ret; + } + + // for initialization syntax + public void Add( object o ) { InitDict.Add( o ); } + public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); } + } +} diff --git a/OpenRA.Game/Cursor.cs b/OpenRA.Game/Cursor.cs index a67599cd23..f08a900244 100644 --- a/OpenRA.Game/Cursor.cs +++ b/OpenRA.Game/Cursor.cs @@ -1,28 +1,28 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Graphics; - -namespace OpenRA -{ - public class Cursor - { - CursorSequence sequence; - public Cursor(string cursor) - { - sequence = CursorProvider.GetCursorSequence(cursor); - } - - public void Draw(int frame, float2 pos) - { - sequence.GetSprite(frame).DrawAt(pos - sequence.Hotspot, Game.modData.Palette.GetPaletteIndex(sequence.Palette)); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Graphics; + +namespace OpenRA +{ + public class Cursor + { + CursorSequence sequence; + public Cursor(string cursor) + { + sequence = CursorProvider.GetCursorSequence(cursor); + } + + public void Draw(int frame, float2 pos) + { + sequence.GetSprite(frame).DrawAt(pos - sequence.Hotspot, Game.modData.Palette.GetPaletteIndex(sequence.Palette)); + } + } +} diff --git a/OpenRA.Game/Effects/DelayedAction.cs b/OpenRA.Game/Effects/DelayedAction.cs index 48f07f8c3a..bb77ccf518 100755 --- a/OpenRA.Game/Effects/DelayedAction.cs +++ b/OpenRA.Game/Effects/DelayedAction.cs @@ -1,36 +1,36 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Effects -{ - public class DelayedAction : IEffect - { - Action a; - int delay; - - public DelayedAction(int delay, Action a) - { - this.a = a; - this.delay = delay; - } - - public void Tick( World world ) - { - if (--delay <= 0) - world.AddFrameEndTask(w => { w.Remove(this); a(); }); - } - - public IEnumerable Render() { yield break; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Effects +{ + public class DelayedAction : IEffect + { + Action a; + int delay; + + public DelayedAction(int delay, Action a) + { + this.a = a; + this.delay = delay; + } + + public void Tick( World world ) + { + if (--delay <= 0) + world.AddFrameEndTask(w => { w.Remove(this); a(); }); + } + + public IEnumerable Render() { yield break; } + } +} diff --git a/OpenRA.Game/Effects/FlashTarget.cs b/OpenRA.Game/Effects/FlashTarget.cs index 73cc191c20..d7b727a1a2 100755 --- a/OpenRA.Game/Effects/FlashTarget.cs +++ b/OpenRA.Game/Effects/FlashTarget.cs @@ -1,45 +1,45 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Effects -{ - public class FlashTarget : IEffect - { - Actor target; - int remainingTicks = 4; - - public FlashTarget(Actor target) - { - this.target = target; - foreach (var e in target.World.Effects.OfType().Where(a => a.target == target).ToArray()) - target.World.Remove(e); - } - - public void Tick( World world ) - { - if (--remainingTicks == 0 || !target.IsInWorld) - world.AddFrameEndTask(w => w.Remove(this)); - } - - public IEnumerable Render() - { - if (!target.IsInWorld) - yield break; - - if (remainingTicks % 2 == 0) - foreach (var r in target.Render()) - yield return r.WithPalette("highlight"); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Effects +{ + public class FlashTarget : IEffect + { + Actor target; + int remainingTicks = 4; + + public FlashTarget(Actor target) + { + this.target = target; + foreach (var e in target.World.Effects.OfType().Where(a => a.target == target).ToArray()) + target.World.Remove(e); + } + + public void Tick( World world ) + { + if (--remainingTicks == 0 || !target.IsInWorld) + world.AddFrameEndTask(w => w.Remove(this)); + } + + public IEnumerable Render() + { + if (!target.IsInWorld) + yield break; + + if (remainingTicks % 2 == 0) + foreach (var r in target.Render()) + yield return r.WithPalette("highlight"); + } + } +} diff --git a/OpenRA.Game/Effects/IEffect.cs b/OpenRA.Game/Effects/IEffect.cs index ad5d5aa461..89219f07fd 100755 --- a/OpenRA.Game/Effects/IEffect.cs +++ b/OpenRA.Game/Effects/IEffect.cs @@ -1,21 +1,21 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Effects -{ - public interface IEffect - { - void Tick( World world ); - IEnumerable Render(); - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Effects +{ + public interface IEffect + { + void Tick( World world ); + IEnumerable Render(); + } +} diff --git a/OpenRA.Game/Exts.cs b/OpenRA.Game/Exts.cs index 3a20197ceb..956d289090 100755 --- a/OpenRA.Game/Exts.cs +++ b/OpenRA.Game/Exts.cs @@ -1,70 +1,70 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Support; - -namespace OpenRA -{ - public static class Exts - { - public static bool HasModifier(this Modifiers k, Modifiers mod) - { - return (k & mod) == mod; - } - - public static IEnumerable SymmetricDifference(this IEnumerable xs, IEnumerable ys) - { - // this is probably a shockingly-slow way to do this, but it's concise. - return xs.Except(ys).Concat(ys.Except(xs)); - } - - public static float Product(this IEnumerable xs) - { - return xs.Aggregate(1f, (a, x) => a * x); - } - - public static V GetOrAdd(this Dictionary d, K k) - where V : new() - { - return d.GetOrAdd(k, _ => new V()); - } - - public static V GetOrAdd(this Dictionary d, K k, Func createFn) - { - V ret; - if (!d.TryGetValue(k, out ret)) - d.Add(k, ret = createFn(k)); - return ret; - } - - public static T Random(this IEnumerable ts, Thirdparty.Random r) - { - var xs = ts.ToArray(); - return xs[r.Next(xs.Length)]; - } - - public static void DoTimed(this IEnumerable e, Action a, string text, double time) - { - var sw = new Stopwatch(); - - e.Do(x => - { - var t = sw.ElapsedTime(); - a(x); - var dt = sw.ElapsedTime() - t; - if (dt > time) - Log.Write("perf", text, x, dt * 1000, Game.LocalTick); - }); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Support; + +namespace OpenRA +{ + public static class Exts + { + public static bool HasModifier(this Modifiers k, Modifiers mod) + { + return (k & mod) == mod; + } + + public static IEnumerable SymmetricDifference(this IEnumerable xs, IEnumerable ys) + { + // this is probably a shockingly-slow way to do this, but it's concise. + return xs.Except(ys).Concat(ys.Except(xs)); + } + + public static float Product(this IEnumerable xs) + { + return xs.Aggregate(1f, (a, x) => a * x); + } + + public static V GetOrAdd(this Dictionary d, K k) + where V : new() + { + return d.GetOrAdd(k, _ => new V()); + } + + public static V GetOrAdd(this Dictionary d, K k, Func createFn) + { + V ret; + if (!d.TryGetValue(k, out ret)) + d.Add(k, ret = createFn(k)); + return ret; + } + + public static T Random(this IEnumerable ts, Thirdparty.Random r) + { + var xs = ts.ToArray(); + return xs[r.Next(xs.Length)]; + } + + public static void DoTimed(this IEnumerable e, Action a, string text, double time) + { + var sw = new Stopwatch(); + + e.Do(x => + { + var t = sw.ElapsedTime(); + a(x); + var dt = sw.ElapsedTime() - t; + if (dt > time) + Log.Write("perf", text, x, dt * 1000, Game.LocalTick); + }); + } + } +} diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 14f7418f5e..ab2bbf0a33 100755 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -1,369 +1,369 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Net; -using System.Windows.Forms; -using OpenRA.FileFormats; -using OpenRA.GameRules; -using OpenRA.Graphics; -using OpenRA.Network; -using OpenRA.Server; -using OpenRA.Support; -using OpenRA.Widgets; - -using XRandom = OpenRA.Thirdparty.Random; - -namespace OpenRA -{ - public static class Game - { - public static Utilities Utilities; - - public static int CellSize { get { return modData.Manifest.TileSize; } } - - public static ModData modData; - private static WorldRenderer worldRenderer; - - public static Viewport viewport; - public static Settings Settings; - - internal static OrderManager orderManager; - static Server.Server server; - - public static XRandom CosmeticRandom = new XRandom(); // not synced - - public static Renderer Renderer; - public static bool HasInputFocus = false; - - public static void MoveViewport(float2 loc) - { - viewport.Center(loc); - } - - public static void JoinServer(string host, int port) - { - var replayFilename = ChooseReplayFilename(); - string path = Path.Combine( Game.SupportDir, "Replays" ); - if( !Directory.Exists( path ) ) Directory.CreateDirectory( path ); - var replayFile = File.Create( Path.Combine( path, replayFilename ) ); - - JoinInner(new OrderManager(host, port, - new ReplayRecorderConnection(new NetworkConnection(host, port), replayFile))); - } - - static string ChooseReplayFilename() - { - return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddTHHmmssZ.rep"); - } - - static void JoinInner(OrderManager om) - { - if (orderManager != null) orderManager.Dispose(); - orderManager = om; - lastConnectionState = ConnectionState.PreConnecting; - ConnectionStateChanged(orderManager); - } - - public static void JoinReplay(string replayFile) - { - JoinInner(new OrderManager("", -1, new ReplayConnection(replayFile))); - } - - static void JoinLocal() - { - JoinInner(new OrderManager("", -1, new EchoConnection())); - } - - public static int RenderFrame = 0; - public static int NetFrameNumber { get { return orderManager.NetFrameNumber; } } - public static int LocalTick { get { return orderManager.LocalFrameNumber; } } - const int NetTickScale = 3; // 120ms net tick for 40ms local tick - - public static event Action ConnectionStateChanged = _ => { }; - static ConnectionState lastConnectionState = ConnectionState.PreConnecting; - public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } } - - - // Hacky workaround for orderManager visibility - public static Widget OpenWindow(World world, string widget) - { - return Widget.OpenWindow(widget, new Dictionary{{ "world", world }, { "orderManager", orderManager }, { "worldRenderer", worldRenderer }}); - } - - static ActionQueue afterTickActions = new ActionQueue(); - public static void RunAfterTick(Action a) { afterTickActions.Add(a); } - - static void Tick( OrderManager orderManager, Viewport viewPort ) - { - if (orderManager.Connection.ConnectionState != lastConnectionState) - { - lastConnectionState = orderManager.Connection.ConnectionState; - ConnectionStateChanged( orderManager ); - } - - Tick( orderManager ); - if( worldRenderer != null && orderManager.world != worldRenderer.world ) - Tick( worldRenderer.world.orderManager ); - - using (new PerfSample("render")) - { - ++RenderFrame; - viewport.DrawRegions(worldRenderer, new DefaultInputHandler( orderManager.world )); - Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height)); - } - - PerfHistory.items["render"].Tick(); - PerfHistory.items["batches"].Tick(); - - MasterServerQuery.Tick(); - - afterTickActions.PerformActions(); - } - - private static void Tick( OrderManager orderManager ) - { - int t = Environment.TickCount; - int dt = t - orderManager.LastTickTime; - if (dt >= Settings.Game.Timestep) - using( new PerfSample( "tick_time" ) ) - { - orderManager.LastTickTime += Settings.Game.Timestep; - Widget.DoTick(); - var world = orderManager.world; - if( orderManager.GameStarted && world.LocalPlayer != null ) - ++Viewport.TicksSinceLastMove; - Sound.Tick(); - Sync.CheckSyncUnchanged( world, () => { orderManager.TickImmediate(); } ); - - if (world != null) - { - var isNetTick = LocalTick % NetTickScale == 0; - - if (!isNetTick || orderManager.IsReadyForNextFrame) - { - ++orderManager.LocalFrameNumber; - - Log.Write("debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local"); - - if (isNetTick) orderManager.Tick(); - - - Sync.CheckSyncUnchanged(world, () => - { - world.OrderGenerator.Tick(world); - world.Selection.Tick(world); - }); - - world.Tick(); - - PerfHistory.Tick(); - } - else - if (orderManager.NetFrameNumber == 0) - orderManager.LastTickTime = Environment.TickCount; - } - } - } - - public static event Action LobbyInfoChanged = () => { }; - - internal static void SyncLobbyInfo() - { - LobbyInfoChanged(); - } - - public static event Action AfterGameStart = _ => {}; - public static event Action BeforeGameStart = () => {}; - internal static void StartGame(string mapUID) - { - BeforeGameStart(); - - var map = modData.PrepareMap(mapUID); - viewport = new Viewport(new int2(Renderer.Resolution), map.Bounds, Renderer); - orderManager.world = new World(modData.Manifest, map, orderManager); - worldRenderer = new WorldRenderer(orderManager.world); - - if (orderManager.GameStarted) return; - Widget.SelectedWidget = null; - - orderManager.LocalFrameNumber = 0; - orderManager.StartGame(); - worldRenderer.RefreshPalette(); - AfterGameStart( orderManager.world ); - } - - public static bool IsHost - { - get { return orderManager.Connection.LocalClientId == 0; } - } - - public static Dictionary CurrentMods - { - get { return Mod.AllMods.Where( k => modData.Manifest.Mods.Contains( k.Key )).ToDictionary( k => k.Key, k => k.Value ); } - } - - static Modifiers modifiers; - public static Modifiers GetModifierKeys() { return modifiers; } - internal static void HandleModifierKeys(Modifiers mods) { modifiers = mods; } - - internal static void Initialize(Arguments args) - { - AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly; - - var defaultSupport = Environment.GetFolderPath(Environment.SpecialFolder.Personal) - + Path.DirectorySeparatorChar + "OpenRA"; - - SupportDir = args.GetValue("SupportDir", defaultSupport); - FileSystem.SpecialPackageRoot = args.GetValue("SpecialPackageRoot", ""); - - Utilities = new Utilities(args.GetValue("UtilityPath", "OpenRA.Utility.exe")); - - Settings = new Settings(SupportDir + "settings.yaml", args); - Settings.Save(); - - Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar; - Log.AddChannel("perf", "perf.log"); - Log.AddChannel("debug", "debug.log"); - Log.AddChannel("sync", "syncreport.log"); - - FileSystem.Mount("."); // Needed to access shaders - Renderer.Initialize( Game.Settings.Graphics.Mode ); - Renderer.SheetSize = Settings.Game.SheetSize; - Renderer = new Renderer(); - - Console.WriteLine("Available mods:"); - foreach(var mod in Mod.AllMods) - Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version); - - Sound.Create(); - InitializeWithMods(Settings.Game.Mods); - } - - public static void InitializeWithMods(string[] mods) - { - // Clear static state if we have switched mods - LobbyInfoChanged = () => {}; - AddChatLine = (a,b,c) => {}; - worldRenderer = null; - if (server != null) - server.Shutdown(); - if (orderManager != null) - orderManager.Dispose(); - - // Discard any invalid mods - var mm = mods.Where( m => Mod.AllMods.ContainsKey( m ) ).ToArray(); - Console.WriteLine("Loading mods: {0}",string.Join(",",mm)); - Settings.Game.Mods = mm; - Settings.Save(); - - Sound.Initialize(); - - modData = new ModData( mm ); - modData.LoadInitialAssets(); - - - PerfHistory.items["render"].hasNormalTick = false; - PerfHistory.items["batches"].hasNormalTick = false; - - JoinLocal(); - viewport = new Viewport(new int2(Renderer.Resolution), Rectangle.Empty, Renderer); - - Widget.RootWidget.RemoveChildren(); - modData.WidgetLoader.LoadWidget( new Dictionary(), Widget.RootWidget, "INIT_SETUP" ); - } - - public static void LoadShellMap() - { - StartGame(ChooseShellmap()); - Game.orderManager.LastTickTime = Environment.TickCount; - } - - static string ChooseShellmap() - { - var shellmaps = modData.AvailableMaps - .Where(m => m.Value.UseAsShellmap); - - if (shellmaps.Count() == 0) - throw new InvalidDataException("No valid shellmaps available"); - - return shellmaps.Random(CosmeticRandom).Key; - } - - static bool quit; - public static event Action OnQuit = () => {}; - internal static void Run() - { - while (!quit) - { - Tick( orderManager, viewport ); - Application.DoEvents(); - } - OnQuit(); - } - - public static void Exit() { quit = true; } - - public static Action AddChatLine = (c,n,s) => {}; - - public static void Debug(string s, params object[] args) - { - AddChatLine(Color.White, "Debug", String.Format(s,args)); - } - - public static void Disconnect() - { - if (IsHost && server != null) - server.Shutdown(); - - orderManager.Dispose(); - var shellmap = ChooseShellmap(); - JoinLocal(); - StartGame(shellmap); - - Widget.CloseWindow(); - Widget.OpenWindow("MAINMENU_BG"); - } - - static string baseSupportDir = null; - public static string SupportDir - { - set - { - var dir = value; - - // Expand paths relative to the personal directory - if (dir.ElementAt(0) == '~') - dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + dir.Substring(1); - - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); - - baseSupportDir = dir + Path.DirectorySeparatorChar; - } - get { return baseSupportDir; } - } - - public static T CreateObject( string name ) - { - return modData.ObjectCreator.CreateObject( name ); - } - - public static void CreateAndJoinServer(Settings settings, string map) - { - server = new Server.Server(modData, settings, map); - JoinServer(IPAddress.Loopback.ToString(), settings.Server.ListenPort); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Net; +using System.Windows.Forms; +using OpenRA.FileFormats; +using OpenRA.GameRules; +using OpenRA.Graphics; +using OpenRA.Network; +using OpenRA.Server; +using OpenRA.Support; +using OpenRA.Widgets; + +using XRandom = OpenRA.Thirdparty.Random; + +namespace OpenRA +{ + public static class Game + { + public static Utilities Utilities; + + public static int CellSize { get { return modData.Manifest.TileSize; } } + + public static ModData modData; + private static WorldRenderer worldRenderer; + + public static Viewport viewport; + public static Settings Settings; + + internal static OrderManager orderManager; + static Server.Server server; + + public static XRandom CosmeticRandom = new XRandom(); // not synced + + public static Renderer Renderer; + public static bool HasInputFocus = false; + + public static void MoveViewport(float2 loc) + { + viewport.Center(loc); + } + + public static void JoinServer(string host, int port) + { + var replayFilename = ChooseReplayFilename(); + string path = Path.Combine( Game.SupportDir, "Replays" ); + if( !Directory.Exists( path ) ) Directory.CreateDirectory( path ); + var replayFile = File.Create( Path.Combine( path, replayFilename ) ); + + JoinInner(new OrderManager(host, port, + new ReplayRecorderConnection(new NetworkConnection(host, port), replayFile))); + } + + static string ChooseReplayFilename() + { + return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddTHHmmssZ.rep"); + } + + static void JoinInner(OrderManager om) + { + if (orderManager != null) orderManager.Dispose(); + orderManager = om; + lastConnectionState = ConnectionState.PreConnecting; + ConnectionStateChanged(orderManager); + } + + public static void JoinReplay(string replayFile) + { + JoinInner(new OrderManager("", -1, new ReplayConnection(replayFile))); + } + + static void JoinLocal() + { + JoinInner(new OrderManager("", -1, new EchoConnection())); + } + + public static int RenderFrame = 0; + public static int NetFrameNumber { get { return orderManager.NetFrameNumber; } } + public static int LocalTick { get { return orderManager.LocalFrameNumber; } } + const int NetTickScale = 3; // 120ms net tick for 40ms local tick + + public static event Action ConnectionStateChanged = _ => { }; + static ConnectionState lastConnectionState = ConnectionState.PreConnecting; + public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } } + + + // Hacky workaround for orderManager visibility + public static Widget OpenWindow(World world, string widget) + { + return Widget.OpenWindow(widget, new Dictionary{{ "world", world }, { "orderManager", orderManager }, { "worldRenderer", worldRenderer }}); + } + + static ActionQueue afterTickActions = new ActionQueue(); + public static void RunAfterTick(Action a) { afterTickActions.Add(a); } + + static void Tick( OrderManager orderManager, Viewport viewPort ) + { + if (orderManager.Connection.ConnectionState != lastConnectionState) + { + lastConnectionState = orderManager.Connection.ConnectionState; + ConnectionStateChanged( orderManager ); + } + + Tick( orderManager ); + if( worldRenderer != null && orderManager.world != worldRenderer.world ) + Tick( worldRenderer.world.orderManager ); + + using (new PerfSample("render")) + { + ++RenderFrame; + viewport.DrawRegions(worldRenderer, new DefaultInputHandler( orderManager.world )); + Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height)); + } + + PerfHistory.items["render"].Tick(); + PerfHistory.items["batches"].Tick(); + + MasterServerQuery.Tick(); + + afterTickActions.PerformActions(); + } + + private static void Tick( OrderManager orderManager ) + { + int t = Environment.TickCount; + int dt = t - orderManager.LastTickTime; + if (dt >= Settings.Game.Timestep) + using( new PerfSample( "tick_time" ) ) + { + orderManager.LastTickTime += Settings.Game.Timestep; + Widget.DoTick(); + var world = orderManager.world; + if( orderManager.GameStarted && world.LocalPlayer != null ) + ++Viewport.TicksSinceLastMove; + Sound.Tick(); + Sync.CheckSyncUnchanged( world, () => { orderManager.TickImmediate(); } ); + + if (world != null) + { + var isNetTick = LocalTick % NetTickScale == 0; + + if (!isNetTick || orderManager.IsReadyForNextFrame) + { + ++orderManager.LocalFrameNumber; + + Log.Write("debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local"); + + if (isNetTick) orderManager.Tick(); + + + Sync.CheckSyncUnchanged(world, () => + { + world.OrderGenerator.Tick(world); + world.Selection.Tick(world); + }); + + world.Tick(); + + PerfHistory.Tick(); + } + else + if (orderManager.NetFrameNumber == 0) + orderManager.LastTickTime = Environment.TickCount; + } + } + } + + public static event Action LobbyInfoChanged = () => { }; + + internal static void SyncLobbyInfo() + { + LobbyInfoChanged(); + } + + public static event Action AfterGameStart = _ => {}; + public static event Action BeforeGameStart = () => {}; + internal static void StartGame(string mapUID) + { + BeforeGameStart(); + + var map = modData.PrepareMap(mapUID); + viewport = new Viewport(new int2(Renderer.Resolution), map.Bounds, Renderer); + orderManager.world = new World(modData.Manifest, map, orderManager); + worldRenderer = new WorldRenderer(orderManager.world); + + if (orderManager.GameStarted) return; + Widget.SelectedWidget = null; + + orderManager.LocalFrameNumber = 0; + orderManager.StartGame(); + worldRenderer.RefreshPalette(); + AfterGameStart( orderManager.world ); + } + + public static bool IsHost + { + get { return orderManager.Connection.LocalClientId == 0; } + } + + public static Dictionary CurrentMods + { + get { return Mod.AllMods.Where( k => modData.Manifest.Mods.Contains( k.Key )).ToDictionary( k => k.Key, k => k.Value ); } + } + + static Modifiers modifiers; + public static Modifiers GetModifierKeys() { return modifiers; } + internal static void HandleModifierKeys(Modifiers mods) { modifiers = mods; } + + internal static void Initialize(Arguments args) + { + AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly; + + var defaultSupport = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + + Path.DirectorySeparatorChar + "OpenRA"; + + SupportDir = args.GetValue("SupportDir", defaultSupport); + FileSystem.SpecialPackageRoot = args.GetValue("SpecialPackageRoot", ""); + + Utilities = new Utilities(args.GetValue("UtilityPath", "OpenRA.Utility.exe")); + + Settings = new Settings(SupportDir + "settings.yaml", args); + Settings.Save(); + + Log.LogPath = SupportDir + "Logs" + Path.DirectorySeparatorChar; + Log.AddChannel("perf", "perf.log"); + Log.AddChannel("debug", "debug.log"); + Log.AddChannel("sync", "syncreport.log"); + + FileSystem.Mount("."); // Needed to access shaders + Renderer.Initialize( Game.Settings.Graphics.Mode ); + Renderer.SheetSize = Settings.Game.SheetSize; + Renderer = new Renderer(); + + Console.WriteLine("Available mods:"); + foreach(var mod in Mod.AllMods) + Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version); + + Sound.Create(); + InitializeWithMods(Settings.Game.Mods); + } + + public static void InitializeWithMods(string[] mods) + { + // Clear static state if we have switched mods + LobbyInfoChanged = () => {}; + AddChatLine = (a,b,c) => {}; + worldRenderer = null; + if (server != null) + server.Shutdown(); + if (orderManager != null) + orderManager.Dispose(); + + // Discard any invalid mods + var mm = mods.Where( m => Mod.AllMods.ContainsKey( m ) ).ToArray(); + Console.WriteLine("Loading mods: {0}",string.Join(",",mm)); + Settings.Game.Mods = mm; + Settings.Save(); + + Sound.Initialize(); + + modData = new ModData( mm ); + modData.LoadInitialAssets(); + + + PerfHistory.items["render"].hasNormalTick = false; + PerfHistory.items["batches"].hasNormalTick = false; + + JoinLocal(); + viewport = new Viewport(new int2(Renderer.Resolution), Rectangle.Empty, Renderer); + + Widget.RootWidget.RemoveChildren(); + modData.WidgetLoader.LoadWidget( new Dictionary(), Widget.RootWidget, "INIT_SETUP" ); + } + + public static void LoadShellMap() + { + StartGame(ChooseShellmap()); + Game.orderManager.LastTickTime = Environment.TickCount; + } + + static string ChooseShellmap() + { + var shellmaps = modData.AvailableMaps + .Where(m => m.Value.UseAsShellmap); + + if (shellmaps.Count() == 0) + throw new InvalidDataException("No valid shellmaps available"); + + return shellmaps.Random(CosmeticRandom).Key; + } + + static bool quit; + public static event Action OnQuit = () => {}; + internal static void Run() + { + while (!quit) + { + Tick( orderManager, viewport ); + Application.DoEvents(); + } + OnQuit(); + } + + public static void Exit() { quit = true; } + + public static Action AddChatLine = (c,n,s) => {}; + + public static void Debug(string s, params object[] args) + { + AddChatLine(Color.White, "Debug", String.Format(s,args)); + } + + public static void Disconnect() + { + if (IsHost && server != null) + server.Shutdown(); + + orderManager.Dispose(); + var shellmap = ChooseShellmap(); + JoinLocal(); + StartGame(shellmap); + + Widget.CloseWindow(); + Widget.OpenWindow("MAINMENU_BG"); + } + + static string baseSupportDir = null; + public static string SupportDir + { + set + { + var dir = value; + + // Expand paths relative to the personal directory + if (dir.ElementAt(0) == '~') + dir = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + dir.Substring(1); + + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + + baseSupportDir = dir + Path.DirectorySeparatorChar; + } + get { return baseSupportDir; } + } + + public static T CreateObject( string name ) + { + return modData.ObjectCreator.CreateObject( name ); + } + + public static void CreateAndJoinServer(Settings settings, string map) + { + server = new Server.Server(modData, settings, map); + JoinServer(IPAddress.Loopback.ToString(), settings.Server.ListenPort); + } + } +} diff --git a/OpenRA.Game/GameRules/ActorInfo.cs b/OpenRA.Game/GameRules/ActorInfo.cs index 7a5a584cf2..63bd3fda48 100644 --- a/OpenRA.Game/GameRules/ActorInfo.cs +++ b/OpenRA.Game/GameRules/ActorInfo.cs @@ -1,99 +1,99 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA -{ - public class ActorInfo - { - public readonly string Name; - public readonly TypeDictionary Traits = new TypeDictionary(); - - public ActorInfo( string name, MiniYaml node, Dictionary allUnits ) - { - var mergedNode = MergeWithParent( node, allUnits ).NodesDict; - - Name = name; - foreach( var t in mergedNode ) - if( t.Key != "Inherits" && !t.Key.StartsWith("-") ) - Traits.Add( LoadTraitInfo( t.Key.Split('@')[0], t.Value ) ); - } - - static MiniYaml GetParent( MiniYaml node, Dictionary allUnits ) - { - MiniYaml inherits; - node.NodesDict.TryGetValue( "Inherits", out inherits ); - if( inherits == null || string.IsNullOrEmpty( inherits.Value ) ) - return null; - - MiniYaml parent; - allUnits.TryGetValue( inherits.Value, out parent ); - if( parent == null ) - return null; - - return parent; - } - - static MiniYaml MergeWithParent( MiniYaml node, Dictionary allUnits ) - { - var parent = GetParent( node, allUnits ); - if( parent != null ) - return MiniYaml.Merge( node, MergeWithParent( parent, allUnits ) ); - return node; - } - - static ITraitInfo LoadTraitInfo(string traitName, MiniYaml my) - { - var info = Game.CreateObject(traitName + "Info"); - FieldLoader.Load(info, my); - return info; - } - - public IEnumerable TraitsInConstructOrder() - { - var ret = new List(); - var t = Traits.WithInterface().ToList(); - int index = 0; - while (t.Count != 0) - { - var prereqs = PrerequisitesOf(t[index]); - var unsatisfied = prereqs.Where(n => !ret.Any(x => x.GetType() == n || x.GetType().IsSubclassOf(n))); - if (!unsatisfied.Any()) - { - ret.Add(t[index]); - t.RemoveAt(index); - index = 0; - } - else if (++index >= t.Count) - throw new InvalidOperationException("Trait prerequisites not satisfied (or prerequisite loop) Actor={0} Unresolved={1} Missing={2}".F( - Name, - string.Join(",", t.Select(x => x.GetType().Name).ToArray()), - string.Join(",", unsatisfied.Select(x => x.Name).ToArray()))); - } - - return ret; - } - - static List PrerequisitesOf( ITraitInfo info ) - { - return info - .GetType() - .GetInterfaces() - .Where( t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof( ITraitPrerequisite<> ) ) - .Select( t => t.GetGenericArguments()[ 0 ] ) - .ToList(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA +{ + public class ActorInfo + { + public readonly string Name; + public readonly TypeDictionary Traits = new TypeDictionary(); + + public ActorInfo( string name, MiniYaml node, Dictionary allUnits ) + { + var mergedNode = MergeWithParent( node, allUnits ).NodesDict; + + Name = name; + foreach( var t in mergedNode ) + if( t.Key != "Inherits" && !t.Key.StartsWith("-") ) + Traits.Add( LoadTraitInfo( t.Key.Split('@')[0], t.Value ) ); + } + + static MiniYaml GetParent( MiniYaml node, Dictionary allUnits ) + { + MiniYaml inherits; + node.NodesDict.TryGetValue( "Inherits", out inherits ); + if( inherits == null || string.IsNullOrEmpty( inherits.Value ) ) + return null; + + MiniYaml parent; + allUnits.TryGetValue( inherits.Value, out parent ); + if( parent == null ) + return null; + + return parent; + } + + static MiniYaml MergeWithParent( MiniYaml node, Dictionary allUnits ) + { + var parent = GetParent( node, allUnits ); + if( parent != null ) + return MiniYaml.Merge( node, MergeWithParent( parent, allUnits ) ); + return node; + } + + static ITraitInfo LoadTraitInfo(string traitName, MiniYaml my) + { + var info = Game.CreateObject(traitName + "Info"); + FieldLoader.Load(info, my); + return info; + } + + public IEnumerable TraitsInConstructOrder() + { + var ret = new List(); + var t = Traits.WithInterface().ToList(); + int index = 0; + while (t.Count != 0) + { + var prereqs = PrerequisitesOf(t[index]); + var unsatisfied = prereqs.Where(n => !ret.Any(x => x.GetType() == n || x.GetType().IsSubclassOf(n))); + if (!unsatisfied.Any()) + { + ret.Add(t[index]); + t.RemoveAt(index); + index = 0; + } + else if (++index >= t.Count) + throw new InvalidOperationException("Trait prerequisites not satisfied (or prerequisite loop) Actor={0} Unresolved={1} Missing={2}".F( + Name, + string.Join(",", t.Select(x => x.GetType().Name).ToArray()), + string.Join(",", unsatisfied.Select(x => x.Name).ToArray()))); + } + + return ret; + } + + static List PrerequisitesOf( ITraitInfo info ) + { + return info + .GetType() + .GetInterfaces() + .Where( t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof( ITraitPrerequisite<> ) ) + .Select( t => t.GetGenericArguments()[ 0 ] ) + .ToList(); + } + } +} diff --git a/OpenRA.Game/GameRules/MusicInfo.cs b/OpenRA.Game/GameRules/MusicInfo.cs index ca3a31d4ea..bdeff4aafa 100644 --- a/OpenRA.Game/GameRules/MusicInfo.cs +++ b/OpenRA.Game/GameRules/MusicInfo.cs @@ -1,34 +1,34 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + using OpenRA.FileFormats; namespace OpenRA.GameRules { public class MusicInfo - { - public readonly string Filename = null; - public readonly string Title = null; - public readonly int Length = 0; // seconds + { + public readonly string Filename = null; + public readonly string Title = null; + public readonly int Length = 0; // seconds public readonly bool Exists = false; public MusicInfo( string key, MiniYaml value ) { - Filename = key+".aud"; - Title = value.Value; - - if (!FileSystem.Exists(Filename)) - return; - - Exists = true; - Length = (int)AudLoader.SoundLength(FileSystem.Open(Filename)); + Filename = key+".aud"; + Title = value.Value; + + if (!FileSystem.Exists(Filename)) + return; + + Exists = true; + Length = (int)AudLoader.SoundLength(FileSystem.Open(Filename)); } } } diff --git a/OpenRA.Game/GameRules/Rules.cs b/OpenRA.Game/GameRules/Rules.cs index 12dca3a90c..390284ba11 100755 --- a/OpenRA.Game/GameRules/Rules.cs +++ b/OpenRA.Game/GameRules/Rules.cs @@ -1,52 +1,52 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.GameRules; - -namespace OpenRA -{ - public static class Rules - { - public static Dictionary Info; - public static Dictionary Weapons; - public static Dictionary Voices; - public static Dictionary Music; - public static Dictionary Movies; - public static Dictionary TileSets; - - public static void LoadRules(Manifest m, Map map) - { - // Added support to extend the list of rules (add it to m.LocalRules) - Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y)); - Weapons = LoadYamlRules(m.Weapons, map.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); - Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new VoiceInfo(k.Value)); - Music = LoadYamlRules(m.Music, new List(), (k, _) => new MusicInfo(k.Key, k.Value)); - Movies = LoadYamlRules(m.Movies, new List(), (k, v) => k.Value.Value); - - TileSets = new Dictionary(); - foreach (var file in m.TileSets) - { - var t = new TileSet(file); - TileSets.Add(t.Id,t); - } - } - - static Dictionary LoadYamlRules(string[] files, List dict, Func, T> f) - { - var y = files.Select(a => MiniYaml.FromFile(a)).Aggregate(dict,MiniYaml.Merge); - var yy = y.ToDictionary( x => x.Key, x => x.Value ); - return y.ToDictionary(kv => kv.Key.ToLowerInvariant(), kv => f(kv, yy)); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.GameRules; + +namespace OpenRA +{ + public static class Rules + { + public static Dictionary Info; + public static Dictionary Weapons; + public static Dictionary Voices; + public static Dictionary Music; + public static Dictionary Movies; + public static Dictionary TileSets; + + public static void LoadRules(Manifest m, Map map) + { + // Added support to extend the list of rules (add it to m.LocalRules) + Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y)); + Weapons = LoadYamlRules(m.Weapons, map.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); + Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new VoiceInfo(k.Value)); + Music = LoadYamlRules(m.Music, new List(), (k, _) => new MusicInfo(k.Key, k.Value)); + Movies = LoadYamlRules(m.Movies, new List(), (k, v) => k.Value.Value); + + TileSets = new Dictionary(); + foreach (var file in m.TileSets) + { + var t = new TileSet(file); + TileSets.Add(t.Id,t); + } + } + + static Dictionary LoadYamlRules(string[] files, List dict, Func, T> f) + { + var y = files.Select(a => MiniYaml.FromFile(a)).Aggregate(dict,MiniYaml.Merge); + var yy = y.ToDictionary( x => x.Key, x => x.Value ); + return y.ToDictionary(kv => kv.Key.ToLowerInvariant(), kv => f(kv, yy)); + } + } +} diff --git a/OpenRA.Game/GameRules/Settings.cs b/OpenRA.Game/GameRules/Settings.cs index e25fcc95fe..f51ea9051d 100755 --- a/OpenRA.Game/GameRules/Settings.cs +++ b/OpenRA.Game/GameRules/Settings.cs @@ -1,162 +1,162 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Windows.Forms; -using OpenRA.FileFormats; -using OpenRA.FileFormats.Graphics; -using OpenRA.Server; - -namespace OpenRA.GameRules -{ - public class ServerSettings - { - public string Name = "OpenRA Game"; - public int ListenPort = 1234; - public int ExternalPort = 1234; - public bool AdvertiseOnline = true; - public string MasterServer = "http://master.open-ra.org/"; - public bool AllowCheats = false; - } - - public class DebugSettings - { - public bool BotDebug = false; - public bool PerfGraph = false; - public float LongTickThreshold = 0.001f; - public bool SanityCheckUnsyncedCode = false; - } - - public class GraphicSettings - { - public string Renderer = "Gl"; - public WindowMode Mode = WindowMode.PseudoFullscreen; - public int2 FullscreenSize = new int2(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); - public int2 WindowedSize = new int2(1024, 768); - public readonly int2 MinResolution = new int2(800, 600); - } - - public class SoundSettings - { - public float SoundVolume = 0.5f; - public float MusicVolume = 0.5f; - public float VideoVolume = 0.5f; - public bool Shuffle = false; - public bool Repeat = false; - } - - public class PlayerSettings - { - public string Name = "Newbie"; - [Obsolete] public Color Color1 = Color.FromArgb(255,160,238); - [Obsolete] public Color Color2 = Color.FromArgb(68,0,56); - public ColorRamp ColorRamp = new ColorRamp(75, 255, 180, 25); - public string LastServer = "localhost:1234"; - } - - public class GameSettings - { - public string[] Mods = { "ra" }; - public bool MatchTimer = true; - - // Chat settings - public bool TeamChatToggle = false; - - // Behaviour settings - public bool ViewportEdgeScroll = true; - public bool InverseDragScroll = false; - public float ViewportEdgeScrollStep = 10f; - - // Internal game settings - public int Timestep = 40; - public int SheetSize = 2048; - } - - public class Settings - { - string SettingsFile; - - public PlayerSettings Player = new PlayerSettings(); - public GameSettings Game = new GameSettings(); - public SoundSettings Sound = new SoundSettings(); - public GraphicSettings Graphics = new GraphicSettings(); - public ServerSettings Server = new ServerSettings(); - public DebugSettings Debug = new DebugSettings(); - - public Dictionary Sections; - public Settings(string file, Arguments args) - { - SettingsFile = file; - Sections = new Dictionary() - { - {"Player", Player}, - {"Game", Game}, - {"Sound", Sound}, - {"Graphics", Graphics}, - {"Server", Server}, - {"Debug", Debug} - }; - - - // Override fieldloader to ignore invalid entries - var err1 = FieldLoader.UnknownFieldAction; - var err2 = FieldLoader.InvalidValueAction; - - FieldLoader.UnknownFieldAction = (s,f) => - { - Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) ); - }; - - if (File.Exists(SettingsFile)) - { - //Console.WriteLine("Loading settings file {0}",SettingsFile); - var yaml = MiniYaml.DictFromFile(SettingsFile); - - foreach (var kv in Sections) - if (yaml.ContainsKey(kv.Key)) - LoadSectionYaml(yaml[kv.Key], kv.Value); - } - - // Override with commandline args - foreach (var kv in Sections) - foreach (var f in kv.Value.GetType().GetFields()) - if (args.Contains(kv.Key+"."+f.Name)) - FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") ); - - FieldLoader.UnknownFieldAction = err1; - FieldLoader.InvalidValueAction = err2; - } - - public void Save() - { - var root = new List(); - foreach( var kv in Sections ) - root.Add( new MiniYamlNode( kv.Key, FieldSaver.SaveDifferences(kv.Value, Activator.CreateInstance(kv.Value.GetType())) ) ); - - root.WriteToFile(SettingsFile); - } - - void LoadSectionYaml(MiniYaml yaml, object section) - { - object defaults = Activator.CreateInstance(section.GetType()); - FieldLoader.InvalidValueAction = (s,t,f) => - { - object ret = defaults.GetType().GetField(f).GetValue(defaults); - System.Console.WriteLine("FieldLoader: Cannot parse `{0}` into `{2}:{1}`; substituting default `{3}`".F(s,t.Name,f,ret) ); - return ret; - }; - - FieldLoader.Load(section, yaml); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using OpenRA.FileFormats; +using OpenRA.FileFormats.Graphics; +using OpenRA.Server; + +namespace OpenRA.GameRules +{ + public class ServerSettings + { + public string Name = "OpenRA Game"; + public int ListenPort = 1234; + public int ExternalPort = 1234; + public bool AdvertiseOnline = true; + public string MasterServer = "http://master.open-ra.org/"; + public bool AllowCheats = false; + } + + public class DebugSettings + { + public bool BotDebug = false; + public bool PerfGraph = false; + public float LongTickThreshold = 0.001f; + public bool SanityCheckUnsyncedCode = false; + } + + public class GraphicSettings + { + public string Renderer = "Gl"; + public WindowMode Mode = WindowMode.PseudoFullscreen; + public int2 FullscreenSize = new int2(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); + public int2 WindowedSize = new int2(1024, 768); + public readonly int2 MinResolution = new int2(800, 600); + } + + public class SoundSettings + { + public float SoundVolume = 0.5f; + public float MusicVolume = 0.5f; + public float VideoVolume = 0.5f; + public bool Shuffle = false; + public bool Repeat = false; + } + + public class PlayerSettings + { + public string Name = "Newbie"; + [Obsolete] public Color Color1 = Color.FromArgb(255,160,238); + [Obsolete] public Color Color2 = Color.FromArgb(68,0,56); + public ColorRamp ColorRamp = new ColorRamp(75, 255, 180, 25); + public string LastServer = "localhost:1234"; + } + + public class GameSettings + { + public string[] Mods = { "ra" }; + public bool MatchTimer = true; + + // Chat settings + public bool TeamChatToggle = false; + + // Behaviour settings + public bool ViewportEdgeScroll = true; + public bool InverseDragScroll = false; + public float ViewportEdgeScrollStep = 10f; + + // Internal game settings + public int Timestep = 40; + public int SheetSize = 2048; + } + + public class Settings + { + string SettingsFile; + + public PlayerSettings Player = new PlayerSettings(); + public GameSettings Game = new GameSettings(); + public SoundSettings Sound = new SoundSettings(); + public GraphicSettings Graphics = new GraphicSettings(); + public ServerSettings Server = new ServerSettings(); + public DebugSettings Debug = new DebugSettings(); + + public Dictionary Sections; + public Settings(string file, Arguments args) + { + SettingsFile = file; + Sections = new Dictionary() + { + {"Player", Player}, + {"Game", Game}, + {"Sound", Sound}, + {"Graphics", Graphics}, + {"Server", Server}, + {"Debug", Debug} + }; + + + // Override fieldloader to ignore invalid entries + var err1 = FieldLoader.UnknownFieldAction; + var err2 = FieldLoader.InvalidValueAction; + + FieldLoader.UnknownFieldAction = (s,f) => + { + Console.WriteLine( "Ignoring unknown field `{0}` on `{1}`".F( s, f.Name ) ); + }; + + if (File.Exists(SettingsFile)) + { + //Console.WriteLine("Loading settings file {0}",SettingsFile); + var yaml = MiniYaml.DictFromFile(SettingsFile); + + foreach (var kv in Sections) + if (yaml.ContainsKey(kv.Key)) + LoadSectionYaml(yaml[kv.Key], kv.Value); + } + + // Override with commandline args + foreach (var kv in Sections) + foreach (var f in kv.Value.GetType().GetFields()) + if (args.Contains(kv.Key+"."+f.Name)) + FieldLoader.LoadField( kv.Value, f.Name, args.GetValue(kv.Key+"."+f.Name, "") ); + + FieldLoader.UnknownFieldAction = err1; + FieldLoader.InvalidValueAction = err2; + } + + public void Save() + { + var root = new List(); + foreach( var kv in Sections ) + root.Add( new MiniYamlNode( kv.Key, FieldSaver.SaveDifferences(kv.Value, Activator.CreateInstance(kv.Value.GetType())) ) ); + + root.WriteToFile(SettingsFile); + } + + void LoadSectionYaml(MiniYaml yaml, object section) + { + object defaults = Activator.CreateInstance(section.GetType()); + FieldLoader.InvalidValueAction = (s,t,f) => + { + object ret = defaults.GetType().GetField(f).GetValue(defaults); + System.Console.WriteLine("FieldLoader: Cannot parse `{0}` into `{2}:{1}`; substituting default `{3}`".F(s,t.Name,f,ret) ); + return ret; + }; + + FieldLoader.Load(section, yaml); + } + } +} diff --git a/OpenRA.Game/GameRules/VoiceInfo.cs b/OpenRA.Game/GameRules/VoiceInfo.cs index efca5c0114..b14b9a8b1a 100644 --- a/OpenRA.Game/GameRules/VoiceInfo.cs +++ b/OpenRA.Game/GameRules/VoiceInfo.cs @@ -1,76 +1,76 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using System; - -namespace OpenRA.GameRules -{ - public class VoiceInfo - { - public readonly Dictionary Variants; - public readonly Dictionary Voices; - public readonly string DefaultVariant = ".aud" ; - [FieldLoader.Load] public readonly string[] DisableVariants = { }; - - static Dictionary Load( MiniYaml y, string name ) - { - return y.NodesDict.ContainsKey( name ) - ? y.NodesDict[ name ].NodesDict.ToDictionary( - a => a.Key, - a => (string[])FieldLoader.GetValue( "(value)", typeof( string[] ), a.Value.Value ) ) - : new Dictionary(); - } - - public readonly OpenRA.FileFormats.Lazy> Pools; - - public VoiceInfo( MiniYaml y ) - { - FieldLoader.Load( this, y ); - Variants = Load(y, "Variants"); - Voices = Load(y, "Voices"); - - if (!Voices.ContainsKey("Attack")) - Voices.Add("Attack", Voices["Move"]); - - if (!Voices.ContainsKey("AttackMove")) - Voices.Add("AttackMove", Voices["Move"]); - - Pools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new VoicePool(a.Value) )); - } - } - - public class VoicePool - { - readonly string[] clips; - readonly List liveclips = new List(); - - public VoicePool(params string[] clips) - { - this.clips = clips; - } - - public string GetNext() - { - if (liveclips.Count == 0) - liveclips.AddRange(clips); - - if (liveclips.Count == 0) - return null; /* avoid crashing if there's no clips at all */ - - var i = Game.CosmeticRandom.Next(liveclips.Count); - var s = liveclips[i]; - liveclips.RemoveAt(i); - return s; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using System; + +namespace OpenRA.GameRules +{ + public class VoiceInfo + { + public readonly Dictionary Variants; + public readonly Dictionary Voices; + public readonly string DefaultVariant = ".aud" ; + [FieldLoader.Load] public readonly string[] DisableVariants = { }; + + static Dictionary Load( MiniYaml y, string name ) + { + return y.NodesDict.ContainsKey( name ) + ? y.NodesDict[ name ].NodesDict.ToDictionary( + a => a.Key, + a => (string[])FieldLoader.GetValue( "(value)", typeof( string[] ), a.Value.Value ) ) + : new Dictionary(); + } + + public readonly OpenRA.FileFormats.Lazy> Pools; + + public VoiceInfo( MiniYaml y ) + { + FieldLoader.Load( this, y ); + Variants = Load(y, "Variants"); + Voices = Load(y, "Voices"); + + if (!Voices.ContainsKey("Attack")) + Voices.Add("Attack", Voices["Move"]); + + if (!Voices.ContainsKey("AttackMove")) + Voices.Add("AttackMove", Voices["Move"]); + + Pools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new VoicePool(a.Value) )); + } + } + + public class VoicePool + { + readonly string[] clips; + readonly List liveclips = new List(); + + public VoicePool(params string[] clips) + { + this.clips = clips; + } + + public string GetNext() + { + if (liveclips.Count == 0) + liveclips.AddRange(clips); + + if (liveclips.Count == 0) + return null; /* avoid crashing if there's no clips at all */ + + var i = Game.CosmeticRandom.Next(liveclips.Count); + var s = liveclips[i]; + liveclips.RemoveAt(i); + return s; + } + } +} diff --git a/OpenRA.Game/GameRules/WeaponInfo.cs b/OpenRA.Game/GameRules/WeaponInfo.cs index 9b19e66aa9..cf386629bc 100644 --- a/OpenRA.Game/GameRules/WeaponInfo.cs +++ b/OpenRA.Game/GameRules/WeaponInfo.cs @@ -1,126 +1,126 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.FileFormats; -using OpenRA.Traits; -using System.Linq; - -namespace OpenRA.GameRules -{ - public class WarheadInfo - { - [FieldLoader.Load] public readonly int Spread = 1; // distance (in pixels) from the explosion center at which damage is 1/2. - [FieldLoader.LoadUsing( "LoadVersus" )] - public readonly Dictionary Versus; // damage vs each armortype - [FieldLoader.Load] public readonly bool Ore = false; // can this damage ore? - [FieldLoader.Load] public readonly string Explosion = null; // explosion effect to use - [FieldLoader.Load] public readonly string WaterExplosion = null; // explosion effect on hitting water (usually a splash) - [FieldLoader.Load] public readonly string SmudgeType = null; // type of smudge to apply - [FieldLoader.Load] public readonly int[] Size = { 0, 0 }; // size of the explosion. provide 2 values for a ring effect (outer/inner) - [FieldLoader.Load] public readonly int InfDeath = 0; // infantry death animation to use - [FieldLoader.Load] public readonly string ImpactSound = null; // sound to play on impact - [FieldLoader.Load] public readonly string WaterImpactSound = null; // sound to play on impact with water - [FieldLoader.Load] public readonly int Damage = 0; // how much (raw) damage to deal - [FieldLoader.Load] public readonly int Delay = 0; // delay in ticks before dealing the damage. 0=instant (old model) - [FieldLoader.Load] public readonly DamageModel DamageModel = DamageModel.Normal; // which damage model to use - [FieldLoader.Load] public readonly bool PreventProne = false; // whether we should prevent prone response in infantry. - - public float EffectivenessAgainst(Actor self) - { - var health = self.Info.Traits.GetOrDefault(); - if (health == null) return 0f; - var armor = self.Info.Traits.GetOrDefault(); - if (armor == null || armor.Type == null) return 1; - - float versus; - return Versus.TryGetValue(armor.Type, out versus) ? versus : 1; - } - - public WarheadInfo( MiniYaml yaml ) - { - FieldLoader.Load( this, yaml ); - } - - static object LoadVersus( MiniYaml y ) - { - return y.NodesDict.ContainsKey( "Versus" ) - ? y.NodesDict[ "Versus" ].NodesDict.ToDictionary( - a => a.Key, - a => (float)FieldLoader.GetValue( "(value)", typeof( float ), a.Value.Value ) ) - : new Dictionary(); - } - } - - - - public enum DamageModel - { - Normal, // classic RA damage model: point actors, distance-based falloff - PerCell, // like RA's "nuke damage" - } - - public class ProjectileArgs - { - public WeaponInfo weapon; - public Actor firedBy; - public int2 src; - public int srcAltitude; - public int facing; - public Target target; - public int2 dest; - public int destAltitude; - public float firepowerModifier = 1.0f; - } - - public interface IProjectileInfo { IEffect Create(ProjectileArgs args); } - - public class WeaponInfo - { - [FieldLoader.Load] public readonly float Range = 0; - [FieldLoader.Load] public readonly string Report = null; - [FieldLoader.Load] public readonly int ROF = 1; - [FieldLoader.Load] public readonly int Burst = 1; - [FieldLoader.Load] public readonly bool Charges = false; - [FieldLoader.Load] public readonly bool Underwater = false; - [FieldLoader.Load] public readonly string[] ValidTargets = { "Ground" }; - [FieldLoader.Load] public readonly int BurstDelay = 5; - [FieldLoader.Load] public readonly float MinRange = 0; - - [FieldLoader.LoadUsing( "LoadProjectile" )] public IProjectileInfo Projectile; - [FieldLoader.LoadUsing( "LoadWarheads" )] public List Warheads; - - public WeaponInfo(string name, MiniYaml content) - { - FieldLoader.Load( this, content ); - } - - static object LoadProjectile( MiniYaml yaml ) - { - MiniYaml proj; - if( !yaml.NodesDict.TryGetValue( "Projectile", out proj ) ) - return null; - var ret = Game.CreateObject( proj.Value + "Info" ); - FieldLoader.Load( ret, proj ); - return ret; - } - - static object LoadWarheads( MiniYaml yaml ) - { - var ret = new List(); - foreach( var w in yaml.Nodes ) - if( w.Key.Split( '@' )[ 0 ] == "Warhead" ) - ret.Add( new WarheadInfo( w.Value ) ); - - return ret; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.FileFormats; +using OpenRA.Traits; +using System.Linq; + +namespace OpenRA.GameRules +{ + public class WarheadInfo + { + [FieldLoader.Load] public readonly int Spread = 1; // distance (in pixels) from the explosion center at which damage is 1/2. + [FieldLoader.LoadUsing( "LoadVersus" )] + public readonly Dictionary Versus; // damage vs each armortype + [FieldLoader.Load] public readonly bool Ore = false; // can this damage ore? + [FieldLoader.Load] public readonly string Explosion = null; // explosion effect to use + [FieldLoader.Load] public readonly string WaterExplosion = null; // explosion effect on hitting water (usually a splash) + [FieldLoader.Load] public readonly string SmudgeType = null; // type of smudge to apply + [FieldLoader.Load] public readonly int[] Size = { 0, 0 }; // size of the explosion. provide 2 values for a ring effect (outer/inner) + [FieldLoader.Load] public readonly int InfDeath = 0; // infantry death animation to use + [FieldLoader.Load] public readonly string ImpactSound = null; // sound to play on impact + [FieldLoader.Load] public readonly string WaterImpactSound = null; // sound to play on impact with water + [FieldLoader.Load] public readonly int Damage = 0; // how much (raw) damage to deal + [FieldLoader.Load] public readonly int Delay = 0; // delay in ticks before dealing the damage. 0=instant (old model) + [FieldLoader.Load] public readonly DamageModel DamageModel = DamageModel.Normal; // which damage model to use + [FieldLoader.Load] public readonly bool PreventProne = false; // whether we should prevent prone response in infantry. + + public float EffectivenessAgainst(Actor self) + { + var health = self.Info.Traits.GetOrDefault(); + if (health == null) return 0f; + var armor = self.Info.Traits.GetOrDefault(); + if (armor == null || armor.Type == null) return 1; + + float versus; + return Versus.TryGetValue(armor.Type, out versus) ? versus : 1; + } + + public WarheadInfo( MiniYaml yaml ) + { + FieldLoader.Load( this, yaml ); + } + + static object LoadVersus( MiniYaml y ) + { + return y.NodesDict.ContainsKey( "Versus" ) + ? y.NodesDict[ "Versus" ].NodesDict.ToDictionary( + a => a.Key, + a => (float)FieldLoader.GetValue( "(value)", typeof( float ), a.Value.Value ) ) + : new Dictionary(); + } + } + + + + public enum DamageModel + { + Normal, // classic RA damage model: point actors, distance-based falloff + PerCell, // like RA's "nuke damage" + } + + public class ProjectileArgs + { + public WeaponInfo weapon; + public Actor firedBy; + public int2 src; + public int srcAltitude; + public int facing; + public Target target; + public int2 dest; + public int destAltitude; + public float firepowerModifier = 1.0f; + } + + public interface IProjectileInfo { IEffect Create(ProjectileArgs args); } + + public class WeaponInfo + { + [FieldLoader.Load] public readonly float Range = 0; + [FieldLoader.Load] public readonly string Report = null; + [FieldLoader.Load] public readonly int ROF = 1; + [FieldLoader.Load] public readonly int Burst = 1; + [FieldLoader.Load] public readonly bool Charges = false; + [FieldLoader.Load] public readonly bool Underwater = false; + [FieldLoader.Load] public readonly string[] ValidTargets = { "Ground" }; + [FieldLoader.Load] public readonly int BurstDelay = 5; + [FieldLoader.Load] public readonly float MinRange = 0; + + [FieldLoader.LoadUsing( "LoadProjectile" )] public IProjectileInfo Projectile; + [FieldLoader.LoadUsing( "LoadWarheads" )] public List Warheads; + + public WeaponInfo(string name, MiniYaml content) + { + FieldLoader.Load( this, content ); + } + + static object LoadProjectile( MiniYaml yaml ) + { + MiniYaml proj; + if( !yaml.NodesDict.TryGetValue( "Projectile", out proj ) ) + return null; + var ret = Game.CreateObject( proj.Value + "Info" ); + FieldLoader.Load( ret, proj ); + return ret; + } + + static object LoadWarheads( MiniYaml yaml ) + { + var ret = new List(); + foreach( var w in yaml.Nodes ) + if( w.Key.Split( '@' )[ 0 ] == "Warhead" ) + ret.Add( new WarheadInfo( w.Value ) ); + + return ret; + } + } +} diff --git a/OpenRA.Game/Graphics/Animation.cs b/OpenRA.Game/Graphics/Animation.cs index 63f01ac475..58a2ee8777 100644 --- a/OpenRA.Game/Graphics/Animation.cs +++ b/OpenRA.Game/Graphics/Animation.cs @@ -1,145 +1,145 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; - -namespace OpenRA.Graphics -{ - public class Animation - { - string name; - public Sequence CurrentSequence { get; private set; } - int frame = 0; - bool backwards = false; - bool tickAlways; - - Func facingFunc; - - public string Name { get { return name; } } - - public Animation( string name ) - : this( name, () => 0 ) - { - } - - public Animation( string name, Func facingFunc ) - { - this.name = name.ToLowerInvariant(); - this.tickFunc = () => { }; - this.facingFunc = facingFunc; - } - - public Sprite Image - { - get - { - return backwards - ? CurrentSequence.GetSprite(CurrentSequence.End - frame - 1, facingFunc()) - : CurrentSequence.GetSprite(frame, facingFunc()); - } - } - - public void Play( string sequenceName ) - { - PlayThen(sequenceName, () => { }); - } - - public void PlayRepeating( string sequenceName ) - { - PlayThen( sequenceName, () => PlayRepeating( CurrentSequence.Name ) ); - } - - public bool ReplaceAnim(string sequenceName) - { - if (!HasSequence(sequenceName)) - return false; - - CurrentSequence = SequenceProvider.GetSequence(name, sequenceName); - frame %= CurrentSequence.Length; - return true; - } - - public void PlayThen( string sequenceName, Action after ) - { - after = after ?? ( () => { } ); - backwards = false; - tickAlways = false; - CurrentSequence = SequenceProvider.GetSequence( name, sequenceName ); - frame = 0; - tickFunc = () => - { - ++frame; - if( frame >= CurrentSequence.Length ) - { - frame = CurrentSequence.Length - 1; - tickFunc = () => { }; - after(); - } - }; - } - - public void PlayBackwardsThen(string sequenceName, Action after) - { - PlayThen(sequenceName, after); - backwards = true; - } - - public void PlayFetchIndex( string sequenceName, Func func ) - { - backwards = false; - tickAlways = true; - CurrentSequence = SequenceProvider.GetSequence( name, sequenceName ); - frame = func(); - tickFunc = () => frame = func(); - } - - int timeUntilNextFrame; - Action tickFunc; - - public void Tick() - { - Tick( 40 ); // tick one frame - } - - public bool HasSequence(string seq) { return SequenceProvider.HasSequence( name, seq ); } - - public void Tick( int t ) - { - if( tickAlways ) - tickFunc(); - else - { - timeUntilNextFrame -= t; - while( timeUntilNextFrame <= 0 ) - { - tickFunc(); - timeUntilNextFrame += CurrentSequence != null ? CurrentSequence.Tick : 40; // 25 fps == 40 ms - } - } - } - - public void ChangeImage(string newImage, string newAnimIfMissing) - { - newImage = newImage.ToLowerInvariant(); - - if (name != newImage) - { - name = newImage.ToLowerInvariant(); - if (!ReplaceAnim(CurrentSequence.Name)) - ReplaceAnim(newAnimIfMissing); - } - } - - public Sequence GetSequence( string sequenceName ) - { - return SequenceProvider.GetSequence( name, sequenceName ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; + +namespace OpenRA.Graphics +{ + public class Animation + { + string name; + public Sequence CurrentSequence { get; private set; } + int frame = 0; + bool backwards = false; + bool tickAlways; + + Func facingFunc; + + public string Name { get { return name; } } + + public Animation( string name ) + : this( name, () => 0 ) + { + } + + public Animation( string name, Func facingFunc ) + { + this.name = name.ToLowerInvariant(); + this.tickFunc = () => { }; + this.facingFunc = facingFunc; + } + + public Sprite Image + { + get + { + return backwards + ? CurrentSequence.GetSprite(CurrentSequence.End - frame - 1, facingFunc()) + : CurrentSequence.GetSprite(frame, facingFunc()); + } + } + + public void Play( string sequenceName ) + { + PlayThen(sequenceName, () => { }); + } + + public void PlayRepeating( string sequenceName ) + { + PlayThen( sequenceName, () => PlayRepeating( CurrentSequence.Name ) ); + } + + public bool ReplaceAnim(string sequenceName) + { + if (!HasSequence(sequenceName)) + return false; + + CurrentSequence = SequenceProvider.GetSequence(name, sequenceName); + frame %= CurrentSequence.Length; + return true; + } + + public void PlayThen( string sequenceName, Action after ) + { + after = after ?? ( () => { } ); + backwards = false; + tickAlways = false; + CurrentSequence = SequenceProvider.GetSequence( name, sequenceName ); + frame = 0; + tickFunc = () => + { + ++frame; + if( frame >= CurrentSequence.Length ) + { + frame = CurrentSequence.Length - 1; + tickFunc = () => { }; + after(); + } + }; + } + + public void PlayBackwardsThen(string sequenceName, Action after) + { + PlayThen(sequenceName, after); + backwards = true; + } + + public void PlayFetchIndex( string sequenceName, Func func ) + { + backwards = false; + tickAlways = true; + CurrentSequence = SequenceProvider.GetSequence( name, sequenceName ); + frame = func(); + tickFunc = () => frame = func(); + } + + int timeUntilNextFrame; + Action tickFunc; + + public void Tick() + { + Tick( 40 ); // tick one frame + } + + public bool HasSequence(string seq) { return SequenceProvider.HasSequence( name, seq ); } + + public void Tick( int t ) + { + if( tickAlways ) + tickFunc(); + else + { + timeUntilNextFrame -= t; + while( timeUntilNextFrame <= 0 ) + { + tickFunc(); + timeUntilNextFrame += CurrentSequence != null ? CurrentSequence.Tick : 40; // 25 fps == 40 ms + } + } + } + + public void ChangeImage(string newImage, string newAnimIfMissing) + { + newImage = newImage.ToLowerInvariant(); + + if (name != newImage) + { + name = newImage.ToLowerInvariant(); + if (!ReplaceAnim(CurrentSequence.Name)) + ReplaceAnim(newAnimIfMissing); + } + } + + public Sequence GetSequence( string sequenceName ) + { + return SequenceProvider.GetSequence( name, sequenceName ); + } + } +} diff --git a/OpenRA.Game/Graphics/ChromeProvider.cs b/OpenRA.Game/Graphics/ChromeProvider.cs index bce9c9eee0..470d9d269e 100644 --- a/OpenRA.Game/Graphics/ChromeProvider.cs +++ b/OpenRA.Game/Graphics/ChromeProvider.cs @@ -1,87 +1,87 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using OpenRA.FileFormats; - -namespace OpenRA.Graphics -{ - public static class ChromeProvider - { - static Dictionary> collections; - static Dictionary cachedSheets; - static Dictionary> cachedSprites; - - public static void Initialize(params string[] chromeFiles) - { - collections = new Dictionary>(); - cachedSheets = new Dictionary(); - cachedSprites = new Dictionary>(); - - foreach (var f in chromeFiles) - LoadChromeSource(f); - } - - static void LoadChromeSource(string filename) - { - XmlDocument document = new XmlDocument(); - document.Load(FileSystem.Open(filename)); - foreach (XmlElement eCollection in document.SelectNodes("/chrome/collection")) - LoadChromeForCollection(eCollection); - } - - static void LoadChromeForCollection(XmlElement eCollection) - { - string elementName = eCollection.GetAttribute("name"); - string defaultSrc = (eCollection.HasAttribute("src") ? eCollection.GetAttribute("src") : null); - - var images = eCollection.SelectNodes("./image").OfType() - .Select(e => new MappedImage(defaultSrc, e)) - .ToDictionary(s => s.Name); - - collections.Add(elementName, images); - } - - public static Sprite GetImage(string collection, string image) - { - // Cached sprite - if (cachedSprites.ContainsKey(collection) && cachedSprites[collection].ContainsKey(image)) - return cachedSprites[collection][image]; - - MappedImage mi; - try { mi = collections[collection][image]; } - catch (KeyNotFoundException) - { - throw new InvalidOperationException( - "Collection `{0}` does not have an image `{1}`".F(collection, image)); - } - - // Cached sheet - Sheet sheet; - if (cachedSheets.ContainsKey(mi.Src)) - sheet = cachedSheets[mi.Src]; - else - { - sheet = new Sheet(mi.Src); - cachedSheets.Add(mi.Src, sheet); - } - - // Cache the sprite - if (!cachedSprites.ContainsKey(collection)) - cachedSprites.Add(collection, new Dictionary()); - cachedSprites[collection].Add(image, mi.GetImage(sheet)); - - return cachedSprites[collection][image]; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using OpenRA.FileFormats; + +namespace OpenRA.Graphics +{ + public static class ChromeProvider + { + static Dictionary> collections; + static Dictionary cachedSheets; + static Dictionary> cachedSprites; + + public static void Initialize(params string[] chromeFiles) + { + collections = new Dictionary>(); + cachedSheets = new Dictionary(); + cachedSprites = new Dictionary>(); + + foreach (var f in chromeFiles) + LoadChromeSource(f); + } + + static void LoadChromeSource(string filename) + { + XmlDocument document = new XmlDocument(); + document.Load(FileSystem.Open(filename)); + foreach (XmlElement eCollection in document.SelectNodes("/chrome/collection")) + LoadChromeForCollection(eCollection); + } + + static void LoadChromeForCollection(XmlElement eCollection) + { + string elementName = eCollection.GetAttribute("name"); + string defaultSrc = (eCollection.HasAttribute("src") ? eCollection.GetAttribute("src") : null); + + var images = eCollection.SelectNodes("./image").OfType() + .Select(e => new MappedImage(defaultSrc, e)) + .ToDictionary(s => s.Name); + + collections.Add(elementName, images); + } + + public static Sprite GetImage(string collection, string image) + { + // Cached sprite + if (cachedSprites.ContainsKey(collection) && cachedSprites[collection].ContainsKey(image)) + return cachedSprites[collection][image]; + + MappedImage mi; + try { mi = collections[collection][image]; } + catch (KeyNotFoundException) + { + throw new InvalidOperationException( + "Collection `{0}` does not have an image `{1}`".F(collection, image)); + } + + // Cached sheet + Sheet sheet; + if (cachedSheets.ContainsKey(mi.Src)) + sheet = cachedSheets[mi.Src]; + else + { + sheet = new Sheet(mi.Src); + cachedSheets.Add(mi.Src, sheet); + } + + // Cache the sprite + if (!cachedSprites.ContainsKey(collection)) + cachedSprites.Add(collection, new Dictionary()); + cachedSprites[collection].Add(image, mi.GetImage(sheet)); + + return cachedSprites[collection][image]; + } + } +} diff --git a/OpenRA.Game/Graphics/CursorProvider.cs b/OpenRA.Game/Graphics/CursorProvider.cs index 7607a58c2f..bab1d93617 100644 --- a/OpenRA.Game/Graphics/CursorProvider.cs +++ b/OpenRA.Game/Graphics/CursorProvider.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Game/Graphics/CursorSequence.cs b/OpenRA.Game/Graphics/CursorSequence.cs index f1d2b34625..d662d528e3 100644 --- a/OpenRA.Game/Graphics/CursorSequence.cs +++ b/OpenRA.Game/Graphics/CursorSequence.cs @@ -1,57 +1,57 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Xml; -using OpenRA.FileFormats; - -namespace OpenRA.Graphics -{ - public class CursorSequence - { - readonly int start, length; - readonly string palette; - - public int Start { get { return start; } } - public int End { get { return start + length; } } - public int Length { get { return length; } } - public string Palette { get { return palette; } } - public readonly int2 Hotspot; - - Sprite[] sprites; - - public CursorSequence(string cursorSrc, string palette, MiniYaml info) - { - sprites = Game.modData.CursorSheetBuilder.LoadAllSprites(cursorSrc); - var d = info.NodesDict; - - start = int.Parse(d["start"].Value); - this.palette = palette; - - if ((d.ContainsKey("length") && d["length"].Value == "*") || (d.ContainsKey("end") && d["end"].Value == "*")) - length = sprites.Length - start; - else if (d.ContainsKey("length")) - length = int.Parse(d["length"].Value); - else if (d.ContainsKey("end")) - length = int.Parse(d["end"].Value) - start; - else - length = 1; - - if (d.ContainsKey("x")) - int.TryParse(d["x"].Value, out Hotspot.X ); - if (d.ContainsKey("y")) - int.TryParse(d["y"].Value, out Hotspot.Y ); - } - - public Sprite GetSprite(int frame) - { - return sprites[(frame % length) + start]; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Xml; +using OpenRA.FileFormats; + +namespace OpenRA.Graphics +{ + public class CursorSequence + { + readonly int start, length; + readonly string palette; + + public int Start { get { return start; } } + public int End { get { return start + length; } } + public int Length { get { return length; } } + public string Palette { get { return palette; } } + public readonly int2 Hotspot; + + Sprite[] sprites; + + public CursorSequence(string cursorSrc, string palette, MiniYaml info) + { + sprites = Game.modData.CursorSheetBuilder.LoadAllSprites(cursorSrc); + var d = info.NodesDict; + + start = int.Parse(d["start"].Value); + this.palette = palette; + + if ((d.ContainsKey("length") && d["length"].Value == "*") || (d.ContainsKey("end") && d["end"].Value == "*")) + length = sprites.Length - start; + else if (d.ContainsKey("length")) + length = int.Parse(d["length"].Value); + else if (d.ContainsKey("end")) + length = int.Parse(d["end"].Value) - start; + else + length = 1; + + if (d.ContainsKey("x")) + int.TryParse(d["x"].Value, out Hotspot.X ); + if (d.ContainsKey("y")) + int.TryParse(d["y"].Value, out Hotspot.Y ); + } + + public Sprite GetSprite(int frame) + { + return sprites[(frame % length) + start]; + } + } +} diff --git a/OpenRA.Game/Graphics/CursorSheetBuilder.cs b/OpenRA.Game/Graphics/CursorSheetBuilder.cs index 688826341f..2219606c30 100644 --- a/OpenRA.Game/Graphics/CursorSheetBuilder.cs +++ b/OpenRA.Game/Graphics/CursorSheetBuilder.cs @@ -1,45 +1,45 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; -using OpenRA.FileFormats; - -namespace OpenRA.Graphics -{ - public class CursorSheetBuilder - { - ModData modData; - Cache cursors; - readonly string[] exts = { ".shp" }; - - public CursorSheetBuilder( ModData modData ) - { - this.modData = modData; - this.cursors = new Cache( LoadCursors ); - } - - Sprite[] LoadCursors(string filename) - { - try - { - var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts)); - return shp.Select(a => modData.SheetBuilder.Add(a.Image, a.Size)).ToArray(); - } - catch (IndexOutOfRangeException) // This will occur when loading a custom (RA-format) .shp - { - var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts)); - return shp.Select(a => modData.SheetBuilder.Add(a.Image, shp.Size)).ToArray(); - } - } - - public Sprite[] LoadAllSprites(string filename) { return cursors[filename]; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.FileFormats; + +namespace OpenRA.Graphics +{ + public class CursorSheetBuilder + { + ModData modData; + Cache cursors; + readonly string[] exts = { ".shp" }; + + public CursorSheetBuilder( ModData modData ) + { + this.modData = modData; + this.cursors = new Cache( LoadCursors ); + } + + Sprite[] LoadCursors(string filename) + { + try + { + var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts)); + return shp.Select(a => modData.SheetBuilder.Add(a.Image, a.Size)).ToArray(); + } + catch (IndexOutOfRangeException) // This will occur when loading a custom (RA-format) .shp + { + var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts)); + return shp.Select(a => modData.SheetBuilder.Add(a.Image, shp.Size)).ToArray(); + } + } + + public Sprite[] LoadAllSprites(string filename) { return cursors[filename]; } + } +} diff --git a/OpenRA.Game/Graphics/HardwarePalette.cs b/OpenRA.Game/Graphics/HardwarePalette.cs index 16322ef51b..7fb5c35617 100644 --- a/OpenRA.Game/Graphics/HardwarePalette.cs +++ b/OpenRA.Game/Graphics/HardwarePalette.cs @@ -1,82 +1,82 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.FileFormats.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Graphics -{ - public class HardwarePalette - { - public const int MaxPalettes = 64; - int allocated = 0; - - ITexture texture; - Dictionary palettes; - Dictionary indices; - - public HardwarePalette() - { - palettes = new Dictionary(); - indices = new Dictionary(); - texture = Game.Renderer.Device.CreateTexture(); - } - - public Palette GetPalette(string name) - { - Palette ret; - if (!palettes.TryGetValue(name,out ret)) - throw new InvalidOperationException("Palette `{0}` does not exist".F(name)); - return ret; - } - - public int GetPaletteIndex(string name) - { - int ret; - if (!indices.TryGetValue(name,out ret)) - throw new InvalidOperationException("Palette `{0}` does not exist".F(name)); - return ret; - } - - public void AddPalette(string name, Palette p) - { - if (palettes.ContainsKey(name)) - throw new InvalidOperationException("Palette {0} has already been defined".F(name)); - - palettes.Add(name, p); - indices.Add(name, allocated++); - } - - public void Update(IEnumerable paletteMods) - { - var copy = palettes.ToDictionary(p => p.Key, p => new Palette(p.Value)); - - foreach (var mod in paletteMods) - mod.AdjustPalette(copy); - - var data = new uint[MaxPalettes,256]; - foreach (var pal in copy) - { - var j = indices[pal.Key]; - var c = pal.Value.Values; - for (var i = 0; i < 256; i++) - data[j,i] = c[i]; - } - - // Doesn't work - texture.SetData(data); - Game.Renderer.PaletteTexture = texture; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.FileFormats.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Graphics +{ + public class HardwarePalette + { + public const int MaxPalettes = 64; + int allocated = 0; + + ITexture texture; + Dictionary palettes; + Dictionary indices; + + public HardwarePalette() + { + palettes = new Dictionary(); + indices = new Dictionary(); + texture = Game.Renderer.Device.CreateTexture(); + } + + public Palette GetPalette(string name) + { + Palette ret; + if (!palettes.TryGetValue(name,out ret)) + throw new InvalidOperationException("Palette `{0}` does not exist".F(name)); + return ret; + } + + public int GetPaletteIndex(string name) + { + int ret; + if (!indices.TryGetValue(name,out ret)) + throw new InvalidOperationException("Palette `{0}` does not exist".F(name)); + return ret; + } + + public void AddPalette(string name, Palette p) + { + if (palettes.ContainsKey(name)) + throw new InvalidOperationException("Palette {0} has already been defined".F(name)); + + palettes.Add(name, p); + indices.Add(name, allocated++); + } + + public void Update(IEnumerable paletteMods) + { + var copy = palettes.ToDictionary(p => p.Key, p => new Palette(p.Value)); + + foreach (var mod in paletteMods) + mod.AdjustPalette(copy); + + var data = new uint[MaxPalettes,256]; + foreach (var pal in copy) + { + var j = indices[pal.Key]; + var c = pal.Value.Values; + for (var i = 0; i < 256; i++) + data[j,i] = c[i]; + } + + // Doesn't work + texture.SetData(data); + Game.Renderer.PaletteTexture = texture; + } + } +} diff --git a/OpenRA.Game/Graphics/LineRenderer.cs b/OpenRA.Game/Graphics/LineRenderer.cs index f03f73cd4e..e461538d23 100644 --- a/OpenRA.Game/Graphics/LineRenderer.cs +++ b/OpenRA.Game/Graphics/LineRenderer.cs @@ -1,77 +1,77 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.FileFormats.Graphics; - -namespace OpenRA.Graphics -{ - public class LineRenderer : Renderer.IBatchRenderer - { - Renderer renderer; - - Vertex[] vertices = new Vertex[ Renderer.TempBufferSize ]; - ushort[] indices = new ushort[ Renderer.TempBufferSize ]; - int nv = 0, ni = 0; - - public LineRenderer( Renderer renderer ) - { - this.renderer = renderer; - } - - public void Flush() - { - if( ni > 0 ) - { - renderer.LineShader.Render( () => - { - var vb = renderer.GetTempVertexBuffer(); - var ib = renderer.GetTempIndexBuffer(); - vb.SetData( vertices, nv ); - ib.SetData( indices, ni ); - renderer.DrawBatch( vb, ib, - nv, ni / 2, PrimitiveType.LineList ); - } ); - - nv = 0; ni = 0; - } - } - - public void DrawLine( float2 start, float2 end, Color startColor, Color endColor ) - { - Renderer.CurrentBatchRenderer = this; - - if( ni + 2 > Renderer.TempBufferSize ) - Flush(); - if( nv + 2 > Renderer.TempBufferSize ) - Flush(); - - indices[ ni++ ] = (ushort)nv; - - vertices[ nv++ ] = new Vertex( start, - new float2( startColor.R / 255.0f, startColor.G / 255.0f ), - new float2( startColor.B / 255.0f, startColor.A / 255.0f ) ); - - indices[ ni++ ] = (ushort)nv; - - vertices[ nv++ ] = new Vertex( end, - new float2( endColor.R / 255.0f, endColor.G / 255.0f ), - new float2( endColor.B / 255.0f, endColor.A / 255.0f ) ); - } - - public void FillRect( RectangleF r, Color color ) - { - for (float y = r.Top; y < r.Bottom; y++) - { - DrawLine(new float2(r.Left, y), new float2(r.Right, y), color, color); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.FileFormats.Graphics; + +namespace OpenRA.Graphics +{ + public class LineRenderer : Renderer.IBatchRenderer + { + Renderer renderer; + + Vertex[] vertices = new Vertex[ Renderer.TempBufferSize ]; + ushort[] indices = new ushort[ Renderer.TempBufferSize ]; + int nv = 0, ni = 0; + + public LineRenderer( Renderer renderer ) + { + this.renderer = renderer; + } + + public void Flush() + { + if( ni > 0 ) + { + renderer.LineShader.Render( () => + { + var vb = renderer.GetTempVertexBuffer(); + var ib = renderer.GetTempIndexBuffer(); + vb.SetData( vertices, nv ); + ib.SetData( indices, ni ); + renderer.DrawBatch( vb, ib, + nv, ni / 2, PrimitiveType.LineList ); + } ); + + nv = 0; ni = 0; + } + } + + public void DrawLine( float2 start, float2 end, Color startColor, Color endColor ) + { + Renderer.CurrentBatchRenderer = this; + + if( ni + 2 > Renderer.TempBufferSize ) + Flush(); + if( nv + 2 > Renderer.TempBufferSize ) + Flush(); + + indices[ ni++ ] = (ushort)nv; + + vertices[ nv++ ] = new Vertex( start, + new float2( startColor.R / 255.0f, startColor.G / 255.0f ), + new float2( startColor.B / 255.0f, startColor.A / 255.0f ) ); + + indices[ ni++ ] = (ushort)nv; + + vertices[ nv++ ] = new Vertex( end, + new float2( endColor.R / 255.0f, endColor.G / 255.0f ), + new float2( endColor.B / 255.0f, endColor.A / 255.0f ) ); + } + + public void FillRect( RectangleF r, Color color ) + { + for (float y = r.Top; y < r.Bottom; y++) + { + DrawLine(new float2(r.Left, y), new float2(r.Right, y), color, color); + } + } + } +} diff --git a/OpenRA.Game/Graphics/MappedImage.cs b/OpenRA.Game/Graphics/MappedImage.cs index 0fa842d3a2..9a4b9e7756 100644 --- a/OpenRA.Game/Graphics/MappedImage.cs +++ b/OpenRA.Game/Graphics/MappedImage.cs @@ -1,41 +1,41 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using System.IO; -using System.Xml; - -namespace OpenRA.Graphics -{ - class MappedImage - { - readonly Rectangle rect; - public readonly string Src; - public readonly string Name; - - public MappedImage(string defaultSrc, XmlElement e) - { - Src = (e.HasAttribute("src")) ? e.GetAttribute("src") : defaultSrc; - Name = e.GetAttribute("name"); - if (Src == null) - throw new InvalidDataException("Image src missing"); - - rect = new Rectangle(int.Parse(e.GetAttribute("x")), - int.Parse(e.GetAttribute("y")), - int.Parse(e.GetAttribute("width")), - int.Parse(e.GetAttribute("height"))); - } - - public Sprite GetImage(Sheet s) - { - return new Sprite(s, rect, TextureChannel.Alpha); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using System.IO; +using System.Xml; + +namespace OpenRA.Graphics +{ + class MappedImage + { + readonly Rectangle rect; + public readonly string Src; + public readonly string Name; + + public MappedImage(string defaultSrc, XmlElement e) + { + Src = (e.HasAttribute("src")) ? e.GetAttribute("src") : defaultSrc; + Name = e.GetAttribute("name"); + if (Src == null) + throw new InvalidDataException("Image src missing"); + + rect = new Rectangle(int.Parse(e.GetAttribute("x")), + int.Parse(e.GetAttribute("y")), + int.Parse(e.GetAttribute("width")), + int.Parse(e.GetAttribute("height"))); + } + + public Sprite GetImage(Sheet s) + { + return new Sprite(s, rect, TextureChannel.Alpha); + } + } +} diff --git a/OpenRA.Game/Graphics/Minimap.cs b/OpenRA.Game/Graphics/Minimap.cs index 08cad4472f..088c2b8c9c 100644 --- a/OpenRA.Game/Graphics/Minimap.cs +++ b/OpenRA.Game/Graphics/Minimap.cs @@ -1,195 +1,195 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using System.Drawing.Imaging; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; -using System.IO; - -namespace OpenRA.Graphics -{ - public class Minimap - { - public static Bitmap TerrainBitmap(Map map) - { - return TerrainBitmap(map, false); - } - - public static Bitmap TerrainBitmap(Map map, bool actualSize) - { - var tileset = Rules.TileSets[map.Tileset]; - var width = map.Bounds.Width; - var height = map.Bounds.Height; - - if (!actualSize) - { - width = height = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); - } - - Bitmap terrain = new Bitmap(width, height); - - var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height), - ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - - unsafe - { - int* c = (int*)bitmapData.Scan0; - - for (var x = 0; x < map.Bounds.Width; x++) - for (var y = 0; y < map.Bounds.Height; y++) - { - var mapX = x + map.Bounds.Left; - var mapY = y + map.Bounds.Top; - var type = tileset.GetTerrainType(map.MapTiles.Value[mapX, mapY]); - if (!tileset.Terrain.ContainsKey(type)) - throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type)); - - *(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[type].Color.ToArgb(); - } - } - terrain.UnlockBits(bitmapData); - return terrain; - } - - // Add the static resources defined in the map; if the map lives - // in a world use AddCustomTerrain instead - public static Bitmap AddStaticResources(Map map, Bitmap terrainBitmap) - { - Bitmap terrain = new Bitmap(terrainBitmap); - var tileset = Rules.TileSets[map.Tileset]; - - var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height), - ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - - unsafe - { - int* c = (int*)bitmapData.Scan0; - - for (var x = 0; x < map.Bounds.Width; x++) - for (var y = 0; y < map.Bounds.Height; y++) - { - var mapX = x + map.Bounds.Left; - var mapY = y + map.Bounds.Top; - if (map.MapResources.Value[mapX, mapY].type == 0) - continue; - - var res = Rules.Info["world"].Traits.WithInterface() - .Where(t => t.ResourceType == map.MapResources.Value[mapX, mapY].type) - .Select(t => t.TerrainType).FirstOrDefault(); - if (res == null) - continue; - - *(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[res].Color.ToArgb(); - } - } - terrain.UnlockBits(bitmapData); - - return terrain; - } - - public static Bitmap CustomTerrainBitmap(World world) - { - var map = world.Map; - var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); - Bitmap bitmap = new Bitmap(size, size); - var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), - ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - - unsafe - { - int* c = (int*)bitmapData.Scan0; - - for (var x = 0; x < map.Bounds.Width; x++) - for (var y = 0; y < map.Bounds.Height; y++) - { - var mapX = x + map.Bounds.Left; - var mapY = y + map.Bounds.Top; - var custom = map.CustomTerrain[mapX,mapY]; - if (custom == null) - continue; - *(c + (y * bitmapData.Stride >> 2) + x) = world.TileSet.Terrain[custom].Color.ToArgb(); - } - } - bitmap.UnlockBits(bitmapData); - return bitmap; - } - - public static Bitmap ActorsBitmap(World world) - { - var map = world.Map; - var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); - Bitmap bitmap = new Bitmap(size, size); - var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), - ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - - unsafe - { - int* c = (int*)bitmapData.Scan0; - - foreach (var t in world.Queries.WithTrait()) - { - if (!world.LocalShroud.IsVisible(t.Actor)) - continue; - - var color = t.Trait.RadarSignatureColor(t.Actor); - foreach (var cell in t.Trait.RadarSignatureCells(t.Actor)) - if (world.Map.IsInMap(cell)) - *(c + ((cell.Y - world.Map.Bounds.Top) * bitmapData.Stride >> 2) + cell.X - world.Map.Bounds.Left) = color.ToArgb(); - } - } - - bitmap.UnlockBits(bitmapData); - return bitmap; - } - - public static Bitmap ShroudBitmap(World world) - { - var map = world.Map; - var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); - Bitmap bitmap = new Bitmap(size, size); - if (world.LocalShroud.Disabled) - return bitmap; - - var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), - ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - - var shroud = Color.Black.ToArgb(); - var fog = Color.FromArgb(128, Color.Black).ToArgb(); - - unsafe - { - int* c = (int*)bitmapData.Scan0; - - for (var x = 0; x < map.Bounds.Width; x++) - for (var y = 0; y < map.Bounds.Height; y++) - { - var mapX = x + map.Bounds.Left; - var mapY = y + map.Bounds.Top; - if (!world.LocalShroud.IsExplored(mapX, mapY)) - *(c + (y * bitmapData.Stride >> 2) + x) = shroud; - else if (!world.LocalShroud.IsVisible(mapX,mapY)) - *(c + (y * bitmapData.Stride >> 2) + x) = fog; - } - } - - bitmap.UnlockBits(bitmapData); - return bitmap; - } - - public static Bitmap RenderMapPreview(Map map) - { - Bitmap terrain = TerrainBitmap(map); - return AddStaticResources(map, terrain); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; +using System.IO; + +namespace OpenRA.Graphics +{ + public class Minimap + { + public static Bitmap TerrainBitmap(Map map) + { + return TerrainBitmap(map, false); + } + + public static Bitmap TerrainBitmap(Map map, bool actualSize) + { + var tileset = Rules.TileSets[map.Tileset]; + var width = map.Bounds.Width; + var height = map.Bounds.Height; + + if (!actualSize) + { + width = height = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); + } + + Bitmap terrain = new Bitmap(width, height); + + var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height), + ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + + unsafe + { + int* c = (int*)bitmapData.Scan0; + + for (var x = 0; x < map.Bounds.Width; x++) + for (var y = 0; y < map.Bounds.Height; y++) + { + var mapX = x + map.Bounds.Left; + var mapY = y + map.Bounds.Top; + var type = tileset.GetTerrainType(map.MapTiles.Value[mapX, mapY]); + if (!tileset.Terrain.ContainsKey(type)) + throw new InvalidDataException("Tileset {0} lacks terraintype {1}".F(tileset.Id, type)); + + *(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[type].Color.ToArgb(); + } + } + terrain.UnlockBits(bitmapData); + return terrain; + } + + // Add the static resources defined in the map; if the map lives + // in a world use AddCustomTerrain instead + public static Bitmap AddStaticResources(Map map, Bitmap terrainBitmap) + { + Bitmap terrain = new Bitmap(terrainBitmap); + var tileset = Rules.TileSets[map.Tileset]; + + var bitmapData = terrain.LockBits(new Rectangle(0, 0, terrain.Width, terrain.Height), + ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + + unsafe + { + int* c = (int*)bitmapData.Scan0; + + for (var x = 0; x < map.Bounds.Width; x++) + for (var y = 0; y < map.Bounds.Height; y++) + { + var mapX = x + map.Bounds.Left; + var mapY = y + map.Bounds.Top; + if (map.MapResources.Value[mapX, mapY].type == 0) + continue; + + var res = Rules.Info["world"].Traits.WithInterface() + .Where(t => t.ResourceType == map.MapResources.Value[mapX, mapY].type) + .Select(t => t.TerrainType).FirstOrDefault(); + if (res == null) + continue; + + *(c + (y * bitmapData.Stride >> 2) + x) = tileset.Terrain[res].Color.ToArgb(); + } + } + terrain.UnlockBits(bitmapData); + + return terrain; + } + + public static Bitmap CustomTerrainBitmap(World world) + { + var map = world.Map; + var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); + Bitmap bitmap = new Bitmap(size, size); + var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + + unsafe + { + int* c = (int*)bitmapData.Scan0; + + for (var x = 0; x < map.Bounds.Width; x++) + for (var y = 0; y < map.Bounds.Height; y++) + { + var mapX = x + map.Bounds.Left; + var mapY = y + map.Bounds.Top; + var custom = map.CustomTerrain[mapX,mapY]; + if (custom == null) + continue; + *(c + (y * bitmapData.Stride >> 2) + x) = world.TileSet.Terrain[custom].Color.ToArgb(); + } + } + bitmap.UnlockBits(bitmapData); + return bitmap; + } + + public static Bitmap ActorsBitmap(World world) + { + var map = world.Map; + var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); + Bitmap bitmap = new Bitmap(size, size); + var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + + unsafe + { + int* c = (int*)bitmapData.Scan0; + + foreach (var t in world.Queries.WithTrait()) + { + if (!world.LocalShroud.IsVisible(t.Actor)) + continue; + + var color = t.Trait.RadarSignatureColor(t.Actor); + foreach (var cell in t.Trait.RadarSignatureCells(t.Actor)) + if (world.Map.IsInMap(cell)) + *(c + ((cell.Y - world.Map.Bounds.Top) * bitmapData.Stride >> 2) + cell.X - world.Map.Bounds.Left) = color.ToArgb(); + } + } + + bitmap.UnlockBits(bitmapData); + return bitmap; + } + + public static Bitmap ShroudBitmap(World world) + { + var map = world.Map; + var size = Util.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); + Bitmap bitmap = new Bitmap(size, size); + if (world.LocalShroud.Disabled) + return bitmap; + + var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + + var shroud = Color.Black.ToArgb(); + var fog = Color.FromArgb(128, Color.Black).ToArgb(); + + unsafe + { + int* c = (int*)bitmapData.Scan0; + + for (var x = 0; x < map.Bounds.Width; x++) + for (var y = 0; y < map.Bounds.Height; y++) + { + var mapX = x + map.Bounds.Left; + var mapY = y + map.Bounds.Top; + if (!world.LocalShroud.IsExplored(mapX, mapY)) + *(c + (y * bitmapData.Stride >> 2) + x) = shroud; + else if (!world.LocalShroud.IsVisible(mapX,mapY)) + *(c + (y * bitmapData.Stride >> 2) + x) = fog; + } + } + + bitmap.UnlockBits(bitmapData); + return bitmap; + } + + public static Bitmap RenderMapPreview(Map map) + { + Bitmap terrain = TerrainBitmap(map); + return AddStaticResources(map, terrain); + } + } +} diff --git a/OpenRA.Game/Graphics/Renderer.cs b/OpenRA.Game/Graphics/Renderer.cs index 2e5132d908..6c286f60ce 100644 --- a/OpenRA.Game/Graphics/Renderer.cs +++ b/OpenRA.Game/Graphics/Renderer.cs @@ -1,208 +1,208 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Reflection; -using System.Windows.Forms; -using OpenRA.FileFormats.Graphics; -using OpenRA.Support; - -namespace OpenRA.Graphics -{ - public class Renderer - { - internal static int SheetSize; - - internal IShader SpriteShader { get; private set; } /* note: shared shader params */ - internal IShader LineShader { get; private set; } - internal IShader RgbaSpriteShader { get; private set; } - internal IShader WorldSpriteShader { get; private set; } - - public SpriteRenderer SpriteRenderer { get; private set; } - public SpriteRenderer RgbaSpriteRenderer { get; private set; } - public SpriteRenderer WorldSpriteRenderer { get; private set; } - public LineRenderer LineRenderer { get; private set; } - - public ITexture PaletteTexture; - - public readonly SpriteFont RegularFont, BoldFont, TitleFont, TinyFont; - - internal const int TempBufferSize = 8192; - const int TempBufferCount = 8; - - Queue> tempBuffersV = new Queue>(); - Queue tempBuffersI = new Queue(); - - public Renderer() - { - SpriteShader = device.CreateShader("world-shp"); - LineShader = device.CreateShader("world-line"); - RgbaSpriteShader = device.CreateShader("chrome-rgba"); - WorldSpriteShader = device.CreateShader("chrome-shp"); - - SpriteRenderer = new SpriteRenderer( this, SpriteShader ); - RgbaSpriteRenderer = new SpriteRenderer( this, RgbaSpriteShader ); - WorldSpriteRenderer = new SpriteRenderer( this, WorldSpriteShader ); - LineRenderer = new LineRenderer(this); - - RegularFont = new SpriteFont("FreeSans.ttf", 14); - BoldFont = new SpriteFont("FreeSansBold.ttf", 14); - TitleFont = new SpriteFont("titles.ttf", 48); - TinyFont = new SpriteFont("FreeSans.ttf", 10); - - for( int i = 0 ; i < TempBufferCount ; i++ ) - { - tempBuffersV.Enqueue( device.CreateVertexBuffer( TempBufferSize ) ); - tempBuffersI.Enqueue( device.CreateIndexBuffer( TempBufferSize ) ); - } - } - - internal IGraphicsDevice Device { get { return device; } } - - public void BeginFrame(float2 scroll) - { - device.Clear(Color.Black); - - float2 r1 = new float2(2f/Resolution.Width, -2f/Resolution.Height); - float2 r2 = new float2(-1, 1); - - SetShaderParams( SpriteShader, r1, r2, scroll ); - SetShaderParams( LineShader, r1, r2, scroll ); - SetShaderParams( RgbaSpriteShader, r1, r2, scroll ); - SetShaderParams( WorldSpriteShader, r1, r2, scroll ); - } - - private void SetShaderParams( IShader s, float2 r1, float2 r2, float2 scroll ) - { - s.SetValue( "Palette", PaletteTexture ); - s.SetValue( "Scroll", (int) scroll.X, (int) scroll.Y ); - s.SetValue( "r1", r1.X, r1.Y ); - s.SetValue( "r2", r2.X, r2.Y ); - s.Commit(); - } - - public void EndFrame( IInputHandler inputHandler ) - { - Flush(); - device.Present( inputHandler ); - } - - public void DrawBatch(IVertexBuffer vertices, IIndexBuffer indices, - Range vertexRange, Range indexRange, PrimitiveType type, IShader shader) - where T : struct - { - vertices.Bind(); - indices.Bind(); - - device.DrawIndexedPrimitives(type, vertexRange, indexRange); - - PerfHistory.Increment("batches", 1); - } - - public void DrawBatch(IVertexBuffer vertices, IIndexBuffer indices, - int vertexPool, int numPrimitives, PrimitiveType type) - where T : struct - { - vertices.Bind(); - indices.Bind(); - - device.DrawIndexedPrimitives(type, vertexPool, numPrimitives); - - PerfHistory.Increment("batches", 1); - } - - public void Flush() - { - CurrentBatchRenderer = null; - } - - static IGraphicsDevice device; - - public static Size Resolution { get { return device.WindowSize; } } - - internal static void Initialize( OpenRA.FileFormats.Graphics.WindowMode windowMode ) - { - var resolution = GetResolution( windowMode ); - device = CreateDevice( Assembly.LoadFile( Path.GetFullPath( "OpenRA.Renderer.{0}.dll".F(Game.Settings.Graphics.Renderer) ) ), resolution.Width, resolution.Height, windowMode, false ); - } - - static Size GetResolution(WindowMode windowmode) - { - var desktopResolution = Screen.PrimaryScreen.Bounds.Size; - var customSize = (windowmode == WindowMode.Windowed) ? Game.Settings.Graphics.WindowedSize : Game.Settings.Graphics.FullscreenSize; - - if (customSize.X > 0 && customSize.Y > 0) - { - desktopResolution.Width = customSize.X; - desktopResolution.Height = customSize.Y; - } - return new Size( - desktopResolution.Width, - desktopResolution.Height); - } - - static IGraphicsDevice CreateDevice( Assembly rendererDll, int width, int height, WindowMode window, bool vsync ) - { - foreach( RendererAttribute r in rendererDll.GetCustomAttributes( typeof( RendererAttribute ), false ) ) - { - return (IGraphicsDevice)r.Type.GetConstructor( new Type[] { typeof( int ), typeof( int ), typeof( WindowMode ), typeof( bool ) } ) - .Invoke( new object[] { width, height, window, vsync } ); - } - throw new NotImplementedException(); - } - - internal IVertexBuffer GetTempVertexBuffer() - { - var ret = tempBuffersV.Dequeue(); - tempBuffersV.Enqueue( ret ); - return ret; - } - - internal IIndexBuffer GetTempIndexBuffer() - { - var ret = tempBuffersI.Dequeue(); - tempBuffersI.Enqueue( ret ); - return ret; - } - - public interface IBatchRenderer - { - void Flush(); - } - - static IBatchRenderer currentBatchRenderer; - public static IBatchRenderer CurrentBatchRenderer - { - get { return currentBatchRenderer; } - set - { - if( currentBatchRenderer == value ) return; - if( currentBatchRenderer != null ) - currentBatchRenderer.Flush(); - currentBatchRenderer = value; - } - } - - public void EnableScissor(int left, int top, int width, int height) - { - Flush(); - Device.EnableScissor( left, top, width, height ); - } - - public void DisableScissor() - { - Flush(); - Device.DisableScissor(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Reflection; +using System.Windows.Forms; +using OpenRA.FileFormats.Graphics; +using OpenRA.Support; + +namespace OpenRA.Graphics +{ + public class Renderer + { + internal static int SheetSize; + + internal IShader SpriteShader { get; private set; } /* note: shared shader params */ + internal IShader LineShader { get; private set; } + internal IShader RgbaSpriteShader { get; private set; } + internal IShader WorldSpriteShader { get; private set; } + + public SpriteRenderer SpriteRenderer { get; private set; } + public SpriteRenderer RgbaSpriteRenderer { get; private set; } + public SpriteRenderer WorldSpriteRenderer { get; private set; } + public LineRenderer LineRenderer { get; private set; } + + public ITexture PaletteTexture; + + public readonly SpriteFont RegularFont, BoldFont, TitleFont, TinyFont; + + internal const int TempBufferSize = 8192; + const int TempBufferCount = 8; + + Queue> tempBuffersV = new Queue>(); + Queue tempBuffersI = new Queue(); + + public Renderer() + { + SpriteShader = device.CreateShader("world-shp"); + LineShader = device.CreateShader("world-line"); + RgbaSpriteShader = device.CreateShader("chrome-rgba"); + WorldSpriteShader = device.CreateShader("chrome-shp"); + + SpriteRenderer = new SpriteRenderer( this, SpriteShader ); + RgbaSpriteRenderer = new SpriteRenderer( this, RgbaSpriteShader ); + WorldSpriteRenderer = new SpriteRenderer( this, WorldSpriteShader ); + LineRenderer = new LineRenderer(this); + + RegularFont = new SpriteFont("FreeSans.ttf", 14); + BoldFont = new SpriteFont("FreeSansBold.ttf", 14); + TitleFont = new SpriteFont("titles.ttf", 48); + TinyFont = new SpriteFont("FreeSans.ttf", 10); + + for( int i = 0 ; i < TempBufferCount ; i++ ) + { + tempBuffersV.Enqueue( device.CreateVertexBuffer( TempBufferSize ) ); + tempBuffersI.Enqueue( device.CreateIndexBuffer( TempBufferSize ) ); + } + } + + internal IGraphicsDevice Device { get { return device; } } + + public void BeginFrame(float2 scroll) + { + device.Clear(Color.Black); + + float2 r1 = new float2(2f/Resolution.Width, -2f/Resolution.Height); + float2 r2 = new float2(-1, 1); + + SetShaderParams( SpriteShader, r1, r2, scroll ); + SetShaderParams( LineShader, r1, r2, scroll ); + SetShaderParams( RgbaSpriteShader, r1, r2, scroll ); + SetShaderParams( WorldSpriteShader, r1, r2, scroll ); + } + + private void SetShaderParams( IShader s, float2 r1, float2 r2, float2 scroll ) + { + s.SetValue( "Palette", PaletteTexture ); + s.SetValue( "Scroll", (int) scroll.X, (int) scroll.Y ); + s.SetValue( "r1", r1.X, r1.Y ); + s.SetValue( "r2", r2.X, r2.Y ); + s.Commit(); + } + + public void EndFrame( IInputHandler inputHandler ) + { + Flush(); + device.Present( inputHandler ); + } + + public void DrawBatch(IVertexBuffer vertices, IIndexBuffer indices, + Range vertexRange, Range indexRange, PrimitiveType type, IShader shader) + where T : struct + { + vertices.Bind(); + indices.Bind(); + + device.DrawIndexedPrimitives(type, vertexRange, indexRange); + + PerfHistory.Increment("batches", 1); + } + + public void DrawBatch(IVertexBuffer vertices, IIndexBuffer indices, + int vertexPool, int numPrimitives, PrimitiveType type) + where T : struct + { + vertices.Bind(); + indices.Bind(); + + device.DrawIndexedPrimitives(type, vertexPool, numPrimitives); + + PerfHistory.Increment("batches", 1); + } + + public void Flush() + { + CurrentBatchRenderer = null; + } + + static IGraphicsDevice device; + + public static Size Resolution { get { return device.WindowSize; } } + + internal static void Initialize( OpenRA.FileFormats.Graphics.WindowMode windowMode ) + { + var resolution = GetResolution( windowMode ); + device = CreateDevice( Assembly.LoadFile( Path.GetFullPath( "OpenRA.Renderer.{0}.dll".F(Game.Settings.Graphics.Renderer) ) ), resolution.Width, resolution.Height, windowMode, false ); + } + + static Size GetResolution(WindowMode windowmode) + { + var desktopResolution = Screen.PrimaryScreen.Bounds.Size; + var customSize = (windowmode == WindowMode.Windowed) ? Game.Settings.Graphics.WindowedSize : Game.Settings.Graphics.FullscreenSize; + + if (customSize.X > 0 && customSize.Y > 0) + { + desktopResolution.Width = customSize.X; + desktopResolution.Height = customSize.Y; + } + return new Size( + desktopResolution.Width, + desktopResolution.Height); + } + + static IGraphicsDevice CreateDevice( Assembly rendererDll, int width, int height, WindowMode window, bool vsync ) + { + foreach( RendererAttribute r in rendererDll.GetCustomAttributes( typeof( RendererAttribute ), false ) ) + { + return (IGraphicsDevice)r.Type.GetConstructor( new Type[] { typeof( int ), typeof( int ), typeof( WindowMode ), typeof( bool ) } ) + .Invoke( new object[] { width, height, window, vsync } ); + } + throw new NotImplementedException(); + } + + internal IVertexBuffer GetTempVertexBuffer() + { + var ret = tempBuffersV.Dequeue(); + tempBuffersV.Enqueue( ret ); + return ret; + } + + internal IIndexBuffer GetTempIndexBuffer() + { + var ret = tempBuffersI.Dequeue(); + tempBuffersI.Enqueue( ret ); + return ret; + } + + public interface IBatchRenderer + { + void Flush(); + } + + static IBatchRenderer currentBatchRenderer; + public static IBatchRenderer CurrentBatchRenderer + { + get { return currentBatchRenderer; } + set + { + if( currentBatchRenderer == value ) return; + if( currentBatchRenderer != null ) + currentBatchRenderer.Flush(); + currentBatchRenderer = value; + } + } + + public void EnableScissor(int left, int top, int width, int height) + { + Flush(); + Device.EnableScissor( left, top, width, height ); + } + + public void DisableScissor() + { + Flush(); + Device.DisableScissor(); + } + } +} diff --git a/OpenRA.Game/Graphics/Sequence.cs b/OpenRA.Game/Graphics/Sequence.cs index 5b8b43b384..0338856f22 100644 --- a/OpenRA.Game/Graphics/Sequence.cs +++ b/OpenRA.Game/Graphics/Sequence.cs @@ -1,89 +1,89 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Xml; -using OpenRA.FileFormats; -using System.Collections.Generic; - -namespace OpenRA.Graphics -{ - public class Sequence - { - readonly Sprite[] sprites; - readonly int start, length, facings, tick; - - public readonly string Name; - public int Start { get { return start; } } - public int End { get { return start + length; } } - public int Length { get { return length; } } - public int Facings { get { return facings; } } - public int Tick { get { return tick; } } - - string srcOverride; - public Sequence(string unit, string name, MiniYaml info) - { - srcOverride = info.Value; - Name = name; - var d = info.NodesDict; - - sprites = Game.modData.SpriteLoader.LoadAllSprites(string.IsNullOrEmpty(srcOverride) ? unit : srcOverride ); - start = int.Parse(d["Start"].Value); - - if (!d.ContainsKey("Length")) - length = 1; - else if (d["Length"].Value == "*") - length = sprites.Length - Start; - else - length = int.Parse(d["Length"].Value); - - - if(d.ContainsKey("Facings")) - facings = int.Parse(d["Facings"].Value); - else - facings = 1; - - if(d.ContainsKey("Tick")) - tick = int.Parse(d["Tick"].Value); - else - tick = 40; - } - - public MiniYaml Save() - { - var root = new List(); - - root.Add(new MiniYamlNode("Start", start.ToString())); - - if (length > 1 && (start != 0 || length != sprites.Length - start)) - root.Add(new MiniYamlNode("Length", length.ToString())); - else if (length > 1 && length == sprites.Length - start) - root.Add(new MiniYamlNode("Length", "*")); - - if (facings > 1) - root.Add(new MiniYamlNode("Facings", facings.ToString())); - - if (tick != 40) - root.Add(new MiniYamlNode("Tick", tick.ToString())); - - return new MiniYaml(srcOverride, root); - } - - public Sprite GetSprite( int frame ) - { - return GetSprite( frame, 0 ); - } - - public Sprite GetSprite(int frame, int facing) - { - var f = Traits.Util.QuantizeFacing( facing, facings ); - return sprites[ (f * length) + ( frame % length ) + start ]; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Xml; +using OpenRA.FileFormats; +using System.Collections.Generic; + +namespace OpenRA.Graphics +{ + public class Sequence + { + readonly Sprite[] sprites; + readonly int start, length, facings, tick; + + public readonly string Name; + public int Start { get { return start; } } + public int End { get { return start + length; } } + public int Length { get { return length; } } + public int Facings { get { return facings; } } + public int Tick { get { return tick; } } + + string srcOverride; + public Sequence(string unit, string name, MiniYaml info) + { + srcOverride = info.Value; + Name = name; + var d = info.NodesDict; + + sprites = Game.modData.SpriteLoader.LoadAllSprites(string.IsNullOrEmpty(srcOverride) ? unit : srcOverride ); + start = int.Parse(d["Start"].Value); + + if (!d.ContainsKey("Length")) + length = 1; + else if (d["Length"].Value == "*") + length = sprites.Length - Start; + else + length = int.Parse(d["Length"].Value); + + + if(d.ContainsKey("Facings")) + facings = int.Parse(d["Facings"].Value); + else + facings = 1; + + if(d.ContainsKey("Tick")) + tick = int.Parse(d["Tick"].Value); + else + tick = 40; + } + + public MiniYaml Save() + { + var root = new List(); + + root.Add(new MiniYamlNode("Start", start.ToString())); + + if (length > 1 && (start != 0 || length != sprites.Length - start)) + root.Add(new MiniYamlNode("Length", length.ToString())); + else if (length > 1 && length == sprites.Length - start) + root.Add(new MiniYamlNode("Length", "*")); + + if (facings > 1) + root.Add(new MiniYamlNode("Facings", facings.ToString())); + + if (tick != 40) + root.Add(new MiniYamlNode("Tick", tick.ToString())); + + return new MiniYaml(srcOverride, root); + } + + public Sprite GetSprite( int frame ) + { + return GetSprite( frame, 0 ); + } + + public Sprite GetSprite(int frame, int facing) + { + var f = Traits.Util.QuantizeFacing( facing, facings ); + return sprites[ (f * length) + ( frame % length ) + start ]; + } + } +} diff --git a/OpenRA.Game/Graphics/SequenceProvider.cs b/OpenRA.Game/Graphics/SequenceProvider.cs index ccaa154135..679fcacc1f 100644 --- a/OpenRA.Game/Graphics/SequenceProvider.cs +++ b/OpenRA.Game/Graphics/SequenceProvider.cs @@ -1,72 +1,72 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using OpenRA.FileFormats; - -namespace OpenRA.Graphics -{ - public static class SequenceProvider - { - static Dictionary> units; - - public static void Initialize(string[] sequenceFiles, List sequenceNodes) - { - units = new Dictionary>(); - if (sequenceFiles.Length == 0) - return; - - var sequences = sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(sequenceNodes, MiniYaml.Merge); - - foreach (var s in sequences) - LoadSequencesForUnit(s.Key, s.Value); - } - - static void LoadSequencesForUnit(string unit, MiniYaml sequences) - { - Game.modData.LoadScreen.Display(); - try { - var seq = sequences.NodesDict.ToDictionary(x => x.Key, x => new Sequence(unit,x.Key,x.Value)); - units.Add(unit, seq); - } catch (FileNotFoundException) {} // Do nothing; we can crash later if we actually wanted art - } - - public static MiniYaml SaveSequencesForUnit(string unitname) - { - var ret = new List(); - foreach (var s in units[unitname]) - ret.Add(new MiniYamlNode(s.Key, s.Value.Save())); - - return new MiniYaml(null, ret); - } - - public static Sequence GetSequence(string unitName, string sequenceName) - { - try { return units[unitName][sequenceName]; } - catch (KeyNotFoundException) - { - if (units.ContainsKey(unitName)) - throw new InvalidOperationException( - "Unit `{0}` does not have a sequence `{1}`".F(unitName, sequenceName)); - else - throw new InvalidOperationException( - "Unit `{0}` does not have any sequences defined.".F(unitName)); - } - } - - public static bool HasSequence(string unit, string seq) - { - return units[unit].ContainsKey(seq); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using OpenRA.FileFormats; + +namespace OpenRA.Graphics +{ + public static class SequenceProvider + { + static Dictionary> units; + + public static void Initialize(string[] sequenceFiles, List sequenceNodes) + { + units = new Dictionary>(); + if (sequenceFiles.Length == 0) + return; + + var sequences = sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(sequenceNodes, MiniYaml.Merge); + + foreach (var s in sequences) + LoadSequencesForUnit(s.Key, s.Value); + } + + static void LoadSequencesForUnit(string unit, MiniYaml sequences) + { + Game.modData.LoadScreen.Display(); + try { + var seq = sequences.NodesDict.ToDictionary(x => x.Key, x => new Sequence(unit,x.Key,x.Value)); + units.Add(unit, seq); + } catch (FileNotFoundException) {} // Do nothing; we can crash later if we actually wanted art + } + + public static MiniYaml SaveSequencesForUnit(string unitname) + { + var ret = new List(); + foreach (var s in units[unitname]) + ret.Add(new MiniYamlNode(s.Key, s.Value.Save())); + + return new MiniYaml(null, ret); + } + + public static Sequence GetSequence(string unitName, string sequenceName) + { + try { return units[unitName][sequenceName]; } + catch (KeyNotFoundException) + { + if (units.ContainsKey(unitName)) + throw new InvalidOperationException( + "Unit `{0}` does not have a sequence `{1}`".F(unitName, sequenceName)); + else + throw new InvalidOperationException( + "Unit `{0}` does not have any sequences defined.".F(unitName)); + } + } + + public static bool HasSequence(string unit, string seq) + { + return units[unit].ContainsKey(seq); + } + } +} diff --git a/OpenRA.Game/Graphics/Sheet.cs b/OpenRA.Game/Graphics/Sheet.cs index d2ecc2418b..0b725f1c88 100644 --- a/OpenRA.Game/Graphics/Sheet.cs +++ b/OpenRA.Game/Graphics/Sheet.cs @@ -1,67 +1,67 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.FileFormats; -using OpenRA.FileFormats.Graphics; - -namespace OpenRA.Graphics -{ - public class Sheet - { - Bitmap bitmap; - ITexture texture; - bool dirty; - byte[] data; - public readonly Size Size; - - public Sheet(Size size) - { - Size = size; - } - - public Sheet(string filename) - { - bitmap = (Bitmap)Image.FromStream(FileSystem.Open(filename)); - Size = bitmap.Size; - } - - public ITexture Texture - { - get - { - if (texture == null) - { - texture = Game.Renderer.Device.CreateTexture(); - dirty = true; - } - - if (dirty) - { - if (data != null) - { - texture.SetData(data, Size.Width, Size.Height); - dirty = false; - } - else if (bitmap != null) - { - texture.SetData(bitmap); - dirty = false; - } - } - - return texture; - } - } - - public byte[] Data { get { if (data == null) data = new byte[4 * Size.Width * Size.Height]; return data; } } - public void MakeDirty() { dirty = true; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.FileFormats; +using OpenRA.FileFormats.Graphics; + +namespace OpenRA.Graphics +{ + public class Sheet + { + Bitmap bitmap; + ITexture texture; + bool dirty; + byte[] data; + public readonly Size Size; + + public Sheet(Size size) + { + Size = size; + } + + public Sheet(string filename) + { + bitmap = (Bitmap)Image.FromStream(FileSystem.Open(filename)); + Size = bitmap.Size; + } + + public ITexture Texture + { + get + { + if (texture == null) + { + texture = Game.Renderer.Device.CreateTexture(); + dirty = true; + } + + if (dirty) + { + if (data != null) + { + texture.SetData(data, Size.Width, Size.Height); + dirty = false; + } + else if (bitmap != null) + { + texture.SetData(bitmap); + dirty = false; + } + } + + return texture; + } + } + + public byte[] Data { get { if (data == null) data = new byte[4 * Size.Width * Size.Height]; return data; } } + public void MakeDirty() { dirty = true; } + } +} diff --git a/OpenRA.Game/Graphics/SheetBuilder.cs b/OpenRA.Game/Graphics/SheetBuilder.cs index a5bb3053a7..99f6d22ee2 100644 --- a/OpenRA.Game/Graphics/SheetBuilder.cs +++ b/OpenRA.Game/Graphics/SheetBuilder.cs @@ -1,102 +1,102 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; - -namespace OpenRA.Graphics -{ - public class SheetBuilder - { - internal SheetBuilder(TextureChannel ch) - { - current = null; - rowHeight = 0; - channel = null; - initialChannel = ch; - } - - public Sprite Add(byte[] src, Size size) - { - Sprite rect = Allocate(size); - Util.FastCopyIntoChannel(rect, src); - return rect; - } - - public Sprite Add(Size size, byte paletteIndex) - { - byte[] data = new byte[size.Width * size.Height]; - for (int i = 0; i < data.Length; i++) - data[i] = paletteIndex; - - return Add(data, size); - } - - Sheet NewSheet() { return new Sheet(new Size( Renderer.SheetSize, Renderer.SheetSize ) ); } - - Sheet current = null; - int rowHeight = 0; - Point p; - TextureChannel? channel = null; - TextureChannel initialChannel; - - TextureChannel? NextChannel(TextureChannel? t) - { - if (t == null) - return initialChannel; - - switch (t.Value) - { - case TextureChannel.Red: return TextureChannel.Green; - case TextureChannel.Green: return TextureChannel.Blue; - case TextureChannel.Blue: return TextureChannel.Alpha; - case TextureChannel.Alpha: return null; - - default: return null; - } - } - - public Sprite Allocate(Size imageSize) - { - if (current == null) - { - current = NewSheet(); - channel = NextChannel(null); - } - - if (imageSize.Width + p.X > current.Size.Width) - { - p = new Point(0, p.Y + rowHeight); - rowHeight = imageSize.Height; - } - - if (imageSize.Height > rowHeight) - rowHeight = imageSize.Height; - - if (p.Y + imageSize.Height > current.Size.Height) - { - - if (null == (channel = NextChannel(channel))) - { - current = NewSheet(); - channel = NextChannel(channel); - } - - rowHeight = imageSize.Height; - p = new Point(0,0); - } - - Sprite rect = new Sprite(current, new Rectangle(p, imageSize), channel.Value); - current.MakeDirty(); - p.X += imageSize.Width; - - return rect; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; + +namespace OpenRA.Graphics +{ + public class SheetBuilder + { + internal SheetBuilder(TextureChannel ch) + { + current = null; + rowHeight = 0; + channel = null; + initialChannel = ch; + } + + public Sprite Add(byte[] src, Size size) + { + Sprite rect = Allocate(size); + Util.FastCopyIntoChannel(rect, src); + return rect; + } + + public Sprite Add(Size size, byte paletteIndex) + { + byte[] data = new byte[size.Width * size.Height]; + for (int i = 0; i < data.Length; i++) + data[i] = paletteIndex; + + return Add(data, size); + } + + Sheet NewSheet() { return new Sheet(new Size( Renderer.SheetSize, Renderer.SheetSize ) ); } + + Sheet current = null; + int rowHeight = 0; + Point p; + TextureChannel? channel = null; + TextureChannel initialChannel; + + TextureChannel? NextChannel(TextureChannel? t) + { + if (t == null) + return initialChannel; + + switch (t.Value) + { + case TextureChannel.Red: return TextureChannel.Green; + case TextureChannel.Green: return TextureChannel.Blue; + case TextureChannel.Blue: return TextureChannel.Alpha; + case TextureChannel.Alpha: return null; + + default: return null; + } + } + + public Sprite Allocate(Size imageSize) + { + if (current == null) + { + current = NewSheet(); + channel = NextChannel(null); + } + + if (imageSize.Width + p.X > current.Size.Width) + { + p = new Point(0, p.Y + rowHeight); + rowHeight = imageSize.Height; + } + + if (imageSize.Height > rowHeight) + rowHeight = imageSize.Height; + + if (p.Y + imageSize.Height > current.Size.Height) + { + + if (null == (channel = NextChannel(channel))) + { + current = NewSheet(); + channel = NextChannel(channel); + } + + rowHeight = imageSize.Height; + p = new Point(0,0); + } + + Sprite rect = new Sprite(current, new Rectangle(p, imageSize), channel.Value); + current.MakeDirty(); + p.X += imageSize.Width; + + return rect; + } + } +} diff --git a/OpenRA.Game/Graphics/ShroudRenderer.cs b/OpenRA.Game/Graphics/ShroudRenderer.cs index 4599c022f9..6fb5eb469c 100644 --- a/OpenRA.Game/Graphics/ShroudRenderer.cs +++ b/OpenRA.Game/Graphics/ShroudRenderer.cs @@ -1,161 +1,161 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.Traits; - -namespace OpenRA.Graphics -{ - public class ShroudRenderer - { - Traits.Shroud shroud; - Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow"); - Sprite[,] sprites, fogSprites; - - bool dirty = true; - Map map; - - public ShroudRenderer(World world) - { - this.shroud = world.LocalShroud; - this.map = world.Map; - - sprites = new Sprite[map.MapSize.X, map.MapSize.Y]; - fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y]; - shroud.Dirty += () => dirty = true; - } - - static readonly byte[][] SpecialShroudTiles = - { - new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 }, - new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 }, - new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 }, - new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 }, - new byte[] { 44 }, - new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 }, - new byte[] { 40 }, - new byte[] { 35, 24, 17, 18 }, - new byte[] { 39, 39, 29, 29 }, - new byte[] { 45 }, - new byte[] { 43 }, - new byte[] { 38, 28 }, - new byte[] { 42 }, - new byte[] { 41 }, - new byte[] { 46 }, - }; - - Sprite ChooseShroud(int i, int j) - { - if( !shroud.IsExplored( i, j ) ) return shadowBits[ 0xf ]; - - // bits are for unexploredness: up, right, down, left - var v = 0; - // bits are for unexploredness: TL, TR, BR, BL - var u = 0; - - if( !shroud.IsExplored( i, j - 1 ) ) { v |= 1; u |= 3; } - if( !shroud.IsExplored( i + 1, j ) ) { v |= 2; u |= 6; } - if( !shroud.IsExplored( i, j + 1 ) ) { v |= 4; u |= 12; } - if( !shroud.IsExplored( i - 1, j ) ) { v |= 8; u |= 9; } - - var uSides = u; - - if( !shroud.IsExplored( i - 1, j - 1 ) ) u |= 1; - if( !shroud.IsExplored( i + 1, j - 1 ) ) u |= 2; - if( !shroud.IsExplored( i + 1, j + 1 ) ) u |= 4; - if( !shroud.IsExplored( i - 1, j + 1 ) ) u |= 8; - - return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ]; - } - - Sprite ChooseFog(int i, int j) - { - if (!shroud.IsVisible(i,j)) return shadowBits[0xf]; - if (!shroud.IsExplored(i, j)) return shadowBits[0xf]; - - // bits are for unexploredness: up, right, down, left - var v = 0; - // bits are for unexploredness: TL, TR, BR, BL - var u = 0; - - if (!shroud.IsVisible(i, j - 1)) { v |= 1; u |= 3; } - if (!shroud.IsVisible(i + 1, j)) { v |= 2; u |= 6; } - if (!shroud.IsVisible(i, j + 1)) { v |= 4; u |= 12; } - if (!shroud.IsVisible(i - 1, j)) { v |= 8; u |= 9; } - - var uSides = u; - - if (!shroud.IsVisible(i - 1, j - 1)) u |= 1; - if (!shroud.IsVisible(i + 1, j - 1)) u |= 2; - if (!shroud.IsVisible(i + 1, j + 1)) u |= 4; - if (!shroud.IsVisible(i - 1, j + 1)) u |= 8; - - return shadowBits[SpecialShroudTiles[u ^ uSides][v]]; - } - - internal void Draw( WorldRenderer wr ) - { - if (dirty) - { - dirty = false; - for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) - for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - sprites[i, j] = ChooseShroud(i, j); - - for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) - for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - fogSprites[i, j] = ChooseFog(i, j); - } - - var clipRect = Game.viewport.WorldBounds(wr.world); - DrawShroud( wr, clipRect, fogSprites, "fog" ); - DrawShroud( wr, clipRect, sprites, "shroud" ); - } - - void DrawShroud( WorldRenderer wr, Rectangle clip, Sprite[,] s, string pal ) - { - var shroudPalette = wr.GetPaletteIndex(pal); - - for (var j = clip.Top; j < clip.Bottom; j++) - { - var starti = clip.Left; - var last = shadowBits[0x0f]; - for (var i = clip.Left; i < clip.Right; i++) - { - if ((s[i, j] == shadowBits[0x0f] && last == shadowBits[0x0f]) - || (s[i, j] == shadowBits[0] && last == shadowBits[0])) - continue; - - if (starti != i) - { - s[starti, j].DrawAt( - Game.CellSize * new float2(starti, j), - shroudPalette, - new float2(Game.CellSize * (i - starti), Game.CellSize)); - starti = i + 1; - } - - s[i, j].DrawAt( - Game.CellSize * new float2(i, j), - shroudPalette); - starti = i + 1; - last = s[i, j]; - } - - if (starti < clip.Right) - s[starti, j].DrawAt( - Game.CellSize * new float2(starti, j), - shroudPalette, - new float2(Game.CellSize * (clip.Right - starti), Game.CellSize)); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.Traits; + +namespace OpenRA.Graphics +{ + public class ShroudRenderer + { + Traits.Shroud shroud; + Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow"); + Sprite[,] sprites, fogSprites; + + bool dirty = true; + Map map; + + public ShroudRenderer(World world) + { + this.shroud = world.LocalShroud; + this.map = world.Map; + + sprites = new Sprite[map.MapSize.X, map.MapSize.Y]; + fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y]; + shroud.Dirty += () => dirty = true; + } + + static readonly byte[][] SpecialShroudTiles = + { + new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 }, + new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 }, + new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 }, + new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 }, + new byte[] { 44 }, + new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 }, + new byte[] { 40 }, + new byte[] { 35, 24, 17, 18 }, + new byte[] { 39, 39, 29, 29 }, + new byte[] { 45 }, + new byte[] { 43 }, + new byte[] { 38, 28 }, + new byte[] { 42 }, + new byte[] { 41 }, + new byte[] { 46 }, + }; + + Sprite ChooseShroud(int i, int j) + { + if( !shroud.IsExplored( i, j ) ) return shadowBits[ 0xf ]; + + // bits are for unexploredness: up, right, down, left + var v = 0; + // bits are for unexploredness: TL, TR, BR, BL + var u = 0; + + if( !shroud.IsExplored( i, j - 1 ) ) { v |= 1; u |= 3; } + if( !shroud.IsExplored( i + 1, j ) ) { v |= 2; u |= 6; } + if( !shroud.IsExplored( i, j + 1 ) ) { v |= 4; u |= 12; } + if( !shroud.IsExplored( i - 1, j ) ) { v |= 8; u |= 9; } + + var uSides = u; + + if( !shroud.IsExplored( i - 1, j - 1 ) ) u |= 1; + if( !shroud.IsExplored( i + 1, j - 1 ) ) u |= 2; + if( !shroud.IsExplored( i + 1, j + 1 ) ) u |= 4; + if( !shroud.IsExplored( i - 1, j + 1 ) ) u |= 8; + + return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ]; + } + + Sprite ChooseFog(int i, int j) + { + if (!shroud.IsVisible(i,j)) return shadowBits[0xf]; + if (!shroud.IsExplored(i, j)) return shadowBits[0xf]; + + // bits are for unexploredness: up, right, down, left + var v = 0; + // bits are for unexploredness: TL, TR, BR, BL + var u = 0; + + if (!shroud.IsVisible(i, j - 1)) { v |= 1; u |= 3; } + if (!shroud.IsVisible(i + 1, j)) { v |= 2; u |= 6; } + if (!shroud.IsVisible(i, j + 1)) { v |= 4; u |= 12; } + if (!shroud.IsVisible(i - 1, j)) { v |= 8; u |= 9; } + + var uSides = u; + + if (!shroud.IsVisible(i - 1, j - 1)) u |= 1; + if (!shroud.IsVisible(i + 1, j - 1)) u |= 2; + if (!shroud.IsVisible(i + 1, j + 1)) u |= 4; + if (!shroud.IsVisible(i - 1, j + 1)) u |= 8; + + return shadowBits[SpecialShroudTiles[u ^ uSides][v]]; + } + + internal void Draw( WorldRenderer wr ) + { + if (dirty) + { + dirty = false; + for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) + for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) + sprites[i, j] = ChooseShroud(i, j); + + for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) + for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) + fogSprites[i, j] = ChooseFog(i, j); + } + + var clipRect = Game.viewport.WorldBounds(wr.world); + DrawShroud( wr, clipRect, fogSprites, "fog" ); + DrawShroud( wr, clipRect, sprites, "shroud" ); + } + + void DrawShroud( WorldRenderer wr, Rectangle clip, Sprite[,] s, string pal ) + { + var shroudPalette = wr.GetPaletteIndex(pal); + + for (var j = clip.Top; j < clip.Bottom; j++) + { + var starti = clip.Left; + var last = shadowBits[0x0f]; + for (var i = clip.Left; i < clip.Right; i++) + { + if ((s[i, j] == shadowBits[0x0f] && last == shadowBits[0x0f]) + || (s[i, j] == shadowBits[0] && last == shadowBits[0])) + continue; + + if (starti != i) + { + s[starti, j].DrawAt( + Game.CellSize * new float2(starti, j), + shroudPalette, + new float2(Game.CellSize * (i - starti), Game.CellSize)); + starti = i + 1; + } + + s[i, j].DrawAt( + Game.CellSize * new float2(i, j), + shroudPalette); + starti = i + 1; + last = s[i, j]; + } + + if (starti < clip.Right) + s[starti, j].DrawAt( + Game.CellSize * new float2(starti, j), + shroudPalette, + new float2(Game.CellSize * (clip.Right - starti), Game.CellSize)); + } + } + } +} diff --git a/OpenRA.Game/Graphics/Sprite.cs b/OpenRA.Game/Graphics/Sprite.cs index af568d3959..a10e960b0c 100644 --- a/OpenRA.Game/Graphics/Sprite.cs +++ b/OpenRA.Game/Graphics/Sprite.cs @@ -1,81 +1,81 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; - -namespace OpenRA.Graphics -{ - public class Sprite - { - public readonly Rectangle bounds; - public readonly Sheet sheet; - public readonly TextureChannel channel; - public readonly RectangleF uv; - public readonly float2 size; - - readonly float2[] uvhax; - - public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel) - { - this.bounds = bounds; - this.sheet = sheet; - this.channel = channel; - - uv = new RectangleF( - (float)(bounds.Left) / sheet.Size.Width, - (float)(bounds.Top) / sheet.Size.Height, - (float)(bounds.Width) / sheet.Size.Width, - (float)(bounds.Height) / sheet.Size.Height); - - uvhax = new float2[] - { - new float2( uv.Left, uv.Top ), - new float2( uv.Right, uv.Top ), - new float2( uv.Left, uv.Bottom ), - new float2( uv.Right, uv.Bottom ), - }; - - this.size = new float2(bounds.Size); - } - - public float2 FastMapTextureCoords( int k ) - { - return uvhax[ k ]; - } - - public void DrawAt( WorldRenderer wr, float2 location, string palette ) - { - Game.Renderer.SpriteRenderer.DrawSprite( this, location, wr, palette, this.size ); - } - - public void DrawAt( float2 location, int paletteIndex ) - { - Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, this.size ); - } - - public void DrawAt(float2 location, int paletteIndex, float scale) - { - Game.Renderer.SpriteRenderer.DrawSprite(this, location, paletteIndex, this.size * scale); - } - - public void DrawAt( float2 location, int paletteIndex, float2 size ) - { - Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, size ); - } - } - - public enum TextureChannel - { - Red = 0, - Green = 1, - Blue = 2, - Alpha = 3, - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; + +namespace OpenRA.Graphics +{ + public class Sprite + { + public readonly Rectangle bounds; + public readonly Sheet sheet; + public readonly TextureChannel channel; + public readonly RectangleF uv; + public readonly float2 size; + + readonly float2[] uvhax; + + public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel) + { + this.bounds = bounds; + this.sheet = sheet; + this.channel = channel; + + uv = new RectangleF( + (float)(bounds.Left) / sheet.Size.Width, + (float)(bounds.Top) / sheet.Size.Height, + (float)(bounds.Width) / sheet.Size.Width, + (float)(bounds.Height) / sheet.Size.Height); + + uvhax = new float2[] + { + new float2( uv.Left, uv.Top ), + new float2( uv.Right, uv.Top ), + new float2( uv.Left, uv.Bottom ), + new float2( uv.Right, uv.Bottom ), + }; + + this.size = new float2(bounds.Size); + } + + public float2 FastMapTextureCoords( int k ) + { + return uvhax[ k ]; + } + + public void DrawAt( WorldRenderer wr, float2 location, string palette ) + { + Game.Renderer.SpriteRenderer.DrawSprite( this, location, wr, palette, this.size ); + } + + public void DrawAt( float2 location, int paletteIndex ) + { + Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, this.size ); + } + + public void DrawAt(float2 location, int paletteIndex, float scale) + { + Game.Renderer.SpriteRenderer.DrawSprite(this, location, paletteIndex, this.size * scale); + } + + public void DrawAt( float2 location, int paletteIndex, float2 size ) + { + Game.Renderer.SpriteRenderer.DrawSprite( this, location, paletteIndex, size ); + } + } + + public enum TextureChannel + { + Red = 0, + Green = 1, + Blue = 2, + Alpha = 3, + } +} diff --git a/OpenRA.Game/Graphics/SpriteFont.cs b/OpenRA.Game/Graphics/SpriteFont.cs index 5846e46fd2..8ba3cd9d24 100644 --- a/OpenRA.Game/Graphics/SpriteFont.cs +++ b/OpenRA.Game/Graphics/SpriteFont.cs @@ -1,153 +1,153 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using System.Linq; -using System.Runtime.InteropServices; -using OpenRA.FileFormats; -using Tao.FreeType; - -namespace OpenRA.Graphics -{ - public class SpriteFont - { - int size; - - public SpriteFont(string name, int size) - { - this.size = size; - - if (0 != FT.FT_New_Face(library, name, 0, out face)) - throw new InvalidOperationException("FT_New_Face failed"); - - FT.FT_Set_Pixel_Sizes(face, 0, (uint)size); - glyphs = new Cache, GlyphInfo>(CreateGlyph); - - // setup a 1-channel SheetBuilder for our private use - if (builder == null) builder = new SheetBuilder(TextureChannel.Alpha); - - PrecacheColor(Color.White); - PrecacheColor(Color.Red); - } - - void PrecacheColor(Color c) - { - // precache glyphs for U+0020 - U+007f - for (var n = (char)0x20; n < (char)0x7f; n++) - if (glyphs[Pair.New(n, c)] == null) - throw new InvalidOperationException(); - } - - public void DrawText( string text, float2 location, Color c ) - { - location.Y += size; // baseline vs top - - var p = location; - foreach (var s in text) - { - if (s == '\n') - { - location.Y += size; - p = location; - continue; - } - - var g = glyphs[Pair.New(s, c)]; - Game.Renderer.RgbaSpriteRenderer.DrawSprite(g.Sprite, - new float2( - (int)Math.Round(p.X + g.Offset.X, 0), - p.Y + g.Offset.Y)); - p.X += g.Advance; - } - } - - public void DrawTextWithContrast(string text, float2 location, Color fg, Color bg, int offset) - { - if (offset > 0) - { - DrawText(text, location + new float2(-offset, 0), bg); - DrawText(text, location + new float2(offset, 0), bg); - DrawText(text, location + new float2(0, -offset), bg); - DrawText(text, location + new float2(0, offset), bg); - } - - DrawText(text, location, fg); - } - - public int2 Measure(string text) - { - return new int2((int)text.Split( '\n' ).Max( s => s.Sum(a => glyphs[Pair.New(a, Color.White)].Advance)), text.Split('\n').Count()*size); - } - - Cache, GlyphInfo> glyphs; - IntPtr face; - - GlyphInfo CreateGlyph(Pair c) - { - var index = FT.FT_Get_Char_Index(face, (uint)c.First); - if (0 != FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER)) - throw new InvalidOperationException( "FT_Load_Glyph failed." ); - - var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec)); - var _glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(_face.glyph, typeof(FT_GlyphSlotRec)); - - var s = builder.Allocate( - new Size(_glyph.metrics.width.ToInt32() >> 6, - _glyph.metrics.height.ToInt32() >> 6)); - - var g = new GlyphInfo - { - Sprite = s, - Advance = _glyph.metrics.horiAdvance.ToInt32() / 64f, - Offset = { X = _glyph.bitmap_left, Y = -_glyph.bitmap_top } - }; - - unsafe - { - var p = (byte*)_glyph.bitmap.buffer; - var dest = s.sheet.Data; - var destStride = s.sheet.Size.Width * 4; - - for (var j = 0; j < s.size.Y; j++) - { - for (var i = 0; i < s.size.X; i++) - if (p[i] != 0) - { - var q = destStride * (j + s.bounds.Top) + 4 * (i + s.bounds.Left); - dest[q] = c.Second.B; - dest[q + 1] = c.Second.G; - dest[q + 2] = c.Second.R; - dest[q + 3] = p[i]; - } - - p += _glyph.bitmap.pitch; - } - } - - return g; - } - - static SpriteFont() - { - FT.FT_Init_FreeType(out library); - } - - static IntPtr library; - static SheetBuilder builder; - } - - class GlyphInfo - { - public float Advance; - public int2 Offset; - public Sprite Sprite; - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using OpenRA.FileFormats; +using Tao.FreeType; + +namespace OpenRA.Graphics +{ + public class SpriteFont + { + int size; + + public SpriteFont(string name, int size) + { + this.size = size; + + if (0 != FT.FT_New_Face(library, name, 0, out face)) + throw new InvalidOperationException("FT_New_Face failed"); + + FT.FT_Set_Pixel_Sizes(face, 0, (uint)size); + glyphs = new Cache, GlyphInfo>(CreateGlyph); + + // setup a 1-channel SheetBuilder for our private use + if (builder == null) builder = new SheetBuilder(TextureChannel.Alpha); + + PrecacheColor(Color.White); + PrecacheColor(Color.Red); + } + + void PrecacheColor(Color c) + { + // precache glyphs for U+0020 - U+007f + for (var n = (char)0x20; n < (char)0x7f; n++) + if (glyphs[Pair.New(n, c)] == null) + throw new InvalidOperationException(); + } + + public void DrawText( string text, float2 location, Color c ) + { + location.Y += size; // baseline vs top + + var p = location; + foreach (var s in text) + { + if (s == '\n') + { + location.Y += size; + p = location; + continue; + } + + var g = glyphs[Pair.New(s, c)]; + Game.Renderer.RgbaSpriteRenderer.DrawSprite(g.Sprite, + new float2( + (int)Math.Round(p.X + g.Offset.X, 0), + p.Y + g.Offset.Y)); + p.X += g.Advance; + } + } + + public void DrawTextWithContrast(string text, float2 location, Color fg, Color bg, int offset) + { + if (offset > 0) + { + DrawText(text, location + new float2(-offset, 0), bg); + DrawText(text, location + new float2(offset, 0), bg); + DrawText(text, location + new float2(0, -offset), bg); + DrawText(text, location + new float2(0, offset), bg); + } + + DrawText(text, location, fg); + } + + public int2 Measure(string text) + { + return new int2((int)text.Split( '\n' ).Max( s => s.Sum(a => glyphs[Pair.New(a, Color.White)].Advance)), text.Split('\n').Count()*size); + } + + Cache, GlyphInfo> glyphs; + IntPtr face; + + GlyphInfo CreateGlyph(Pair c) + { + var index = FT.FT_Get_Char_Index(face, (uint)c.First); + if (0 != FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER)) + throw new InvalidOperationException( "FT_Load_Glyph failed." ); + + var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec)); + var _glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(_face.glyph, typeof(FT_GlyphSlotRec)); + + var s = builder.Allocate( + new Size(_glyph.metrics.width.ToInt32() >> 6, + _glyph.metrics.height.ToInt32() >> 6)); + + var g = new GlyphInfo + { + Sprite = s, + Advance = _glyph.metrics.horiAdvance.ToInt32() / 64f, + Offset = { X = _glyph.bitmap_left, Y = -_glyph.bitmap_top } + }; + + unsafe + { + var p = (byte*)_glyph.bitmap.buffer; + var dest = s.sheet.Data; + var destStride = s.sheet.Size.Width * 4; + + for (var j = 0; j < s.size.Y; j++) + { + for (var i = 0; i < s.size.X; i++) + if (p[i] != 0) + { + var q = destStride * (j + s.bounds.Top) + 4 * (i + s.bounds.Left); + dest[q] = c.Second.B; + dest[q + 1] = c.Second.G; + dest[q + 2] = c.Second.R; + dest[q + 3] = p[i]; + } + + p += _glyph.bitmap.pitch; + } + } + + return g; + } + + static SpriteFont() + { + FT.FT_Init_FreeType(out library); + } + + static IntPtr library; + static SheetBuilder builder; + } + + class GlyphInfo + { + public float Advance; + public int2 Offset; + public Sprite Sprite; + } +} diff --git a/OpenRA.Game/Graphics/SpriteLoader.cs b/OpenRA.Game/Graphics/SpriteLoader.cs index 570f8daf50..2cb8efa6b4 100644 --- a/OpenRA.Game/Graphics/SpriteLoader.cs +++ b/OpenRA.Game/Graphics/SpriteLoader.cs @@ -1,37 +1,37 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.FileFormats; - -namespace OpenRA.Graphics -{ - public class SpriteLoader - { - public SpriteLoader( string[] exts, SheetBuilder sheetBuilder ) - { - SheetBuilder = sheetBuilder; - this.exts = exts; - sprites = new Cache( LoadSprites ); - } - - readonly SheetBuilder SheetBuilder; - readonly Cache sprites; - readonly string[] exts; - - Sprite[] LoadSprites(string filename) - { - var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts)); - return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray(); - } - - public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.FileFormats; + +namespace OpenRA.Graphics +{ + public class SpriteLoader + { + public SpriteLoader( string[] exts, SheetBuilder sheetBuilder ) + { + SheetBuilder = sheetBuilder; + this.exts = exts; + sprites = new Cache( LoadSprites ); + } + + readonly SheetBuilder SheetBuilder; + readonly Cache sprites; + readonly string[] exts; + + Sprite[] LoadSprites(string filename) + { + var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts)); + return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray(); + } + + public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; } + } +} diff --git a/OpenRA.Game/Graphics/SpriteRenderer.cs b/OpenRA.Game/Graphics/SpriteRenderer.cs index 88e3135b7a..cdbe35f5b3 100644 --- a/OpenRA.Game/Graphics/SpriteRenderer.cs +++ b/OpenRA.Game/Graphics/SpriteRenderer.cs @@ -1,96 +1,96 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.FileFormats.Graphics; - -namespace OpenRA.Graphics -{ - public class SpriteRenderer : Renderer.IBatchRenderer - { - Renderer renderer; - IShader shader; - - Vertex[] vertices = new Vertex[Renderer.TempBufferSize]; - ushort[] indices = new ushort[Renderer.TempBufferSize]; - Sheet currentSheet = null; - int nv = 0, ni = 0; - - public SpriteRenderer(Renderer renderer, IShader shader) - { - this.renderer = renderer; - this.shader = shader; - } - - public SpriteRenderer(Renderer renderer) - : this(renderer, renderer.SpriteShader) { } - - public void Flush() - { - if (ni > 0) - { - shader.SetValue( "DiffuseTexture", currentSheet.Texture ); - shader.Render(() => - { - var vb = renderer.GetTempVertexBuffer(); - var ib = renderer.GetTempIndexBuffer(); - vb.SetData(vertices, nv); - ib.SetData(indices, ni); - renderer.DrawBatch(vb, ib, - new Range(0, nv), - new Range(0, ni), - PrimitiveType.TriangleList, - shader); - }); - - nv = 0; ni = 0; - currentSheet = null; - } - } - - public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette) - { - DrawSprite(s, location, wr.GetPaletteIndex(palette), s.size); - } - - public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette, float2 size) - { - DrawSprite(s, location, wr.GetPaletteIndex(palette), size); - } - - public void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size) - { - Renderer.CurrentBatchRenderer = this; - - if (s.sheet != currentSheet) - Flush(); - - if( nv + 4 > Renderer.TempBufferSize ) - Flush(); - if( ni + 6 > Renderer.TempBufferSize ) - Flush(); - - currentSheet = s.sheet; - Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, paletteIndex, nv, ni, size); - nv += 4; ni += 6; - } - - - // For RGBASpriteRenderer, which doesn't use palettes - public void DrawSprite(Sprite s, float2 location) - { - DrawSprite(s, location, 0, s.size); - } - - public void DrawSprite(Sprite s, float2 location, float2 size) - { - DrawSprite(s, location, 0, size); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.FileFormats.Graphics; + +namespace OpenRA.Graphics +{ + public class SpriteRenderer : Renderer.IBatchRenderer + { + Renderer renderer; + IShader shader; + + Vertex[] vertices = new Vertex[Renderer.TempBufferSize]; + ushort[] indices = new ushort[Renderer.TempBufferSize]; + Sheet currentSheet = null; + int nv = 0, ni = 0; + + public SpriteRenderer(Renderer renderer, IShader shader) + { + this.renderer = renderer; + this.shader = shader; + } + + public SpriteRenderer(Renderer renderer) + : this(renderer, renderer.SpriteShader) { } + + public void Flush() + { + if (ni > 0) + { + shader.SetValue( "DiffuseTexture", currentSheet.Texture ); + shader.Render(() => + { + var vb = renderer.GetTempVertexBuffer(); + var ib = renderer.GetTempIndexBuffer(); + vb.SetData(vertices, nv); + ib.SetData(indices, ni); + renderer.DrawBatch(vb, ib, + new Range(0, nv), + new Range(0, ni), + PrimitiveType.TriangleList, + shader); + }); + + nv = 0; ni = 0; + currentSheet = null; + } + } + + public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette) + { + DrawSprite(s, location, wr.GetPaletteIndex(palette), s.size); + } + + public void DrawSprite(Sprite s, float2 location, WorldRenderer wr, string palette, float2 size) + { + DrawSprite(s, location, wr.GetPaletteIndex(palette), size); + } + + public void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size) + { + Renderer.CurrentBatchRenderer = this; + + if (s.sheet != currentSheet) + Flush(); + + if( nv + 4 > Renderer.TempBufferSize ) + Flush(); + if( ni + 6 > Renderer.TempBufferSize ) + Flush(); + + currentSheet = s.sheet; + Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, paletteIndex, nv, ni, size); + nv += 4; ni += 6; + } + + + // For RGBASpriteRenderer, which doesn't use palettes + public void DrawSprite(Sprite s, float2 location) + { + DrawSprite(s, location, 0, s.size); + } + + public void DrawSprite(Sprite s, float2 location, float2 size) + { + DrawSprite(s, location, 0, size); + } + } +} diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index cb91ff3e9b..b4505b2291 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -1,105 +1,105 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.FileFormats; -using OpenRA.FileFormats.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Graphics -{ - class TerrainRenderer - { - IVertexBuffer vertexBuffer; - IIndexBuffer indexBuffer; - Sheet terrainSheet; - - World world; - Map map; - - public TerrainRenderer(World world, WorldRenderer wr) - { - this.world = world; - this.map = world.Map; - - Size tileSize = new Size( Game.CellSize, Game.CellSize ); - var tileMapping = new Cache, Sprite>( - x => Game.modData.SheetBuilder.Add(world.TileSet.GetBytes(x), tileSize)); - - Vertex[] vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width]; - ushort[] indices = new ushort[6 * map.Bounds.Height * map.Bounds.Width]; - - terrainSheet = tileMapping[map.MapTiles.Value[map.Bounds.Left, map.Bounds.Top]].sheet; - - int nv = 0; - int ni = 0; - - for( int j = map.Bounds.Top; j < map.Bounds.Bottom; j++ ) - for( int i = map.Bounds.Left; i < map.Bounds.Right; i++ ) - { - Sprite tile = tileMapping[map.MapTiles.Value[i, j]]; - // TODO: The zero below should explicitly refer to the terrain palette, but this code is called - // before the palettes are created. Therefore assumes that "terrain" is the first palette to be defined - Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, Game.modData.Palette.GetPaletteIndex("terrain"), nv, ni, tile.size); - nv += 4; - ni += 6; - - if (tileMapping[map.MapTiles.Value[i, j]].sheet != terrainSheet) - throw new InvalidOperationException("Terrain sprites span multiple sheets"); - } - - vertexBuffer = Game.Renderer.Device.CreateVertexBuffer( vertices.Length ); - vertexBuffer.SetData( vertices, nv ); - - indexBuffer = Game.Renderer.Device.CreateIndexBuffer( indices.Length ); - indexBuffer.SetData( indices, ni ); - } - - public void Draw( WorldRenderer wr, Viewport viewport ) - { - int indicesPerRow = map.Bounds.Width * 6; - int verticesPerRow = map.Bounds.Width * 4; - - int visibleRows = (int)(viewport.Height * 1f / Game.CellSize + 2); - - int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.Bounds.Top); - int lastRow = firstRow + visibleRows; - - if (lastRow < 0 || firstRow > map.Bounds.Height) - return; - - if (firstRow < 0) firstRow = 0; - if (lastRow > map.Bounds.Height) lastRow = map.Bounds.Height; - - if (world.LocalPlayer != null && !world.LocalShroud.Disabled && world.LocalShroud.Bounds.HasValue) - { - var r = world.LocalShroud.Bounds.Value; - if (firstRow < r.Top - map.Bounds.Top) - firstRow = r.Top - map.Bounds.Top; - - if (firstRow > r.Bottom - map.Bounds.Top) - firstRow = r.Bottom - map.Bounds.Top; - } - - if( lastRow < firstRow ) lastRow = firstRow; - - Game.Renderer.SpriteShader.SetValue( "DiffuseTexture", terrainSheet.Texture ); - Game.Renderer.SpriteShader.Render(() => - Game.Renderer.DrawBatch(vertexBuffer, indexBuffer, - new Range(verticesPerRow * firstRow, verticesPerRow * lastRow), - new Range(indicesPerRow * firstRow, indicesPerRow * lastRow), - PrimitiveType.TriangleList, Game.Renderer.SpriteShader)); - - foreach (var r in world.WorldActor.TraitsImplementing()) - r.Render( wr ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.FileFormats; +using OpenRA.FileFormats.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Graphics +{ + class TerrainRenderer + { + IVertexBuffer vertexBuffer; + IIndexBuffer indexBuffer; + Sheet terrainSheet; + + World world; + Map map; + + public TerrainRenderer(World world, WorldRenderer wr) + { + this.world = world; + this.map = world.Map; + + Size tileSize = new Size( Game.CellSize, Game.CellSize ); + var tileMapping = new Cache, Sprite>( + x => Game.modData.SheetBuilder.Add(world.TileSet.GetBytes(x), tileSize)); + + Vertex[] vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width]; + ushort[] indices = new ushort[6 * map.Bounds.Height * map.Bounds.Width]; + + terrainSheet = tileMapping[map.MapTiles.Value[map.Bounds.Left, map.Bounds.Top]].sheet; + + int nv = 0; + int ni = 0; + + for( int j = map.Bounds.Top; j < map.Bounds.Bottom; j++ ) + for( int i = map.Bounds.Left; i < map.Bounds.Right; i++ ) + { + Sprite tile = tileMapping[map.MapTiles.Value[i, j]]; + // TODO: The zero below should explicitly refer to the terrain palette, but this code is called + // before the palettes are created. Therefore assumes that "terrain" is the first palette to be defined + Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, Game.modData.Palette.GetPaletteIndex("terrain"), nv, ni, tile.size); + nv += 4; + ni += 6; + + if (tileMapping[map.MapTiles.Value[i, j]].sheet != terrainSheet) + throw new InvalidOperationException("Terrain sprites span multiple sheets"); + } + + vertexBuffer = Game.Renderer.Device.CreateVertexBuffer( vertices.Length ); + vertexBuffer.SetData( vertices, nv ); + + indexBuffer = Game.Renderer.Device.CreateIndexBuffer( indices.Length ); + indexBuffer.SetData( indices, ni ); + } + + public void Draw( WorldRenderer wr, Viewport viewport ) + { + int indicesPerRow = map.Bounds.Width * 6; + int verticesPerRow = map.Bounds.Width * 4; + + int visibleRows = (int)(viewport.Height * 1f / Game.CellSize + 2); + + int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.Bounds.Top); + int lastRow = firstRow + visibleRows; + + if (lastRow < 0 || firstRow > map.Bounds.Height) + return; + + if (firstRow < 0) firstRow = 0; + if (lastRow > map.Bounds.Height) lastRow = map.Bounds.Height; + + if (world.LocalPlayer != null && !world.LocalShroud.Disabled && world.LocalShroud.Bounds.HasValue) + { + var r = world.LocalShroud.Bounds.Value; + if (firstRow < r.Top - map.Bounds.Top) + firstRow = r.Top - map.Bounds.Top; + + if (firstRow > r.Bottom - map.Bounds.Top) + firstRow = r.Bottom - map.Bounds.Top; + } + + if( lastRow < firstRow ) lastRow = firstRow; + + Game.Renderer.SpriteShader.SetValue( "DiffuseTexture", terrainSheet.Texture ); + Game.Renderer.SpriteShader.Render(() => + Game.Renderer.DrawBatch(vertexBuffer, indexBuffer, + new Range(verticesPerRow * firstRow, verticesPerRow * lastRow), + new Range(indicesPerRow * firstRow, indicesPerRow * lastRow), + PrimitiveType.TriangleList, Game.Renderer.SpriteShader)); + + foreach (var r in world.WorldActor.TraitsImplementing()) + r.Render( wr ); + } + } +} diff --git a/OpenRA.Game/Graphics/Util.cs b/OpenRA.Game/Graphics/Util.cs index 1b70010dba..67dd54d81f 100644 --- a/OpenRA.Game/Graphics/Util.cs +++ b/OpenRA.Game/Graphics/Util.cs @@ -1,122 +1,122 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using OpenRA.FileFormats.Graphics; - -namespace OpenRA.Graphics -{ - public static class Util - { - public static string[] ReadAllLines(Stream s) - { - List result = new List(); - using (StreamReader reader = new StreamReader(s)) - while(!reader.EndOfStream) - { - var line = reader.ReadLine(); - if( !string.IsNullOrEmpty( line ) && line[0] != '#' ) - result.Add( line ); - } - - return result.ToArray(); - } - - public static T[] MakeArray(int count, Converter f) - { - T[] result = new T[count]; - for (int i = 0; i < count; i++) - result[i] = f(i); - - return result; - } - - static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f }; - - public static void FastCreateQuad(Vertex[] vertices, ushort[] indices, float2 o, Sprite r, int palette, int nv, int ni, float2 size) - { - var attrib = new float2(palette / (float)HardwarePalette.MaxPalettes, channelSelect[(int)r.channel]); - - vertices[nv] = new Vertex(o, - r.FastMapTextureCoords(0), attrib); - vertices[nv + 1] = new Vertex(new float2(o.X + size.X, o.Y), - r.FastMapTextureCoords(1), attrib); - vertices[nv + 2] = new Vertex(new float2(o.X, o.Y + size.Y), - r.FastMapTextureCoords(2), attrib); - vertices[nv + 3] = new Vertex(new float2(o.X + size.X, o.Y + size.Y), - r.FastMapTextureCoords(3), attrib); - - indices[ni] = (ushort)(nv); - indices[ni + 1] = indices[ni + 3] = (ushort)(nv + 1); - indices[ni + 2] = indices[ni + 5] = (ushort)(nv + 2); - indices[ni + 4] = (ushort)(nv + 3); - } - - public static void FastCopyIntoChannel(Sprite dest, byte[] src) - { - var masks = new int[] { 2, 1, 0, 3 }; // hack, our channel order is nuts. - var data = dest.sheet.Data; - var srcStride = dest.bounds.Width; - var destStride = dest.sheet.Size.Width * 4; - var destOffset = destStride * dest.bounds.Top + dest.bounds.Left * 4 + masks[(int)dest.channel]; - var destSkip = destStride - 4 * srcStride; - var height = dest.bounds.Height; - - var srcOffset = 0; - for (var j = 0; j < height; j++) - { - for (int i = 0; i < srcStride; i++, srcOffset++) - { - data[destOffset] = src[srcOffset]; - destOffset += 4; - } - destOffset += destSkip; - } - } - - public static Color Lerp(float t, Color a, Color b) - { - return Color.FromArgb( - LerpChannel(t, a.A, b.A), - LerpChannel(t, a.R, b.R), - LerpChannel(t, a.G, b.G), - LerpChannel(t, a.B, b.B)); - } - - public static int LerpARGBColor(float t, int c1, int c2) - { - int a = LerpChannel(t, (c1 >> 24) & 255, (c2 >> 24) & 255); - int r = LerpChannel(t, (c1 >> 16) & 255, (c2 >> 16) & 255); - int g = LerpChannel(t, (c1 >> 8) & 255, (c2 >> 8) & 255); - int b = LerpChannel(t, c1 & 255, c2 & 255); - return (a << 24) | (r << 16) | (g << 8) | b; - } - - public static int LerpChannel(float t, int a, int b) - { - return (int)((1 - t) * a + t * b); - } - - public static int NextPowerOf2(int v) - { - --v; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - ++v; - return v; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using OpenRA.FileFormats.Graphics; + +namespace OpenRA.Graphics +{ + public static class Util + { + public static string[] ReadAllLines(Stream s) + { + List result = new List(); + using (StreamReader reader = new StreamReader(s)) + while(!reader.EndOfStream) + { + var line = reader.ReadLine(); + if( !string.IsNullOrEmpty( line ) && line[0] != '#' ) + result.Add( line ); + } + + return result.ToArray(); + } + + public static T[] MakeArray(int count, Converter f) + { + T[] result = new T[count]; + for (int i = 0; i < count; i++) + result[i] = f(i); + + return result; + } + + static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f }; + + public static void FastCreateQuad(Vertex[] vertices, ushort[] indices, float2 o, Sprite r, int palette, int nv, int ni, float2 size) + { + var attrib = new float2(palette / (float)HardwarePalette.MaxPalettes, channelSelect[(int)r.channel]); + + vertices[nv] = new Vertex(o, + r.FastMapTextureCoords(0), attrib); + vertices[nv + 1] = new Vertex(new float2(o.X + size.X, o.Y), + r.FastMapTextureCoords(1), attrib); + vertices[nv + 2] = new Vertex(new float2(o.X, o.Y + size.Y), + r.FastMapTextureCoords(2), attrib); + vertices[nv + 3] = new Vertex(new float2(o.X + size.X, o.Y + size.Y), + r.FastMapTextureCoords(3), attrib); + + indices[ni] = (ushort)(nv); + indices[ni + 1] = indices[ni + 3] = (ushort)(nv + 1); + indices[ni + 2] = indices[ni + 5] = (ushort)(nv + 2); + indices[ni + 4] = (ushort)(nv + 3); + } + + public static void FastCopyIntoChannel(Sprite dest, byte[] src) + { + var masks = new int[] { 2, 1, 0, 3 }; // hack, our channel order is nuts. + var data = dest.sheet.Data; + var srcStride = dest.bounds.Width; + var destStride = dest.sheet.Size.Width * 4; + var destOffset = destStride * dest.bounds.Top + dest.bounds.Left * 4 + masks[(int)dest.channel]; + var destSkip = destStride - 4 * srcStride; + var height = dest.bounds.Height; + + var srcOffset = 0; + for (var j = 0; j < height; j++) + { + for (int i = 0; i < srcStride; i++, srcOffset++) + { + data[destOffset] = src[srcOffset]; + destOffset += 4; + } + destOffset += destSkip; + } + } + + public static Color Lerp(float t, Color a, Color b) + { + return Color.FromArgb( + LerpChannel(t, a.A, b.A), + LerpChannel(t, a.R, b.R), + LerpChannel(t, a.G, b.G), + LerpChannel(t, a.B, b.B)); + } + + public static int LerpARGBColor(float t, int c1, int c2) + { + int a = LerpChannel(t, (c1 >> 24) & 255, (c2 >> 24) & 255); + int r = LerpChannel(t, (c1 >> 16) & 255, (c2 >> 16) & 255); + int g = LerpChannel(t, (c1 >> 8) & 255, (c2 >> 8) & 255); + int b = LerpChannel(t, c1 & 255, c2 & 255); + return (a << 24) | (r << 16) | (g << 8) | b; + } + + public static int LerpChannel(float t, int a, int b) + { + return (int)((1 - t) * a + t * b); + } + + public static int NextPowerOf2(int v) + { + --v; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + ++v; + return v; + } + } +} diff --git a/OpenRA.Game/Graphics/Viewport.cs b/OpenRA.Game/Graphics/Viewport.cs index 2a7788a5de..9a380d8208 100755 --- a/OpenRA.Game/Graphics/Viewport.cs +++ b/OpenRA.Game/Graphics/Viewport.cs @@ -1,157 +1,157 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Widgets; - -namespace OpenRA.Graphics -{ - public class Viewport - { - readonly int2 screenSize; - int2 scrollPosition; - readonly Renderer renderer; - readonly Rectangle adjustedMapBounds; - - public float2 Location { get { return scrollPosition; } } - - public int Width { get { return screenSize.X; } } - public int Height { get { return screenSize.Y; } } - - float cursorFrame = 0f; - - public static int TicksSinceLastMove = 0; - public static int2 LastMousePos; - - public void Scroll(float2 delta) - { - this.Scroll(delta, false); - } - - public void Scroll(float2 delta, bool ignoreBorders) - { - var d = delta.ToInt2(); - var newScrollPosition = scrollPosition + d; - - if(!ignoreBorders) - newScrollPosition = this.NormalizeScrollPosition(newScrollPosition); - - scrollPosition = newScrollPosition; - } - - private int2 NormalizeScrollPosition(int2 newScrollPosition) - { - return newScrollPosition.Clamp(adjustedMapBounds); - } - - public ScrollDirection GetBlockedDirections() - { - ScrollDirection blockedDirections = ScrollDirection.None; - if(scrollPosition.Y <= adjustedMapBounds.Top) - blockedDirections = blockedDirections.Set(ScrollDirection.Up, true); - if(scrollPosition.X <= adjustedMapBounds.Left) - blockedDirections = blockedDirections.Set(ScrollDirection.Left, true); - if(scrollPosition.Y >= adjustedMapBounds.Bottom) - blockedDirections = blockedDirections.Set(ScrollDirection.Down, true); - if(scrollPosition.X >= adjustedMapBounds.Right) - blockedDirections = blockedDirections.Set(ScrollDirection.Right, true); - - return blockedDirections; - } - - public Viewport(int2 screenSize, Rectangle mapBounds, Renderer renderer) - { - this.screenSize = screenSize; - this.renderer = renderer; - this.adjustedMapBounds = new Rectangle(Game.CellSize*mapBounds.X - screenSize.X/2, - Game.CellSize*mapBounds.Y - screenSize.Y/2, - Game.CellSize*mapBounds.Width, - Game.CellSize*mapBounds.Height); - this.scrollPosition = new int2(adjustedMapBounds.Location) + new int2(adjustedMapBounds.Size)/2; - } - - public void DrawRegions( WorldRenderer wr, IInputHandler inputHandler ) - { - renderer.BeginFrame(scrollPosition); - if (wr != null) - wr.Draw(); - - Widget.DoDraw(); - var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default"; - new Cursor(cursorName).Draw((int)cursorFrame, Viewport.LastMousePos + Location); - - renderer.EndFrame( inputHandler ); - } - - public void Tick() - { - cursorFrame += 0.5f; - } - - public float2 ViewToWorld(int2 loc) - { - return (1f / Game.CellSize) * (loc.ToFloat2() + Location); - } - public float2 ViewToWorld(MouseInput mi) - { - return ViewToWorld(mi.Location); - } - - public void Center(float2 loc) - { - scrollPosition = this.NormalizeScrollPosition((Game.CellSize*loc - screenSize / 2).ToInt2()); - } - - public void Center(IEnumerable actors) - { - if (!actors.Any()) return; - - var avgPos = actors - .Select(a => a.CenterLocation) - .Aggregate((a, b) => a + b) / actors.Count(); - scrollPosition = this.NormalizeScrollPosition((avgPos - screenSize / 2)); - } - - public Rectangle ViewBounds(World world) - { - var r = WorldBounds(world); - var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X); - var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y); - var right = left + (int)(Game.CellSize * r.Width); - var bottom = top + (int)(Game.CellSize * r.Height); - - if (left < 0) left = 0; - if (top < 0) top = 0; - if (right > Game.viewport.Width) right = Game.viewport.Width; - if (bottom > Game.viewport.Height) bottom = Game.viewport.Height; - return new Rectangle(left, top, right - left, bottom - top); - } - - int2 cachedScroll = new int2(int.MaxValue, int.MaxValue); - Rectangle cachedRect; - - public Rectangle WorldBounds(World world) - { - if (cachedScroll != scrollPosition) - { - int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors - var tl = ViewToWorld(int2.Zero).ToInt2() - boundary; - var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary; - cachedRect = Rectangle.Intersect(Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y), world.Map.Bounds); - cachedScroll = scrollPosition; - } - - var b = world.LocalShroud.Bounds; - return (b.HasValue) ? Rectangle.Intersect(cachedRect, b.Value) : cachedRect; - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Widgets; + +namespace OpenRA.Graphics +{ + public class Viewport + { + readonly int2 screenSize; + int2 scrollPosition; + readonly Renderer renderer; + readonly Rectangle adjustedMapBounds; + + public float2 Location { get { return scrollPosition; } } + + public int Width { get { return screenSize.X; } } + public int Height { get { return screenSize.Y; } } + + float cursorFrame = 0f; + + public static int TicksSinceLastMove = 0; + public static int2 LastMousePos; + + public void Scroll(float2 delta) + { + this.Scroll(delta, false); + } + + public void Scroll(float2 delta, bool ignoreBorders) + { + var d = delta.ToInt2(); + var newScrollPosition = scrollPosition + d; + + if(!ignoreBorders) + newScrollPosition = this.NormalizeScrollPosition(newScrollPosition); + + scrollPosition = newScrollPosition; + } + + private int2 NormalizeScrollPosition(int2 newScrollPosition) + { + return newScrollPosition.Clamp(adjustedMapBounds); + } + + public ScrollDirection GetBlockedDirections() + { + ScrollDirection blockedDirections = ScrollDirection.None; + if(scrollPosition.Y <= adjustedMapBounds.Top) + blockedDirections = blockedDirections.Set(ScrollDirection.Up, true); + if(scrollPosition.X <= adjustedMapBounds.Left) + blockedDirections = blockedDirections.Set(ScrollDirection.Left, true); + if(scrollPosition.Y >= adjustedMapBounds.Bottom) + blockedDirections = blockedDirections.Set(ScrollDirection.Down, true); + if(scrollPosition.X >= adjustedMapBounds.Right) + blockedDirections = blockedDirections.Set(ScrollDirection.Right, true); + + return blockedDirections; + } + + public Viewport(int2 screenSize, Rectangle mapBounds, Renderer renderer) + { + this.screenSize = screenSize; + this.renderer = renderer; + this.adjustedMapBounds = new Rectangle(Game.CellSize*mapBounds.X - screenSize.X/2, + Game.CellSize*mapBounds.Y - screenSize.Y/2, + Game.CellSize*mapBounds.Width, + Game.CellSize*mapBounds.Height); + this.scrollPosition = new int2(adjustedMapBounds.Location) + new int2(adjustedMapBounds.Size)/2; + } + + public void DrawRegions( WorldRenderer wr, IInputHandler inputHandler ) + { + renderer.BeginFrame(scrollPosition); + if (wr != null) + wr.Draw(); + + Widget.DoDraw(); + var cursorName = Widget.RootWidget.GetCursorOuter(Viewport.LastMousePos) ?? "default"; + new Cursor(cursorName).Draw((int)cursorFrame, Viewport.LastMousePos + Location); + + renderer.EndFrame( inputHandler ); + } + + public void Tick() + { + cursorFrame += 0.5f; + } + + public float2 ViewToWorld(int2 loc) + { + return (1f / Game.CellSize) * (loc.ToFloat2() + Location); + } + public float2 ViewToWorld(MouseInput mi) + { + return ViewToWorld(mi.Location); + } + + public void Center(float2 loc) + { + scrollPosition = this.NormalizeScrollPosition((Game.CellSize*loc - screenSize / 2).ToInt2()); + } + + public void Center(IEnumerable actors) + { + if (!actors.Any()) return; + + var avgPos = actors + .Select(a => a.CenterLocation) + .Aggregate((a, b) => a + b) / actors.Count(); + scrollPosition = this.NormalizeScrollPosition((avgPos - screenSize / 2)); + } + + public Rectangle ViewBounds(World world) + { + var r = WorldBounds(world); + var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X); + var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y); + var right = left + (int)(Game.CellSize * r.Width); + var bottom = top + (int)(Game.CellSize * r.Height); + + if (left < 0) left = 0; + if (top < 0) top = 0; + if (right > Game.viewport.Width) right = Game.viewport.Width; + if (bottom > Game.viewport.Height) bottom = Game.viewport.Height; + return new Rectangle(left, top, right - left, bottom - top); + } + + int2 cachedScroll = new int2(int.MaxValue, int.MaxValue); + Rectangle cachedRect; + + public Rectangle WorldBounds(World world) + { + if (cachedScroll != scrollPosition) + { + int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors + var tl = ViewToWorld(int2.Zero).ToInt2() - boundary; + var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary; + cachedRect = Rectangle.Intersect(Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y), world.Map.Bounds); + cachedScroll = scrollPosition; + } + + var b = world.LocalShroud.Bounds; + return (b.HasValue) ? Rectangle.Intersect(cachedRect, b.Value) : cachedRect; + } + } } \ No newline at end of file diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 4eff2547b8..5360073c0d 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -1,184 +1,184 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Graphics -{ - public class WorldRenderer - { - public readonly World world; - internal readonly TerrainRenderer terrainRenderer; - internal readonly ShroudRenderer shroudRenderer; - - public readonly UiOverlay uiOverlay; - internal readonly HardwarePalette palette; - - internal WorldRenderer(World world) - { - this.world = world; - this.palette = Game.modData.Palette; - foreach( var pal in world.traitDict.ActorsWithTraitMultiple( world ) ) - pal.Trait.InitPalette( this ); - - terrainRenderer = new TerrainRenderer(world, this); - shroudRenderer = new ShroudRenderer(world); - uiOverlay = new UiOverlay(); - } - - public int GetPaletteIndex(string name) { return palette.GetPaletteIndex(name); } - public Palette GetPalette(string name) { return palette.GetPalette(name); } - public void AddPalette(string name, Palette pal) { palette.AddPalette(name, pal); } - - class SpriteComparer : IComparer - { - public int Compare(Renderable x, Renderable y) - { - return (x.Z + x.ZOffset).CompareTo(y.Z + y.ZOffset); - } - } - - IEnumerable SpritesToRender() - { - var bounds = Game.viewport.ViewBounds(world); - var comparer = new SpriteComparer(); - - bounds.Offset((int)Game.viewport.Location.X, (int)Game.viewport.Location.Y); - - var actors = world.FindUnits( - new float2(bounds.Left, bounds.Top), - new float2(bounds.Right, bounds.Bottom)); - - var renderables = actors.SelectMany(a => a.Render()) - .OrderBy(r => r, comparer); - - var effects = world.Effects.SelectMany(e => e.Render()); - - return renderables.Concat(effects); - } - - public void Draw() - { - RefreshPalette(); - var bounds = Game.viewport.ViewBounds(world); - Game.Renderer.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height); - - terrainRenderer.Draw(this, Game.viewport); - foreach (var a in world.traitDict.ActorsWithTraitMultiple(world)) - foreach (var r in a.Trait.RenderAsTerrain(a.Actor)) - r.Sprite.DrawAt(r.Pos, this.GetPaletteIndex(r.Palette), r.Scale); - - foreach (var a in world.Selection.Actors) - if (!a.Destroyed) - foreach (var t in a.TraitsImplementing()) - t.RenderBeforeWorld(this, a); - - Game.Renderer.Flush(); - - if (world.OrderGenerator != null) - world.OrderGenerator.RenderBeforeWorld(this, world); +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion - foreach (var image in SpritesToRender() ) - image.Sprite.DrawAt(image.Pos, this.GetPaletteIndex(image.Palette), image.Scale); - uiOverlay.Draw(this, world); - - // added for contrails - foreach (var a in world.Actors) - if (!a.Destroyed) - foreach (var t in a.TraitsImplementing()) - t.RenderAfterWorld(this, a); - - if (world.OrderGenerator != null) - world.OrderGenerator.RenderAfterWorld(this, world); - - shroudRenderer.Draw( this ); - Game.Renderer.DisableScissor(); - - foreach (var a in world.Selection.Actors) - if (!a.Destroyed) - foreach (var t in a.TraitsImplementing()) - t.RenderAfterWorld(this, a); - - Game.Renderer.Flush(); - } - - void DrawBox(RectangleF r, Color color) - { - var a = new float2(r.Left, r.Top); - var b = new float2(r.Right - a.X, 0); - var c = new float2(0, r.Bottom - a.Y); - Game.Renderer.LineRenderer.DrawLine(a, a + b, color, color); - Game.Renderer.LineRenderer.DrawLine(a + b, a + b + c, color, color); - Game.Renderer.LineRenderer.DrawLine(a + b + c, a + c, color, color); - Game.Renderer.LineRenderer.DrawLine(a, a + c, color, color); - } - - public void DrawSelectionBox(Actor selectedUnit, Color c) - { - var bounds = selectedUnit.GetBounds(false); - - var xy = new float2(bounds.Left, bounds.Top); - var Xy = new float2(bounds.Right, bounds.Top); - var xY = new float2(bounds.Left, bounds.Bottom); - var XY = new float2(bounds.Right, bounds.Bottom); - - Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(4, 0), c, c); - Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(0, 4), c, c); - Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(-4, 0), c, c); - Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(0, 4), c, c); - - Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(4, 0), c, c); - Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(0, -4), c, c); - Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(-4, 0), c, c); - Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c); - } - - public void DrawLocus(Color c, int2[] cells) - { - var dict = cells.ToDictionary(a => a, a => 0); - foreach (var t in dict.Keys) - { - if (!dict.ContainsKey(t + new int2(-1, 0))) - Game.Renderer.LineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(0, 1)), - c, c); - if (!dict.ContainsKey(t + new int2(1, 0))) - Game.Renderer.LineRenderer.DrawLine(Game.CellSize * (t + new int2(1, 0)), Game.CellSize * (t + new int2(1, 1)), - c, c); - if (!dict.ContainsKey(t + new int2(0, -1))) - Game.Renderer.LineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(1, 0)), - c, c); - if (!dict.ContainsKey(t + new int2(0, 1))) - Game.Renderer.LineRenderer.DrawLine(Game.CellSize * (t + new int2(0, 1)), Game.CellSize * (t + new int2(1, 1)), - c, c); - } - } - - public void DrawRangeCircle(Color c, float2 location, float range) - { - for (var i = 0; i < 32; i++) - { - var start = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * i) / 16); - var end = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * (i + 0.7)) / 16); - - Game.Renderer.LineRenderer.DrawLine(start, end, c, c); - } - } - - public void RefreshPalette() - { - palette.Update( world.WorldActor.TraitsImplementing() ); - } - } -} +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Graphics +{ + public class WorldRenderer + { + public readonly World world; + internal readonly TerrainRenderer terrainRenderer; + internal readonly ShroudRenderer shroudRenderer; + + public readonly UiOverlay uiOverlay; + internal readonly HardwarePalette palette; + + internal WorldRenderer(World world) + { + this.world = world; + this.palette = Game.modData.Palette; + foreach( var pal in world.traitDict.ActorsWithTraitMultiple( world ) ) + pal.Trait.InitPalette( this ); + + terrainRenderer = new TerrainRenderer(world, this); + shroudRenderer = new ShroudRenderer(world); + uiOverlay = new UiOverlay(); + } + + public int GetPaletteIndex(string name) { return palette.GetPaletteIndex(name); } + public Palette GetPalette(string name) { return palette.GetPalette(name); } + public void AddPalette(string name, Palette pal) { palette.AddPalette(name, pal); } + + class SpriteComparer : IComparer + { + public int Compare(Renderable x, Renderable y) + { + return (x.Z + x.ZOffset).CompareTo(y.Z + y.ZOffset); + } + } + + IEnumerable SpritesToRender() + { + var bounds = Game.viewport.ViewBounds(world); + var comparer = new SpriteComparer(); + + bounds.Offset((int)Game.viewport.Location.X, (int)Game.viewport.Location.Y); + + var actors = world.FindUnits( + new float2(bounds.Left, bounds.Top), + new float2(bounds.Right, bounds.Bottom)); + + var renderables = actors.SelectMany(a => a.Render()) + .OrderBy(r => r, comparer); + + var effects = world.Effects.SelectMany(e => e.Render()); + + return renderables.Concat(effects); + } + + public void Draw() + { + RefreshPalette(); + var bounds = Game.viewport.ViewBounds(world); + Game.Renderer.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height); + + terrainRenderer.Draw(this, Game.viewport); + foreach (var a in world.traitDict.ActorsWithTraitMultiple(world)) + foreach (var r in a.Trait.RenderAsTerrain(a.Actor)) + r.Sprite.DrawAt(r.Pos, this.GetPaletteIndex(r.Palette), r.Scale); + + foreach (var a in world.Selection.Actors) + if (!a.Destroyed) + foreach (var t in a.TraitsImplementing()) + t.RenderBeforeWorld(this, a); + + Game.Renderer.Flush(); + + if (world.OrderGenerator != null) + world.OrderGenerator.RenderBeforeWorld(this, world); + + foreach (var image in SpritesToRender() ) + image.Sprite.DrawAt(image.Pos, this.GetPaletteIndex(image.Palette), image.Scale); + uiOverlay.Draw(this, world); + + // added for contrails + foreach (var a in world.Actors) + if (!a.Destroyed) + foreach (var t in a.TraitsImplementing()) + t.RenderAfterWorld(this, a); + + if (world.OrderGenerator != null) + world.OrderGenerator.RenderAfterWorld(this, world); + + shroudRenderer.Draw( this ); + Game.Renderer.DisableScissor(); + + foreach (var a in world.Selection.Actors) + if (!a.Destroyed) + foreach (var t in a.TraitsImplementing()) + t.RenderAfterWorld(this, a); + + Game.Renderer.Flush(); + } + + void DrawBox(RectangleF r, Color color) + { + var a = new float2(r.Left, r.Top); + var b = new float2(r.Right - a.X, 0); + var c = new float2(0, r.Bottom - a.Y); + Game.Renderer.LineRenderer.DrawLine(a, a + b, color, color); + Game.Renderer.LineRenderer.DrawLine(a + b, a + b + c, color, color); + Game.Renderer.LineRenderer.DrawLine(a + b + c, a + c, color, color); + Game.Renderer.LineRenderer.DrawLine(a, a + c, color, color); + } + + public void DrawSelectionBox(Actor selectedUnit, Color c) + { + var bounds = selectedUnit.GetBounds(false); + + var xy = new float2(bounds.Left, bounds.Top); + var Xy = new float2(bounds.Right, bounds.Top); + var xY = new float2(bounds.Left, bounds.Bottom); + var XY = new float2(bounds.Right, bounds.Bottom); + + Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(4, 0), c, c); + Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(0, 4), c, c); + Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(-4, 0), c, c); + Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(0, 4), c, c); + + Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(4, 0), c, c); + Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(0, -4), c, c); + Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(-4, 0), c, c); + Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c); + } + + public void DrawLocus(Color c, int2[] cells) + { + var dict = cells.ToDictionary(a => a, a => 0); + foreach (var t in dict.Keys) + { + if (!dict.ContainsKey(t + new int2(-1, 0))) + Game.Renderer.LineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(0, 1)), + c, c); + if (!dict.ContainsKey(t + new int2(1, 0))) + Game.Renderer.LineRenderer.DrawLine(Game.CellSize * (t + new int2(1, 0)), Game.CellSize * (t + new int2(1, 1)), + c, c); + if (!dict.ContainsKey(t + new int2(0, -1))) + Game.Renderer.LineRenderer.DrawLine(Game.CellSize * t, Game.CellSize * (t + new int2(1, 0)), + c, c); + if (!dict.ContainsKey(t + new int2(0, 1))) + Game.Renderer.LineRenderer.DrawLine(Game.CellSize * (t + new int2(0, 1)), Game.CellSize * (t + new int2(1, 1)), + c, c); + } + } + + public void DrawRangeCircle(Color c, float2 location, float range) + { + for (var i = 0; i < 32; i++) + { + var start = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * i) / 16); + var end = location + Game.CellSize * range * float2.FromAngle((float)(Math.PI * (i + 0.7)) / 16); + + Game.Renderer.LineRenderer.DrawLine(start, end, c, c); + } + } + + public void RefreshPalette() + { + palette.Update( world.WorldActor.TraitsImplementing() ); + } + } +} diff --git a/OpenRA.Game/Group.cs b/OpenRA.Game/Group.cs index e50ebf1c48..082fc6df24 100644 --- a/OpenRA.Game/Group.cs +++ b/OpenRA.Game/Group.cs @@ -1,44 +1,44 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA -{ - public class Group - { - List actors; - int id; - - static int nextGroup; - - public IEnumerable Actors { get { return actors; } } - - public Group(IEnumerable actors) - { - this.actors = actors.ToList(); - - foreach (var a in actors) - a.Group = this; - - id = nextGroup++; - } - - public void Dump() - { - /* debug crap */ - Game.Debug("Group #{0}: {1}".F( - id, string.Join(",", actors.Select(a => "#{0} {1}".F(a.ActorID, a.Info.Name)).ToArray()))); - } - - /* todo: add lazy group path crap, groupleader, pruning, etc */ - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA +{ + public class Group + { + List actors; + int id; + + static int nextGroup; + + public IEnumerable Actors { get { return actors; } } + + public Group(IEnumerable actors) + { + this.actors = actors.ToList(); + + foreach (var a in actors) + a.Group = this; + + id = nextGroup++; + } + + public void Dump() + { + /* debug crap */ + Game.Debug("Group #{0}: {1}".F( + id, string.Join(",", actors.Select(a => "#{0} {1}".F(a.ActorID, a.Info.Name)).ToArray()))); + } + + /* todo: add lazy group path crap, groupleader, pruning, etc */ + } +} diff --git a/OpenRA.Game/InputHandler.cs b/OpenRA.Game/InputHandler.cs index e49dc01149..93d963e50c 100755 --- a/OpenRA.Game/InputHandler.cs +++ b/OpenRA.Game/InputHandler.cs @@ -1,52 +1,52 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Widgets; - -namespace OpenRA -{ - public class NullInputHandler : IInputHandler - { - // ignore all input - public void ModifierKeys( Modifiers mods ) { } - public void OnKeyInput( KeyInput input ) { } - public void OnMouseInput( MouseInput input ) { } - } - - public class DefaultInputHandler : IInputHandler - { - readonly World world; - public DefaultInputHandler( World world ) - { - this.world = world; - } - - public void ModifierKeys( Modifiers mods ) - { - Game.HandleModifierKeys( mods ); - } - - public void OnKeyInput( KeyInput input ) - { - Sync.CheckSyncUnchanged( world, () => - { - Widget.HandleKeyPress( input ); - } ); - } - - public void OnMouseInput( MouseInput input ) - { - Sync.CheckSyncUnchanged( world, () => - { - Widget.HandleInput( input ); - } ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Widgets; + +namespace OpenRA +{ + public class NullInputHandler : IInputHandler + { + // ignore all input + public void ModifierKeys( Modifiers mods ) { } + public void OnKeyInput( KeyInput input ) { } + public void OnMouseInput( MouseInput input ) { } + } + + public class DefaultInputHandler : IInputHandler + { + readonly World world; + public DefaultInputHandler( World world ) + { + this.world = world; + } + + public void ModifierKeys( Modifiers mods ) + { + Game.HandleModifierKeys( mods ); + } + + public void OnKeyInput( KeyInput input ) + { + Sync.CheckSyncUnchanged( world, () => + { + Widget.HandleKeyPress( input ); + } ); + } + + public void OnMouseInput( MouseInput input ) + { + Sync.CheckSyncUnchanged( world, () => + { + Widget.HandleInput( input ); + } ); + } + } +} diff --git a/OpenRA.Game/Map.cs b/OpenRA.Game/Map.cs index 71a6a2875a..d44a0a89cf 100644 --- a/OpenRA.Game/Map.cs +++ b/OpenRA.Game/Map.cs @@ -1,443 +1,443 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Security.Cryptography; -using OpenRA.FileFormats; -using System.Text; - -namespace OpenRA -{ - public class Map - { - protected IFolder Container; - public string Path {get; protected set;} - - // Yaml map data - public string Uid { get; protected set; } - [FieldLoader.Load] public int MapFormat; - [FieldLoader.Load] public bool Selectable; - [FieldLoader.Load] public bool UseAsShellmap; - [FieldLoader.Load] public string RequiresMod; - - [FieldLoader.Load] public string Title; - [FieldLoader.Load] public string Type = "Conquest"; - [FieldLoader.Load] public string Description; - [FieldLoader.Load] public string Author; - [FieldLoader.Load] public string Tileset; - - public Lazy> Actors; - - public int PlayerCount { get { return SpawnPoints.Count(); } } - public IEnumerable SpawnPoints { get { return Actors.Value.Values.Where(a => a.Type == "mpspawn").Select(a => a.InitDict.Get().value); } } - - [FieldLoader.Load] public Rectangle Bounds; - - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography; +using OpenRA.FileFormats; +using System.Text; + +namespace OpenRA +{ + public class Map + { + protected IFolder Container; + public string Path {get; protected set;} + // Yaml map data - public Dictionary Players = new Dictionary(); - public Lazy> Smudges; - - // Rules overrides - public List Rules = new List(); - - // Sequences overrides - public List Sequences = new List(); - - // Weapon overrides - public List Weapons = new List(); - - // Voices overrides - public List Voices = new List(); - - // Binary map data - public byte TileFormat = 1; - [FieldLoader.Load] public int2 MapSize; - - public Lazy[,]> MapTiles; - public Lazy[,]> MapResources; - public string [,] CustomTerrain; - - public Map() - { - // Do nothing; not a valid map (editor hack) - } - - public static Map FromTileset(string tileset) - { - var tile = OpenRA.Rules.TileSets[tileset].Templates.First(); - Map map = new Map() - { - Title = "Name your map here", - Description = "Describe your map here", - Author = "Your name here", - MapSize = new int2(1, 1), - Tileset = tileset, - MapResources = Lazy.New(() => new TileReference[1, 1]), - MapTiles = Lazy.New(() => new TileReference[1, 1] - { { new TileReference { - type = tile.Key, - index = (byte)0 } - } }), - Actors = Lazy.New(() => new Dictionary()), - Smudges = Lazy.New(() => new List()) - }; - - return map; - } - - class Format2ActorReference - { - public string Id = null; - public string Type = null; - public int2 Location = int2.Zero; - public string Owner = null; - } - - public Map(string path) - { - Path = path; - Container = FileSystem.OpenPackage(path, int.MaxValue); - var yaml = new MiniYaml( null, MiniYaml.FromStream(Container.GetContent("map.yaml")) ); - FieldLoader.Load(this, yaml); - Uid = ComputeHash(); - - // 'Simple' metadata - FieldLoader.Load( this, yaml ); - - // Support for formats 1-3 dropped 2011-02-11. - // Use release-20110207 to convert older maps to format 4 - if (MapFormat < 4) - throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, path)); - - - Actors = Lazy.New(() => - { - var ret = new Dictionary(); - // Load actors - foreach (var kv in yaml.NodesDict["Actors"].NodesDict) - ret.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.NodesDict)); - - // Add waypoint actors - - if (MapFormat < 5) - foreach( var wp in yaml.NodesDict[ "Waypoints" ].NodesDict ) - { - string[] loc = wp.Value.Value.Split( ',' ); - var a = new ActorReference("mpspawn"); - a.Add(new LocationInit(new int2( int.Parse( loc[ 0 ] ), int.Parse( loc[ 1 ] ) ))); - ret.Add(wp.Key, a); - } - - return ret; - }); - - // Load players - foreach (var kv in yaml.NodesDict["Players"].NodesDict) - { - var player = new PlayerReference(kv.Value); - Players.Add(player.Name, player); - } - - // Upgrade map to format 5 - if (MapFormat < 5) - { - // Define RequiresMod for map installer - RequiresMod = Game.CurrentMods.Keys.First(); - - var TopLeft = (int2)FieldLoader.GetValue( "", typeof(int2), yaml.NodesDict["TopLeft"].Value); - var BottomRight = (int2)FieldLoader.GetValue( "", typeof(int2), yaml.NodesDict["BottomRight"].Value); - Bounds = Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); - - // Creep player - foreach (var mp in Players.Where(p => !p.Value.NonCombatant && !p.Value.Enemies.Contains("Creeps"))) - mp.Value.Enemies = mp.Value.Enemies.Concat(new[] {"Creeps"}).ToArray(); - - Players.Add("Creeps", new PlayerReference - { - Name = "Creeps", - Race = "Random", - NonCombatant = true, - Enemies = Players.Keys.Where(k => k != "Neutral").ToArray() - }); - } - - /* hack: make some slots. */ - if (!Players.Any(p => p.Value.Playable)) - { - for (int index = 0; index < SpawnPoints.Count(); index++) - { - var p = new PlayerReference - { - Name = "Multi{0}".F(index), - Race = "Random", - Playable = true, - DefaultStartingUnits = true, - Enemies = new[]{"Creeps"} - }; - Players.Add(p.Name, p); - } - } - - // Smudges - Smudges = Lazy.New(() => - { - var ret = new List(); - foreach (var kv in yaml.NodesDict["Smudges"].NodesDict) - { - string[] vals = kv.Key.Split(' '); - string[] loc = vals[1].Split(','); - ret.Add(new SmudgeReference(vals[0], new int2(int.Parse(loc[0]), int.Parse(loc[1])), int.Parse(vals[2]))); - } - - return ret; - }); - - - // Rules - Rules = yaml.NodesDict["Rules"].Nodes; - - // Sequences - Sequences = (yaml.NodesDict.ContainsKey("Sequences")) ? yaml.NodesDict["Sequences"].Nodes : new List(); - - // Weapons - Weapons = (yaml.NodesDict.ContainsKey("Weapons")) ? yaml.NodesDict["Weapons"].Nodes : new List(); - - // Voices - Voices = (yaml.NodesDict.ContainsKey("Voices")) ? yaml.NodesDict["Voices"].Nodes : new List(); - - CustomTerrain = new string[MapSize.X, MapSize.Y]; - - MapTiles = Lazy.New(() => LoadMapTiles()); - MapResources = Lazy.New(() => LoadResourceTiles()); - } - - public void Save(string toPath) - { + public string Uid { get; protected set; } + [FieldLoader.Load] public int MapFormat; + [FieldLoader.Load] public bool Selectable; + [FieldLoader.Load] public bool UseAsShellmap; + [FieldLoader.Load] public string RequiresMod; + + [FieldLoader.Load] public string Title; + [FieldLoader.Load] public string Type = "Conquest"; + [FieldLoader.Load] public string Description; + [FieldLoader.Load] public string Author; + [FieldLoader.Load] public string Tileset; + + public Lazy> Actors; + + public int PlayerCount { get { return SpawnPoints.Count(); } } + public IEnumerable SpawnPoints { get { return Actors.Value.Values.Where(a => a.Type == "mpspawn").Select(a => a.InitDict.Get().value); } } + + [FieldLoader.Load] public Rectangle Bounds; + + + // Yaml map data + public Dictionary Players = new Dictionary(); + public Lazy> Smudges; + + // Rules overrides + public List Rules = new List(); + + // Sequences overrides + public List Sequences = new List(); + + // Weapon overrides + public List Weapons = new List(); + + // Voices overrides + public List Voices = new List(); + + // Binary map data + public byte TileFormat = 1; + [FieldLoader.Load] public int2 MapSize; + + public Lazy[,]> MapTiles; + public Lazy[,]> MapResources; + public string [,] CustomTerrain; + + public Map() + { + // Do nothing; not a valid map (editor hack) + } + + public static Map FromTileset(string tileset) + { + var tile = OpenRA.Rules.TileSets[tileset].Templates.First(); + Map map = new Map() + { + Title = "Name your map here", + Description = "Describe your map here", + Author = "Your name here", + MapSize = new int2(1, 1), + Tileset = tileset, + MapResources = Lazy.New(() => new TileReference[1, 1]), + MapTiles = Lazy.New(() => new TileReference[1, 1] + { { new TileReference { + type = tile.Key, + index = (byte)0 } + } }), + Actors = Lazy.New(() => new Dictionary()), + Smudges = Lazy.New(() => new List()) + }; + + return map; + } + + class Format2ActorReference + { + public string Id = null; + public string Type = null; + public int2 Location = int2.Zero; + public string Owner = null; + } + + public Map(string path) + { + Path = path; + Container = FileSystem.OpenPackage(path, int.MaxValue); + var yaml = new MiniYaml( null, MiniYaml.FromStream(Container.GetContent("map.yaml")) ); + FieldLoader.Load(this, yaml); + Uid = ComputeHash(); + + // 'Simple' metadata + FieldLoader.Load( this, yaml ); + + // Support for formats 1-3 dropped 2011-02-11. + // Use release-20110207 to convert older maps to format 4 + if (MapFormat < 4) + throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, path)); + + + Actors = Lazy.New(() => + { + var ret = new Dictionary(); + // Load actors + foreach (var kv in yaml.NodesDict["Actors"].NodesDict) + ret.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.NodesDict)); + + // Add waypoint actors + + if (MapFormat < 5) + foreach( var wp in yaml.NodesDict[ "Waypoints" ].NodesDict ) + { + string[] loc = wp.Value.Value.Split( ',' ); + var a = new ActorReference("mpspawn"); + a.Add(new LocationInit(new int2( int.Parse( loc[ 0 ] ), int.Parse( loc[ 1 ] ) ))); + ret.Add(wp.Key, a); + } + + return ret; + }); + + // Load players + foreach (var kv in yaml.NodesDict["Players"].NodesDict) + { + var player = new PlayerReference(kv.Value); + Players.Add(player.Name, player); + } + + // Upgrade map to format 5 + if (MapFormat < 5) + { + // Define RequiresMod for map installer + RequiresMod = Game.CurrentMods.Keys.First(); + + var TopLeft = (int2)FieldLoader.GetValue( "", typeof(int2), yaml.NodesDict["TopLeft"].Value); + var BottomRight = (int2)FieldLoader.GetValue( "", typeof(int2), yaml.NodesDict["BottomRight"].Value); + Bounds = Rectangle.FromLTRB(TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y); + + // Creep player + foreach (var mp in Players.Where(p => !p.Value.NonCombatant && !p.Value.Enemies.Contains("Creeps"))) + mp.Value.Enemies = mp.Value.Enemies.Concat(new[] {"Creeps"}).ToArray(); + + Players.Add("Creeps", new PlayerReference + { + Name = "Creeps", + Race = "Random", + NonCombatant = true, + Enemies = Players.Keys.Where(k => k != "Neutral").ToArray() + }); + } + + /* hack: make some slots. */ + if (!Players.Any(p => p.Value.Playable)) + { + for (int index = 0; index < SpawnPoints.Count(); index++) + { + var p = new PlayerReference + { + Name = "Multi{0}".F(index), + Race = "Random", + Playable = true, + DefaultStartingUnits = true, + Enemies = new[]{"Creeps"} + }; + Players.Add(p.Name, p); + } + } + + // Smudges + Smudges = Lazy.New(() => + { + var ret = new List(); + foreach (var kv in yaml.NodesDict["Smudges"].NodesDict) + { + string[] vals = kv.Key.Split(' '); + string[] loc = vals[1].Split(','); + ret.Add(new SmudgeReference(vals[0], new int2(int.Parse(loc[0]), int.Parse(loc[1])), int.Parse(vals[2]))); + } + + return ret; + }); + + + // Rules + Rules = yaml.NodesDict["Rules"].Nodes; + + // Sequences + Sequences = (yaml.NodesDict.ContainsKey("Sequences")) ? yaml.NodesDict["Sequences"].Nodes : new List(); + + // Weapons + Weapons = (yaml.NodesDict.ContainsKey("Weapons")) ? yaml.NodesDict["Weapons"].Nodes : new List(); + + // Voices + Voices = (yaml.NodesDict.ContainsKey("Voices")) ? yaml.NodesDict["Voices"].Nodes : new List(); + + CustomTerrain = new string[MapSize.X, MapSize.Y]; + + MapTiles = Lazy.New(() => LoadMapTiles()); + MapResources = Lazy.New(() => LoadResourceTiles()); + } + + public void Save(string toPath) + { MapFormat = 5; - var root = new List(); - var fields = new string[] - { - "Selectable", - "MapFormat", - "RequiresMod", - "Title", - "Description", - "Author", - "Tileset", - "MapSize", - "Bounds", - "UseAsShellmap", - "Type", - "StartPoints" - }; - - foreach (var field in fields) - { - var f = this.GetType().GetField(field); - if (f.GetValue(this) == null) continue; + var root = new List(); + var fields = new string[] + { + "Selectable", + "MapFormat", + "RequiresMod", + "Title", + "Description", + "Author", + "Tileset", + "MapSize", + "Bounds", + "UseAsShellmap", + "Type", + "StartPoints" + }; + + foreach (var field in fields) + { + var f = this.GetType().GetField(field); + if (f.GetValue(this) == null) continue; root.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) ); - } - - root.Add( new MiniYamlNode( "Players", null, - Players.Select( p => new MiniYamlNode( - "PlayerReference@{0}".F( p.Key ), - FieldSaver.Save( p.Value ) ) ).ToList() ) ); - - root.Add( new MiniYamlNode( "Actors", null, - Actors.Value.Select( x => new MiniYamlNode( - x.Key, - x.Value.Save() ) ).ToList() ) ); - - root.Add(new MiniYamlNode("Smudges", MiniYaml.FromList( Smudges.Value ))); - root.Add(new MiniYamlNode("Rules", null, Rules)); - root.Add(new MiniYamlNode("Sequences", null, Sequences)); - root.Add(new MiniYamlNode("Weapons", null, Weapons)); - root.Add(new MiniYamlNode("Voices", null, Voices)); - - Dictionary entries = new Dictionary(); - entries.Add("map.bin", SaveBinaryData()); - var s = root.WriteToString(); - entries.Add("map.yaml", Encoding.UTF8.GetBytes(s)); - - // Saving the map to a new location - if (toPath != Path) - { - Path = toPath; - - // Create a new map package - // TODO: Add other files (resources, rules) to the entries list - Container = FileSystem.CreatePackage(Path, int.MaxValue, entries); - } - - // Update existing package - Container.Write(entries); - } - - static byte ReadByte(Stream s) - { - int ret = s.ReadByte(); - if (ret == -1) - throw new NotImplementedException(); - return (byte)ret; - } - - static ushort ReadWord(Stream s) - { - ushort ret = ReadByte(s); - ret |= (ushort)(ReadByte(s) << 8); - - return ret; - } - - public TileReference[,] LoadMapTiles() - { - var tiles = new TileReference[MapSize.X, MapSize.Y]; - using (var dataStream = Container.GetContent("map.bin")) - { - if (ReadByte(dataStream) != 1) - throw new InvalidDataException("Unknown binary map format"); - - // Load header info - var width = ReadWord(dataStream); - var height = ReadWord(dataStream); - - if (width != MapSize.X || height != MapSize.Y) - throw new InvalidDataException("Invalid tile data"); - - - // Load tile data - for (int i = 0; i < MapSize.X; i++) - for (int j = 0; j < MapSize.Y; j++) - { - ushort tile = ReadWord(dataStream); - byte index = ReadByte(dataStream); - if (index == byte.MaxValue) - index = (byte)(i % 4 + (j % 4) * 4); - - tiles[i, j] = new TileReference(tile, index); - } - } - return tiles; - } - - public TileReference[,] LoadResourceTiles() - { - var resources = new TileReference[MapSize.X, MapSize.Y]; - - using (var dataStream = Container.GetContent("map.bin")) - { - if (ReadByte(dataStream) != 1) + } + + root.Add( new MiniYamlNode( "Players", null, + Players.Select( p => new MiniYamlNode( + "PlayerReference@{0}".F( p.Key ), + FieldSaver.Save( p.Value ) ) ).ToList() ) ); + + root.Add( new MiniYamlNode( "Actors", null, + Actors.Value.Select( x => new MiniYamlNode( + x.Key, + x.Value.Save() ) ).ToList() ) ); + + root.Add(new MiniYamlNode("Smudges", MiniYaml.FromList( Smudges.Value ))); + root.Add(new MiniYamlNode("Rules", null, Rules)); + root.Add(new MiniYamlNode("Sequences", null, Sequences)); + root.Add(new MiniYamlNode("Weapons", null, Weapons)); + root.Add(new MiniYamlNode("Voices", null, Voices)); + + Dictionary entries = new Dictionary(); + entries.Add("map.bin", SaveBinaryData()); + var s = root.WriteToString(); + entries.Add("map.yaml", Encoding.UTF8.GetBytes(s)); + + // Saving the map to a new location + if (toPath != Path) + { + Path = toPath; + + // Create a new map package + // TODO: Add other files (resources, rules) to the entries list + Container = FileSystem.CreatePackage(Path, int.MaxValue, entries); + } + + // Update existing package + Container.Write(entries); + } + + static byte ReadByte(Stream s) + { + int ret = s.ReadByte(); + if (ret == -1) + throw new NotImplementedException(); + return (byte)ret; + } + + static ushort ReadWord(Stream s) + { + ushort ret = ReadByte(s); + ret |= (ushort)(ReadByte(s) << 8); + + return ret; + } + + public TileReference[,] LoadMapTiles() + { + var tiles = new TileReference[MapSize.X, MapSize.Y]; + using (var dataStream = Container.GetContent("map.bin")) + { + if (ReadByte(dataStream) != 1) throw new InvalidDataException("Unknown binary map format"); - // Load header info - var width = ReadWord(dataStream); - var height = ReadWord(dataStream); - - if (width != MapSize.X || height != MapSize.Y) - throw new InvalidDataException("Invalid tile data"); - - // Skip past tile data - for (var i = 0; i < 3*MapSize.X*MapSize.Y; i++) - ReadByte(dataStream); - - // Load resource data - for (int i = 0; i < MapSize.X; i++) - for (int j = 0; j < MapSize.Y; j++) - { - byte type = ReadByte(dataStream); - byte index = ReadByte(dataStream); - resources[i, j] = new TileReference(type, index); - } - } - return resources; - } - - public byte[] SaveBinaryData() - { - MemoryStream dataStream = new MemoryStream(); - using (var writer = new BinaryWriter(dataStream)) - { - // File header consists of a version byte, followed by 2 ushorts for width and height - writer.Write(TileFormat); - writer.Write((ushort)MapSize.X); - writer.Write((ushort)MapSize.Y); - - // Tile data - for (int i = 0; i < MapSize.X; i++) - for (int j = 0; j < MapSize.Y; j++) - { - writer.Write(MapTiles.Value[i, j].type); - var PickAny = OpenRA.Rules.TileSets[Tileset].Templates[MapTiles.Value[i, j].type].PickAny; - writer.Write(PickAny ? (byte)(i % 4 + (j % 4) * 4) : MapTiles.Value[i, j].index); - } - - // Resource data - for (int i = 0; i < MapSize.X; i++) - for (int j = 0; j < MapSize.Y; j++) - { - writer.Write(MapResources.Value[i, j].type); - writer.Write(MapResources.Value[i, j].index); - } - } - return dataStream.ToArray(); - } - - public bool IsInMap(int2 xy) - { - return IsInMap(xy.X, xy.Y); - } - - public bool IsInMap(int x, int y) - { - return Bounds.Contains(x,y); - } - - static T[,] ResizeArray(T[,] ts, T t, int width, int height) - { - var result = new T[width, height]; - for (var i = 0; i < width; i++) - for (var j = 0; j < height; j++) - result[i, j] = i <= ts.GetUpperBound(0) && j <= ts.GetUpperBound(1) - ? ts[i, j] : t; - return result; - } - - public void Resize(int width, int height) // editor magic. - { - MapTiles = Lazy.New(() => ResizeArray(MapTiles.Value, MapTiles.Value[0, 0], width, height)); - MapResources = Lazy.New(() => ResizeArray(MapResources.Value, MapResources.Value[0, 0], width, height)); - MapSize = new int2(width, height); - } - - public void ResizeCordon(int left, int top, int right, int bottom) - { - Bounds = Rectangle.FromLTRB(left, top, right, bottom); - } - - string ComputeHash() - { - // UID is calculated by taking an SHA1 of the yaml and binary data - // Read the relevant data into a buffer - var data = Container.GetContent("map.yaml").ReadAllBytes() - .Concat(Container.GetContent("map.bin").ReadAllBytes()).ToArray(); - - // Take the SHA1 - using (var csp = SHA1.Create()) - return new string(csp.ComputeHash(data).SelectMany(a => a.ToString("x2")).ToArray()); - } - } + // Load header info + var width = ReadWord(dataStream); + var height = ReadWord(dataStream); + + if (width != MapSize.X || height != MapSize.Y) + throw new InvalidDataException("Invalid tile data"); + + + // Load tile data + for (int i = 0; i < MapSize.X; i++) + for (int j = 0; j < MapSize.Y; j++) + { + ushort tile = ReadWord(dataStream); + byte index = ReadByte(dataStream); + if (index == byte.MaxValue) + index = (byte)(i % 4 + (j % 4) * 4); + + tiles[i, j] = new TileReference(tile, index); + } + } + return tiles; + } + + public TileReference[,] LoadResourceTiles() + { + var resources = new TileReference[MapSize.X, MapSize.Y]; + + using (var dataStream = Container.GetContent("map.bin")) + { + if (ReadByte(dataStream) != 1) + throw new InvalidDataException("Unknown binary map format"); + + // Load header info + var width = ReadWord(dataStream); + var height = ReadWord(dataStream); + + if (width != MapSize.X || height != MapSize.Y) + throw new InvalidDataException("Invalid tile data"); + + // Skip past tile data + for (var i = 0; i < 3*MapSize.X*MapSize.Y; i++) + ReadByte(dataStream); + + // Load resource data + for (int i = 0; i < MapSize.X; i++) + for (int j = 0; j < MapSize.Y; j++) + { + byte type = ReadByte(dataStream); + byte index = ReadByte(dataStream); + resources[i, j] = new TileReference(type, index); + } + } + return resources; + } + + public byte[] SaveBinaryData() + { + MemoryStream dataStream = new MemoryStream(); + using (var writer = new BinaryWriter(dataStream)) + { + // File header consists of a version byte, followed by 2 ushorts for width and height + writer.Write(TileFormat); + writer.Write((ushort)MapSize.X); + writer.Write((ushort)MapSize.Y); + + // Tile data + for (int i = 0; i < MapSize.X; i++) + for (int j = 0; j < MapSize.Y; j++) + { + writer.Write(MapTiles.Value[i, j].type); + var PickAny = OpenRA.Rules.TileSets[Tileset].Templates[MapTiles.Value[i, j].type].PickAny; + writer.Write(PickAny ? (byte)(i % 4 + (j % 4) * 4) : MapTiles.Value[i, j].index); + } + + // Resource data + for (int i = 0; i < MapSize.X; i++) + for (int j = 0; j < MapSize.Y; j++) + { + writer.Write(MapResources.Value[i, j].type); + writer.Write(MapResources.Value[i, j].index); + } + } + return dataStream.ToArray(); + } + + public bool IsInMap(int2 xy) + { + return IsInMap(xy.X, xy.Y); + } + + public bool IsInMap(int x, int y) + { + return Bounds.Contains(x,y); + } + + static T[,] ResizeArray(T[,] ts, T t, int width, int height) + { + var result = new T[width, height]; + for (var i = 0; i < width; i++) + for (var j = 0; j < height; j++) + result[i, j] = i <= ts.GetUpperBound(0) && j <= ts.GetUpperBound(1) + ? ts[i, j] : t; + return result; + } + + public void Resize(int width, int height) // editor magic. + { + MapTiles = Lazy.New(() => ResizeArray(MapTiles.Value, MapTiles.Value[0, 0], width, height)); + MapResources = Lazy.New(() => ResizeArray(MapResources.Value, MapResources.Value[0, 0], width, height)); + MapSize = new int2(width, height); + } + + public void ResizeCordon(int left, int top, int right, int bottom) + { + Bounds = Rectangle.FromLTRB(left, top, right, bottom); + } + + string ComputeHash() + { + // UID is calculated by taking an SHA1 of the yaml and binary data + // Read the relevant data into a buffer + var data = Container.GetContent("map.yaml").ReadAllBytes() + .Concat(Container.GetContent("map.bin").ReadAllBytes()).ToArray(); + + // Take the SHA1 + using (var csp = SHA1.Create()) + return new string(csp.ComputeHash(data).SelectMany(a => a.ToString("x2")).ToArray()); + } + } } diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index 2b3af578ca..752447b4ae 100755 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Game/Network/Connection.cs b/OpenRA.Game/Network/Connection.cs index 97fb39e0de..f9889dc44a 100755 --- a/OpenRA.Game/Network/Connection.cs +++ b/OpenRA.Game/Network/Connection.cs @@ -1,210 +1,210 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Sockets; -using System.Threading; -using OpenRA.Server; -using OpenRA.Support; - -namespace OpenRA.Network -{ - public enum ConnectionState - { - PreConnecting, - NotConnected, - Connecting, - Connected, - } - - public interface IConnection : IDisposable - { - int LocalClientId { get; } - ConnectionState ConnectionState { get; } - void Send( int frame, List orders ); - void SendImmediate( List orders ); - void SendSync( int frame, byte[] syncData ); - void Receive( Action packetFn ); - } - - class EchoConnection : IConnection - { - protected struct ReceivedPacket - { - public int FromClient; - public byte[] Data; - } - protected List receivedPackets = new List(); - - public virtual int LocalClientId - { - get { return 1; } - } - - public virtual ConnectionState ConnectionState - { - get { return ConnectionState.PreConnecting; } - } - - public virtual void Send( int frame, List orders ) - { - var ms = new MemoryStream(); - ms.Write( BitConverter.GetBytes( frame ) ); - foreach( var o in orders ) - ms.Write( o ); - Send( ms.ToArray() ); - } - - public virtual void SendImmediate( List orders ) - { - var ms = new MemoryStream(); - ms.Write( BitConverter.GetBytes( (int)0 ) ); - foreach( var o in orders ) - ms.Write( o ); - Send( ms.ToArray() ); - } - - public virtual void SendSync( int frame, byte[] syncData ) - { - var ms = new MemoryStream(); - ms.Write( BitConverter.GetBytes( frame ) ); - ms.Write( syncData ); - Send( ms.ToArray() ); - } - - protected virtual void Send( byte[] packet ) - { - if( packet.Length == 0 ) - throw new NotImplementedException(); - lock( this ) - receivedPackets.Add( new ReceivedPacket { FromClient = LocalClientId, Data = packet } ); - } - - public virtual void Receive( Action packetFn ) - { - List packets; - lock( this ) - { - packets = receivedPackets; - receivedPackets = new List(); - } - - foreach( var p in packets ) - packetFn( p.FromClient, p.Data ); - } - - public virtual void Dispose() { } - } - - class NetworkConnection : EchoConnection - { - TcpClient socket; - int clientId; - ConnectionState connectionState = ConnectionState.Connecting; - Thread t; - - public NetworkConnection( string host, int port ) - { - t = new Thread( _ => - { - try - { - socket = new TcpClient( host, port ); - socket.NoDelay = true; - var reader = new BinaryReader( socket.GetStream() ); - var serverProtocol = reader.ReadInt32(); - - if (ProtocolVersion.Version != serverProtocol) - throw new InvalidOperationException( - "Protocol version mismatch. Server={0} Client={1}" - .F(serverProtocol, ProtocolVersion.Version)); - - clientId = reader.ReadInt32(); - connectionState = ConnectionState.Connected; - - for( ; ; ) - { - var len = reader.ReadInt32(); - var client = reader.ReadInt32(); - var buf = reader.ReadBytes( len ); - if( len == 0 ) - throw new NotImplementedException(); - lock( this ) - receivedPackets.Add( new ReceivedPacket { FromClient = client, Data = buf } ); - } - } - catch { } - finally - { - connectionState = ConnectionState.NotConnected; - if( socket != null ) - socket.Close(); - } - } - ) { IsBackground = true }; - t.Start(); - } - - public override int LocalClientId { get { return clientId; } } - public override ConnectionState ConnectionState { get { return connectionState; } } - - List queuedSyncPackets = new List(); - - public override void SendSync( int frame, byte[] syncData ) - { - var ms = new MemoryStream(); - ms.Write( BitConverter.GetBytes( frame ) ); - ms.Write( syncData ); - queuedSyncPackets.Add( ms.ToArray() ); - } - - protected override void Send( byte[] packet ) - { - base.Send( packet ); - - try - { - var ms = new MemoryStream(); - ms.Write(BitConverter.GetBytes((int)packet.Length)); - ms.Write(packet); - foreach( var q in queuedSyncPackets ) - { - ms.Write( BitConverter.GetBytes( (int)q.Length ) ); - ms.Write( q ); - base.Send( q ); - } - queuedSyncPackets.Clear(); - ms.WriteTo(socket.GetStream()); - } - catch (SocketException) { /* drop this on the floor; we'll pick up the disconnect from the reader thread */ } - catch (ObjectDisposedException) { /* ditto */ } - catch (InvalidOperationException) { /* ditto */ } - } - - bool disposed = false; - - public override void Dispose () - { - if (disposed) return; - disposed = true; - GC.SuppressFinalize( this ); - - t.Abort(); - if (socket != null) - socket.Client.Close(); - using( new PerfSample( "Thread.Join" )) - t.Join(); - } - - ~NetworkConnection() { Dispose(); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Sockets; +using System.Threading; +using OpenRA.Server; +using OpenRA.Support; + +namespace OpenRA.Network +{ + public enum ConnectionState + { + PreConnecting, + NotConnected, + Connecting, + Connected, + } + + public interface IConnection : IDisposable + { + int LocalClientId { get; } + ConnectionState ConnectionState { get; } + void Send( int frame, List orders ); + void SendImmediate( List orders ); + void SendSync( int frame, byte[] syncData ); + void Receive( Action packetFn ); + } + + class EchoConnection : IConnection + { + protected struct ReceivedPacket + { + public int FromClient; + public byte[] Data; + } + protected List receivedPackets = new List(); + + public virtual int LocalClientId + { + get { return 1; } + } + + public virtual ConnectionState ConnectionState + { + get { return ConnectionState.PreConnecting; } + } + + public virtual void Send( int frame, List orders ) + { + var ms = new MemoryStream(); + ms.Write( BitConverter.GetBytes( frame ) ); + foreach( var o in orders ) + ms.Write( o ); + Send( ms.ToArray() ); + } + + public virtual void SendImmediate( List orders ) + { + var ms = new MemoryStream(); + ms.Write( BitConverter.GetBytes( (int)0 ) ); + foreach( var o in orders ) + ms.Write( o ); + Send( ms.ToArray() ); + } + + public virtual void SendSync( int frame, byte[] syncData ) + { + var ms = new MemoryStream(); + ms.Write( BitConverter.GetBytes( frame ) ); + ms.Write( syncData ); + Send( ms.ToArray() ); + } + + protected virtual void Send( byte[] packet ) + { + if( packet.Length == 0 ) + throw new NotImplementedException(); + lock( this ) + receivedPackets.Add( new ReceivedPacket { FromClient = LocalClientId, Data = packet } ); + } + + public virtual void Receive( Action packetFn ) + { + List packets; + lock( this ) + { + packets = receivedPackets; + receivedPackets = new List(); + } + + foreach( var p in packets ) + packetFn( p.FromClient, p.Data ); + } + + public virtual void Dispose() { } + } + + class NetworkConnection : EchoConnection + { + TcpClient socket; + int clientId; + ConnectionState connectionState = ConnectionState.Connecting; + Thread t; + + public NetworkConnection( string host, int port ) + { + t = new Thread( _ => + { + try + { + socket = new TcpClient( host, port ); + socket.NoDelay = true; + var reader = new BinaryReader( socket.GetStream() ); + var serverProtocol = reader.ReadInt32(); + + if (ProtocolVersion.Version != serverProtocol) + throw new InvalidOperationException( + "Protocol version mismatch. Server={0} Client={1}" + .F(serverProtocol, ProtocolVersion.Version)); + + clientId = reader.ReadInt32(); + connectionState = ConnectionState.Connected; + + for( ; ; ) + { + var len = reader.ReadInt32(); + var client = reader.ReadInt32(); + var buf = reader.ReadBytes( len ); + if( len == 0 ) + throw new NotImplementedException(); + lock( this ) + receivedPackets.Add( new ReceivedPacket { FromClient = client, Data = buf } ); + } + } + catch { } + finally + { + connectionState = ConnectionState.NotConnected; + if( socket != null ) + socket.Close(); + } + } + ) { IsBackground = true }; + t.Start(); + } + + public override int LocalClientId { get { return clientId; } } + public override ConnectionState ConnectionState { get { return connectionState; } } + + List queuedSyncPackets = new List(); + + public override void SendSync( int frame, byte[] syncData ) + { + var ms = new MemoryStream(); + ms.Write( BitConverter.GetBytes( frame ) ); + ms.Write( syncData ); + queuedSyncPackets.Add( ms.ToArray() ); + } + + protected override void Send( byte[] packet ) + { + base.Send( packet ); + + try + { + var ms = new MemoryStream(); + ms.Write(BitConverter.GetBytes((int)packet.Length)); + ms.Write(packet); + foreach( var q in queuedSyncPackets ) + { + ms.Write( BitConverter.GetBytes( (int)q.Length ) ); + ms.Write( q ); + base.Send( q ); + } + queuedSyncPackets.Clear(); + ms.WriteTo(socket.GetStream()); + } + catch (SocketException) { /* drop this on the floor; we'll pick up the disconnect from the reader thread */ } + catch (ObjectDisposedException) { /* ditto */ } + catch (InvalidOperationException) { /* ditto */ } + } + + bool disposed = false; + + public override void Dispose () + { + if (disposed) return; + disposed = true; + GC.SuppressFinalize( this ); + + t.Abort(); + if (socket != null) + socket.Client.Close(); + using( new PerfSample( "Thread.Join" )) + t.Join(); + } + + ~NetworkConnection() { Dispose(); } + } +} diff --git a/OpenRA.Game/Network/Handshake.cs b/OpenRA.Game/Network/Handshake.cs index a6e4b423f8..c5f7c32b67 100644 --- a/OpenRA.Game/Network/Handshake.cs +++ b/OpenRA.Game/Network/Handshake.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Game/Network/Order.cs b/OpenRA.Game/Network/Order.cs index 42c7ce1063..3c058e9579 100755 --- a/OpenRA.Game/Network/Order.cs +++ b/OpenRA.Game/Network/Order.cs @@ -1,227 +1,227 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.IO; -using System.Linq; -using OpenRA.Network; - -namespace OpenRA -{ - [Flags] - enum OrderFields : byte - { - TargetActor = 0x01, - TargetLocation = 0x02, - TargetString = 0x04, - Queued = 0x08, - ExtraLocation = 0x10, - } - - static class OrderFieldsExts - { - public static bool HasField(this OrderFields of, OrderFields f) - { - return (of & f) != 0; - } - } - - public sealed class Order - { - public readonly string OrderString; - public readonly Actor Subject; - public readonly bool Queued; - public Actor TargetActor; - public int2 TargetLocation; - public string TargetString; - public int2 ExtraLocation; - public bool IsImmediate; - - public Player Player { get { return Subject.Owner; } } - - Order(string orderString, Actor subject, - Actor targetActor, int2 targetLocation, string targetString, bool queued, int2 extraLocation) - { - this.OrderString = orderString; - this.Subject = subject; - this.TargetActor = targetActor; - this.TargetLocation = targetLocation; - this.TargetString = targetString; - this.Queued = queued; - this.ExtraLocation = extraLocation; - } - - // For scripting special powers - public Order() - : this(null, null, null, int2.Zero, null, false, int2.Zero) { } - - public Order(string orderString, Actor subject, bool queued) - : this(orderString, subject, null, int2.Zero, null, queued, int2.Zero) { } - - public Order(string orderstring, Order order) - : this(orderstring, order.Subject, order.TargetActor, order.TargetLocation, - order.TargetString, order.Queued, order.ExtraLocation) {} - - public byte[] Serialize() - { - if (IsImmediate) /* chat, whatever */ - { - var ret = new MemoryStream(); - var w = new BinaryWriter(ret); - w.Write((byte)0xfe); - w.Write(OrderString); - w.Write(TargetString); - return ret.ToArray(); - } - - switch (OrderString) - { - // Format: - // u8 : orderID. - // 0xFF: Full serialized order. - // varies: rest of order. - default: - // TODO: specific serializers for specific orders. - { - var ret = new MemoryStream(); - var w = new BinaryWriter(ret); - w.Write( (byte)0xFF ); - w.Write(OrderString); - w.Write(UIntFromActor(Subject)); - - OrderFields fields = 0; - if (TargetActor != null) fields |= OrderFields.TargetActor; - if (TargetLocation != int2.Zero) fields |= OrderFields.TargetLocation; - if (TargetString != null) fields |= OrderFields.TargetString; - if (Queued) fields |= OrderFields.Queued; - if (ExtraLocation != int2.Zero) fields |= OrderFields.ExtraLocation; - - w.Write((byte)fields); - - if (TargetActor != null) - w.Write(UIntFromActor(TargetActor)); - if (TargetLocation != int2.Zero) - w.Write(TargetLocation); - if (TargetString != null) - w.Write(TargetString); - if (ExtraLocation != int2.Zero) - w.Write(ExtraLocation); - - return ret.ToArray(); - } - } - } - - public static Order Deserialize(World world, BinaryReader r) - { - switch (r.ReadByte()) - { - case 0xFF: - { - var order = r.ReadString(); - var subjectId = r.ReadUInt32(); - var flags = (OrderFields)r.ReadByte(); - - var targetActorId = flags.HasField(OrderFields.TargetActor) ? r.ReadUInt32() : 0xffffffff; - var targetLocation = flags.HasField(OrderFields.TargetLocation) ? r.ReadInt2() : int2.Zero; - var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null; - var queued = flags.HasField(OrderFields.Queued); - var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero; - - Actor subject, targetActor; - if( !TryGetActorFromUInt( world, subjectId, out subject ) || !TryGetActorFromUInt( world, targetActorId, out targetActor ) ) - return null; - - return new Order( order, subject, targetActor, targetLocation, targetString, queued, extraLocation); - } - - case 0xfe: - { - var name = r.ReadString(); - var data = r.ReadString(); - - return new Order( name, null, false ) { IsImmediate = true, TargetString = data }; - } - - default: - throw new NotImplementedException(); - } - } - - public override string ToString() - { - return ("OrderString: \"{0}\" \n\t Subject: \"{1}\". \n\t TargetActor: \"{2}\" \n\t TargetLocation: {3}." + - "\n\t TargetString: \"{4}\".\n\t IsImmediate: {5}.\n\t Player(PlayerName): {6}\n").F( - OrderString, Subject, TargetActor != null ? TargetActor.Info.Name : null , TargetLocation, TargetString, IsImmediate, Player != null ? Player.PlayerName : null); - } - - static uint UIntFromActor(Actor a) - { - if (a == null) return 0xffffffff; - return a.ActorID; - } - - static bool TryGetActorFromUInt(World world, uint aID, out Actor ret ) - { - if( aID == 0xFFFFFFFF ) - { - ret = null; - return true; - } - else - { - foreach( var a in world.Actors.Where( x => x.ActorID == aID ) ) - { - ret = a; - return true; - } - ret = null; - return false; - } - } - - // Named constructors for Orders. - // Now that Orders are resolved by individual Actors, these are weird; you unpack orders manually, but not pack them. - public static Order Chat(string text) - { - return new Order("Chat", null, false) { IsImmediate = true, TargetString = text}; - } - - public static Order TeamChat(string text) - { - return new Order("TeamChat", null, false) { IsImmediate = true, TargetString = text }; - } - - public static Order HandshakeResponse(string text) - { - return new Order("HandshakeResponse", null, false) { IsImmediate = true, TargetString = text }; - } - - public static Order Command(string text) - { - return new Order("Command", null, false) { IsImmediate = true, TargetString = text }; - } - - public static Order StartProduction(Actor subject, string item, int count) - { - return new Order("StartProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item }; - } - - public static Order PauseProduction(Actor subject, string item, bool pause) - { - return new Order("PauseProduction", subject, false) { TargetLocation = new int2(pause ? 1 : 0, 0), TargetString = item }; - } - - public static Order CancelProduction(Actor subject, string item, int count) - { - return new Order("CancelProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item }; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.IO; +using System.Linq; +using OpenRA.Network; + +namespace OpenRA +{ + [Flags] + enum OrderFields : byte + { + TargetActor = 0x01, + TargetLocation = 0x02, + TargetString = 0x04, + Queued = 0x08, + ExtraLocation = 0x10, + } + + static class OrderFieldsExts + { + public static bool HasField(this OrderFields of, OrderFields f) + { + return (of & f) != 0; + } + } + + public sealed class Order + { + public readonly string OrderString; + public readonly Actor Subject; + public readonly bool Queued; + public Actor TargetActor; + public int2 TargetLocation; + public string TargetString; + public int2 ExtraLocation; + public bool IsImmediate; + + public Player Player { get { return Subject.Owner; } } + + Order(string orderString, Actor subject, + Actor targetActor, int2 targetLocation, string targetString, bool queued, int2 extraLocation) + { + this.OrderString = orderString; + this.Subject = subject; + this.TargetActor = targetActor; + this.TargetLocation = targetLocation; + this.TargetString = targetString; + this.Queued = queued; + this.ExtraLocation = extraLocation; + } + + // For scripting special powers + public Order() + : this(null, null, null, int2.Zero, null, false, int2.Zero) { } + + public Order(string orderString, Actor subject, bool queued) + : this(orderString, subject, null, int2.Zero, null, queued, int2.Zero) { } + + public Order(string orderstring, Order order) + : this(orderstring, order.Subject, order.TargetActor, order.TargetLocation, + order.TargetString, order.Queued, order.ExtraLocation) {} + + public byte[] Serialize() + { + if (IsImmediate) /* chat, whatever */ + { + var ret = new MemoryStream(); + var w = new BinaryWriter(ret); + w.Write((byte)0xfe); + w.Write(OrderString); + w.Write(TargetString); + return ret.ToArray(); + } + + switch (OrderString) + { + // Format: + // u8 : orderID. + // 0xFF: Full serialized order. + // varies: rest of order. + default: + // TODO: specific serializers for specific orders. + { + var ret = new MemoryStream(); + var w = new BinaryWriter(ret); + w.Write( (byte)0xFF ); + w.Write(OrderString); + w.Write(UIntFromActor(Subject)); + + OrderFields fields = 0; + if (TargetActor != null) fields |= OrderFields.TargetActor; + if (TargetLocation != int2.Zero) fields |= OrderFields.TargetLocation; + if (TargetString != null) fields |= OrderFields.TargetString; + if (Queued) fields |= OrderFields.Queued; + if (ExtraLocation != int2.Zero) fields |= OrderFields.ExtraLocation; + + w.Write((byte)fields); + + if (TargetActor != null) + w.Write(UIntFromActor(TargetActor)); + if (TargetLocation != int2.Zero) + w.Write(TargetLocation); + if (TargetString != null) + w.Write(TargetString); + if (ExtraLocation != int2.Zero) + w.Write(ExtraLocation); + + return ret.ToArray(); + } + } + } + + public static Order Deserialize(World world, BinaryReader r) + { + switch (r.ReadByte()) + { + case 0xFF: + { + var order = r.ReadString(); + var subjectId = r.ReadUInt32(); + var flags = (OrderFields)r.ReadByte(); + + var targetActorId = flags.HasField(OrderFields.TargetActor) ? r.ReadUInt32() : 0xffffffff; + var targetLocation = flags.HasField(OrderFields.TargetLocation) ? r.ReadInt2() : int2.Zero; + var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null; + var queued = flags.HasField(OrderFields.Queued); + var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero; + + Actor subject, targetActor; + if( !TryGetActorFromUInt( world, subjectId, out subject ) || !TryGetActorFromUInt( world, targetActorId, out targetActor ) ) + return null; + + return new Order( order, subject, targetActor, targetLocation, targetString, queued, extraLocation); + } + + case 0xfe: + { + var name = r.ReadString(); + var data = r.ReadString(); + + return new Order( name, null, false ) { IsImmediate = true, TargetString = data }; + } + + default: + throw new NotImplementedException(); + } + } + + public override string ToString() + { + return ("OrderString: \"{0}\" \n\t Subject: \"{1}\". \n\t TargetActor: \"{2}\" \n\t TargetLocation: {3}." + + "\n\t TargetString: \"{4}\".\n\t IsImmediate: {5}.\n\t Player(PlayerName): {6}\n").F( + OrderString, Subject, TargetActor != null ? TargetActor.Info.Name : null , TargetLocation, TargetString, IsImmediate, Player != null ? Player.PlayerName : null); + } + + static uint UIntFromActor(Actor a) + { + if (a == null) return 0xffffffff; + return a.ActorID; + } + + static bool TryGetActorFromUInt(World world, uint aID, out Actor ret ) + { + if( aID == 0xFFFFFFFF ) + { + ret = null; + return true; + } + else + { + foreach( var a in world.Actors.Where( x => x.ActorID == aID ) ) + { + ret = a; + return true; + } + ret = null; + return false; + } + } + + // Named constructors for Orders. + // Now that Orders are resolved by individual Actors, these are weird; you unpack orders manually, but not pack them. + public static Order Chat(string text) + { + return new Order("Chat", null, false) { IsImmediate = true, TargetString = text}; + } + + public static Order TeamChat(string text) + { + return new Order("TeamChat", null, false) { IsImmediate = true, TargetString = text }; + } + + public static Order HandshakeResponse(string text) + { + return new Order("HandshakeResponse", null, false) { IsImmediate = true, TargetString = text }; + } + + public static Order Command(string text) + { + return new Order("Command", null, false) { IsImmediate = true, TargetString = text }; + } + + public static Order StartProduction(Actor subject, string item, int count) + { + return new Order("StartProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item }; + } + + public static Order PauseProduction(Actor subject, string item, bool pause) + { + return new Order("PauseProduction", subject, false) { TargetLocation = new int2(pause ? 1 : 0, 0), TargetString = item }; + } + + public static Order CancelProduction(Actor subject, string item, int count) + { + return new Order("CancelProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item }; + } + } +} diff --git a/OpenRA.Game/Network/OrderIO.cs b/OpenRA.Game/Network/OrderIO.cs index 5ebf787222..40a6fed8d6 100755 --- a/OpenRA.Game/Network/OrderIO.cs +++ b/OpenRA.Game/Network/OrderIO.cs @@ -1,62 +1,62 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.IO; - -namespace OpenRA.Network -{ - public static class OrderIO - { - public static void Write(this Stream s, byte[] buf) - { - s.Write(buf, 0, buf.Length); - } - - public static List ToOrderList(this byte[] bytes, World world) - { - var ms = new MemoryStream(bytes, 4, bytes.Length - 4); - var reader = new BinaryReader(ms); - var ret = new List(); - while( ms.Position < ms.Length ) - { - var o = Order.Deserialize( world, reader ); - if( o != null ) - ret.Add( o ); - } - return ret; - } - - public static byte[] SerializeSync( this List sync ) - { - var ms = new MemoryStream(); - using( var writer = new BinaryWriter( ms ) ) - { - writer.Write( (byte)0x65 ); - foreach( var s in sync ) - writer.Write( s ); - } - return ms.ToArray(); - } - - public static int2 ReadInt2(this BinaryReader r) - { - var x = r.ReadInt32(); - var y = r.ReadInt32(); - return new int2(x, y); - } - - public static void Write(this BinaryWriter w, int2 p) - { - w.Write(p.X); - w.Write(p.Y); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.IO; + +namespace OpenRA.Network +{ + public static class OrderIO + { + public static void Write(this Stream s, byte[] buf) + { + s.Write(buf, 0, buf.Length); + } + + public static List ToOrderList(this byte[] bytes, World world) + { + var ms = new MemoryStream(bytes, 4, bytes.Length - 4); + var reader = new BinaryReader(ms); + var ret = new List(); + while( ms.Position < ms.Length ) + { + var o = Order.Deserialize( world, reader ); + if( o != null ) + ret.Add( o ); + } + return ret; + } + + public static byte[] SerializeSync( this List sync ) + { + var ms = new MemoryStream(); + using( var writer = new BinaryWriter( ms ) ) + { + writer.Write( (byte)0x65 ); + foreach( var s in sync ) + writer.Write( s ); + } + return ms.ToArray(); + } + + public static int2 ReadInt2(this BinaryReader r) + { + var x = r.ReadInt32(); + var y = r.ReadInt32(); + return new int2(x, y); + } + + public static void Write(this BinaryWriter w, int2 p) + { + w.Write(p.X); + w.Write(p.Y); + } + } +} diff --git a/OpenRA.Game/Network/OrderManager.cs b/OpenRA.Game/Network/OrderManager.cs index 44dc8ad93c..5dadc2a17a 100755 --- a/OpenRA.Game/Network/OrderManager.cs +++ b/OpenRA.Game/Network/OrderManager.cs @@ -1,198 +1,198 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using OpenRA.FileFormats; - -namespace OpenRA.Network -{ - public class OrderManager : IDisposable - { - readonly SyncReport syncReport; - readonly FrameData frameData = new FrameData(); - - public Session LobbyInfo = new Session( Game.Settings.Game.Mods ); - public Session.Client LocalClient { get { return LobbyInfo.ClientWithIndex( Connection.LocalClientId ); } } - public World world; - - public readonly string Host; - public readonly int Port; - public string ServerError; - - public int NetFrameNumber { get; private set; } - public int LocalFrameNumber; - public int FramesAhead = 0; - - public int LastTickTime = Environment.TickCount; - - public bool GameStarted { get { return NetFrameNumber != 0; } } - public IConnection Connection { get; private set; } - - public readonly int SyncHeaderSize = 9; - - List localOrders = new List(); - - public void StartGame() - { - if (GameStarted) return; - - NetFrameNumber = 1; - for( int i = NetFrameNumber ; i <= FramesAhead ; i++ ) - Connection.Send( i, new List() ); - } - - public OrderManager( string host, int port, IConnection conn ) - { - this.Host = host; - this.Port = port; - Connection = conn; - syncReport = new SyncReport( this ); - } - - public void IssueOrders( Order[] orders ) - { - foreach( var order in orders ) - IssueOrder( order ); - } - - public void IssueOrder( Order order ) - { - localOrders.Add( order ); - } - - public void TickImmediate() - { - var immediateOrders = localOrders.Where( o => o.IsImmediate ).ToList(); - if( immediateOrders.Count != 0 ) - Connection.SendImmediate( immediateOrders.Select( o => o.Serialize() ).ToList() ); - localOrders.RemoveAll( o => o.IsImmediate ); - - var immediatePackets = new List>(); - - Connection.Receive( - ( clientId, packet ) => - { - var frame = BitConverter.ToInt32( packet, 0 ); - if( packet.Length == 5 && packet[ 4 ] == 0xBF ) - frameData.ClientQuit( clientId, frame ); - else if( packet.Length >= 5 && packet[ 4 ] == 0x65 ) - CheckSync( packet ); - else if( frame == 0 ) - immediatePackets.Add( Pair.New( clientId, packet ) ); - else - frameData.AddFrameOrders( clientId, frame, packet ); - } ); - - foreach( var p in immediatePackets ) - foreach( var o in p.Second.ToOrderList( world ) ) - UnitOrders.ProcessOrder( this, world, p.First, o ); - } - - Dictionary syncForFrame = new Dictionary(); - - void CheckSync( byte[] packet ) - { - var frame = BitConverter.ToInt32(packet, 0); - byte[] existingSync; - if (syncForFrame.TryGetValue(frame, out existingSync)) - { - if (packet.Length != existingSync.Length) - { - syncReport.DumpSyncReport(frame); - OutOfSync(frame); - } - else - { - for (int i = 0; i < packet.Length; i++) - { - if (packet[i] != existingSync[i]) - { - syncReport.DumpSyncReport(frame); - - if (i < SyncHeaderSize) - OutOfSync(frame, "Tick"); - else - OutOfSync(frame, (i - SyncHeaderSize) / 4); - } - } - } - } - else - syncForFrame.Add(frame, packet); - } - - void OutOfSync(int frame, int index) - { - var orders = frameData.OrdersForFrame( world, frame ); - - // Invalid index - if (index >= orders.Count()) - OutOfSync(frame); - - throw new InvalidOperationException("Out of sync in frame {0}.\n {1}".F(frame, orders.ElementAt(index).Order.ToString())); - } - - void OutOfSync(int frame) - { - throw new InvalidOperationException("Out of sync in frame {0}.\n".F(frame)); - } - - void OutOfSync(int frame, string blame) - { - throw new InvalidOperationException("Out of sync in frame {0}: Blame {1}.\n".F(frame, blame)); - } - - public bool IsReadyForNextFrame - { - get { return NetFrameNumber >= 1 && frameData.IsReadyForFrame( NetFrameNumber ); } - } - - public void Tick() - { - if( !IsReadyForNextFrame ) - throw new InvalidOperationException(); - - Connection.Send( NetFrameNumber + FramesAhead, localOrders.Select( o => o.Serialize() ).ToList() ); - localOrders.Clear(); - - var sync = new List(); - sync.Add( world.SyncHash() ); - - foreach( var order in frameData.OrdersForFrame( world, NetFrameNumber) ) - { - UnitOrders.ProcessOrder( this, world, order.Client, order.Order ); - sync.Add( world.SyncHash() ); - } - - var ss = sync.SerializeSync(); - Connection.SendSync( NetFrameNumber, ss ); - - syncReport.UpdateSyncReport(); - - ++NetFrameNumber; - } - - bool disposed; - public void Dispose() - { - if (disposed) return; - - Connection.Dispose(); - - disposed = true; - GC.SuppressFinalize(this); - } - - ~OrderManager() { Dispose(); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using OpenRA.FileFormats; + +namespace OpenRA.Network +{ + public class OrderManager : IDisposable + { + readonly SyncReport syncReport; + readonly FrameData frameData = new FrameData(); + + public Session LobbyInfo = new Session( Game.Settings.Game.Mods ); + public Session.Client LocalClient { get { return LobbyInfo.ClientWithIndex( Connection.LocalClientId ); } } + public World world; + + public readonly string Host; + public readonly int Port; + public string ServerError; + + public int NetFrameNumber { get; private set; } + public int LocalFrameNumber; + public int FramesAhead = 0; + + public int LastTickTime = Environment.TickCount; + + public bool GameStarted { get { return NetFrameNumber != 0; } } + public IConnection Connection { get; private set; } + + public readonly int SyncHeaderSize = 9; + + List localOrders = new List(); + + public void StartGame() + { + if (GameStarted) return; + + NetFrameNumber = 1; + for( int i = NetFrameNumber ; i <= FramesAhead ; i++ ) + Connection.Send( i, new List() ); + } + + public OrderManager( string host, int port, IConnection conn ) + { + this.Host = host; + this.Port = port; + Connection = conn; + syncReport = new SyncReport( this ); + } + + public void IssueOrders( Order[] orders ) + { + foreach( var order in orders ) + IssueOrder( order ); + } + + public void IssueOrder( Order order ) + { + localOrders.Add( order ); + } + + public void TickImmediate() + { + var immediateOrders = localOrders.Where( o => o.IsImmediate ).ToList(); + if( immediateOrders.Count != 0 ) + Connection.SendImmediate( immediateOrders.Select( o => o.Serialize() ).ToList() ); + localOrders.RemoveAll( o => o.IsImmediate ); + + var immediatePackets = new List>(); + + Connection.Receive( + ( clientId, packet ) => + { + var frame = BitConverter.ToInt32( packet, 0 ); + if( packet.Length == 5 && packet[ 4 ] == 0xBF ) + frameData.ClientQuit( clientId, frame ); + else if( packet.Length >= 5 && packet[ 4 ] == 0x65 ) + CheckSync( packet ); + else if( frame == 0 ) + immediatePackets.Add( Pair.New( clientId, packet ) ); + else + frameData.AddFrameOrders( clientId, frame, packet ); + } ); + + foreach( var p in immediatePackets ) + foreach( var o in p.Second.ToOrderList( world ) ) + UnitOrders.ProcessOrder( this, world, p.First, o ); + } + + Dictionary syncForFrame = new Dictionary(); + + void CheckSync( byte[] packet ) + { + var frame = BitConverter.ToInt32(packet, 0); + byte[] existingSync; + if (syncForFrame.TryGetValue(frame, out existingSync)) + { + if (packet.Length != existingSync.Length) + { + syncReport.DumpSyncReport(frame); + OutOfSync(frame); + } + else + { + for (int i = 0; i < packet.Length; i++) + { + if (packet[i] != existingSync[i]) + { + syncReport.DumpSyncReport(frame); + + if (i < SyncHeaderSize) + OutOfSync(frame, "Tick"); + else + OutOfSync(frame, (i - SyncHeaderSize) / 4); + } + } + } + } + else + syncForFrame.Add(frame, packet); + } + + void OutOfSync(int frame, int index) + { + var orders = frameData.OrdersForFrame( world, frame ); + + // Invalid index + if (index >= orders.Count()) + OutOfSync(frame); + + throw new InvalidOperationException("Out of sync in frame {0}.\n {1}".F(frame, orders.ElementAt(index).Order.ToString())); + } + + void OutOfSync(int frame) + { + throw new InvalidOperationException("Out of sync in frame {0}.\n".F(frame)); + } + + void OutOfSync(int frame, string blame) + { + throw new InvalidOperationException("Out of sync in frame {0}: Blame {1}.\n".F(frame, blame)); + } + + public bool IsReadyForNextFrame + { + get { return NetFrameNumber >= 1 && frameData.IsReadyForFrame( NetFrameNumber ); } + } + + public void Tick() + { + if( !IsReadyForNextFrame ) + throw new InvalidOperationException(); + + Connection.Send( NetFrameNumber + FramesAhead, localOrders.Select( o => o.Serialize() ).ToList() ); + localOrders.Clear(); + + var sync = new List(); + sync.Add( world.SyncHash() ); + + foreach( var order in frameData.OrdersForFrame( world, NetFrameNumber) ) + { + UnitOrders.ProcessOrder( this, world, order.Client, order.Order ); + sync.Add( world.SyncHash() ); + } + + var ss = sync.SerializeSync(); + Connection.SendSync( NetFrameNumber, ss ); + + syncReport.UpdateSyncReport(); + + ++NetFrameNumber; + } + + bool disposed; + public void Dispose() + { + if (disposed) return; + + Connection.Dispose(); + + disposed = true; + GC.SuppressFinalize(this); + } + + ~OrderManager() { Dispose(); } + } +} diff --git a/OpenRA.Game/Network/Session.cs b/OpenRA.Game/Network/Session.cs index bf8e24b178..5d8dd9d6f6 100644 --- a/OpenRA.Game/Network/Session.cs +++ b/OpenRA.Game/Network/Session.cs @@ -1,122 +1,122 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; - -namespace OpenRA.Network -{ - public class Session - { - public List Clients = new List(); - public List Slots = new List(); - public Global GlobalSettings = new Global(); - - public Client ClientWithIndex(int clientID) - { - return Clients.SingleOrDefault(c => c.Index == clientID); - } - - public Client ClientInSlot(Slot slot) - { - return Clients.SingleOrDefault(c => c.Slot == slot.Index); - } - - public enum ClientState - { - NotReady, - Ready, - Disconnected = 1000 - } - - public class Client - { - public int Index; - public ColorRamp ColorRamp; - public string Country; - public int SpawnPoint; - public string Name; - public ClientState State; - public int Team; - public int Slot; // which slot we're in, or -1 for `observer`. - } - - public class Slot - { - public int Index; - public string Bot; // trait name of the bot to initialize in this slot, or null otherwise. - public bool Closed; // host has explicitly closed this slot. +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; + +namespace OpenRA.Network +{ + public class Session + { + public List Clients = new List(); + public List Slots = new List(); + public Global GlobalSettings = new Global(); + + public Client ClientWithIndex(int clientID) + { + return Clients.SingleOrDefault(c => c.Index == clientID); + } + + public Client ClientInSlot(Slot slot) + { + return Clients.SingleOrDefault(c => c.Slot == slot.Index); + } + + public enum ClientState + { + NotReady, + Ready, + Disconnected = 1000 + } + + public class Client + { + public int Index; + public ColorRamp ColorRamp; + public string Country; + public int SpawnPoint; + public string Name; + public ClientState State; + public int Team; + public int Slot; // which slot we're in, or -1 for `observer`. + } + + public class Slot + { + public int Index; + public string Bot; // trait name of the bot to initialize in this slot, or null otherwise. + public bool Closed; // host has explicitly closed this slot. public string MapPlayer; // playerReference to bind against. - public bool Spectator = false; // Spectating or not - // todo: more stuff? - } - - public class Global - { - public string ServerName; - public string Map; - public string[] Mods = { "ra" }; // mod names - public int OrderLatency = 3; - public int RandomSeed = 0; - public bool LockTeams = true; // don't allow team changes after game start. - public bool AllowCheats = false; - } - - public Session(string[] mods) - { - this.GlobalSettings.Mods = mods.ToArray(); - } - - public string Serialize() - { - var clientData = new List(); - - foreach (var client in Clients) - clientData.Add(new MiniYamlNode("Client@{0}".F(client.Index), FieldSaver.Save(client))); - - foreach (var slot in Slots) - clientData.Add(new MiniYamlNode("Slot@{0}".F(slot.Index), FieldSaver.Save(slot))); - - clientData.Add(new MiniYamlNode("GlobalSettings", FieldSaver.Save(GlobalSettings))); - - return clientData.WriteToString(); - } - - public static Session Deserialize(string data) - { - var session = new Session(Game.Settings.Game.Mods); - - var ys = MiniYaml.FromString(data); - foreach (var y in ys) - { - var yy = y.Key.Split('@'); - - switch (yy[0]) - { - case "GlobalSettings": - FieldLoader.Load(session.GlobalSettings, y.Value); - break; - - case "Client": - session.Clients.Add(FieldLoader.Load(y.Value)); - break; - - case "Slot": - session.Slots.Add(FieldLoader.Load(y.Value)); - break; - } - } - - return session; - } - } -} + public bool Spectator = false; // Spectating or not + // todo: more stuff? + } + + public class Global + { + public string ServerName; + public string Map; + public string[] Mods = { "ra" }; // mod names + public int OrderLatency = 3; + public int RandomSeed = 0; + public bool LockTeams = true; // don't allow team changes after game start. + public bool AllowCheats = false; + } + + public Session(string[] mods) + { + this.GlobalSettings.Mods = mods.ToArray(); + } + + public string Serialize() + { + var clientData = new List(); + + foreach (var client in Clients) + clientData.Add(new MiniYamlNode("Client@{0}".F(client.Index), FieldSaver.Save(client))); + + foreach (var slot in Slots) + clientData.Add(new MiniYamlNode("Slot@{0}".F(slot.Index), FieldSaver.Save(slot))); + + clientData.Add(new MiniYamlNode("GlobalSettings", FieldSaver.Save(GlobalSettings))); + + return clientData.WriteToString(); + } + + public static Session Deserialize(string data) + { + var session = new Session(Game.Settings.Game.Mods); + + var ys = MiniYaml.FromString(data); + foreach (var y in ys) + { + var yy = y.Key.Split('@'); + + switch (yy[0]) + { + case "GlobalSettings": + FieldLoader.Load(session.GlobalSettings, y.Value); + break; + + case "Client": + session.Clients.Add(FieldLoader.Load(y.Value)); + break; + + case "Slot": + session.Slots.Add(FieldLoader.Load(y.Value)); + break; + } + } + + return session; + } + } +} diff --git a/OpenRA.Game/Network/SyncReport.cs b/OpenRA.Game/Network/SyncReport.cs index f611a29367..36fb30dcaf 100755 --- a/OpenRA.Game/Network/SyncReport.cs +++ b/OpenRA.Game/Network/SyncReport.cs @@ -1,93 +1,93 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; - -namespace OpenRA.Network -{ - class SyncReport - { - readonly OrderManager orderManager; - const int numSyncReports = 5; - Report[] syncReports = new Report[numSyncReports]; - int curIndex = 0; - - public SyncReport( OrderManager orderManager ) - { - this.orderManager = orderManager; - for (var i = 0; i < numSyncReports; i++) - syncReports[i] = new SyncReport.Report(); - } - - internal void UpdateSyncReport() - { - GenerateSyncReport(syncReports[curIndex]); - curIndex = ++curIndex % numSyncReports; - } - - void GenerateSyncReport(Report report) - { - report.Frame = orderManager.NetFrameNumber; - report.SyncedRandom = orderManager.world.SharedRandom.Last; - report.Traits.Clear(); - foreach (var a in orderManager.world.Queries.WithTrait()) - { - var sync = Sync.CalculateSyncHash(a.Trait); - if (sync != 0) - report.Traits.Add(new TraitReport() - { - ActorID = a.Actor.ActorID, - Type = a.Actor.Info.Name, - Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.PlayerName, - Trait = a.Trait.GetType().Name, - Hash = sync - }); - } - } - - internal void DumpSyncReport(int frame) - { - foreach (var r in syncReports) - if (r.Frame == frame) - { - Log.Write("sync", "Sync for net frame {0} -------------", r.Frame); - Log.Write("sync", "SharedRandom: "+r.SyncedRandom); - Log.Write("sync", "Synced Traits:"); - foreach (var a in r.Traits) - Log.Write("sync", "\t {0} {1} {2} {3} ({4})".F( - a.ActorID, - a.Type, - a.Owner, - a.Trait, - a.Hash - )); - return; - } - Log.Write("sync", "No sync report available!"); - } - - class Report - { - public int Frame; - public int SyncedRandom; - public List Traits = new List(); - } - - struct TraitReport - { - public uint ActorID; - public string Type; - public string Owner; - public string Trait; - public int Hash; - } - - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Network +{ + class SyncReport + { + readonly OrderManager orderManager; + const int numSyncReports = 5; + Report[] syncReports = new Report[numSyncReports]; + int curIndex = 0; + + public SyncReport( OrderManager orderManager ) + { + this.orderManager = orderManager; + for (var i = 0; i < numSyncReports; i++) + syncReports[i] = new SyncReport.Report(); + } + + internal void UpdateSyncReport() + { + GenerateSyncReport(syncReports[curIndex]); + curIndex = ++curIndex % numSyncReports; + } + + void GenerateSyncReport(Report report) + { + report.Frame = orderManager.NetFrameNumber; + report.SyncedRandom = orderManager.world.SharedRandom.Last; + report.Traits.Clear(); + foreach (var a in orderManager.world.Queries.WithTrait()) + { + var sync = Sync.CalculateSyncHash(a.Trait); + if (sync != 0) + report.Traits.Add(new TraitReport() + { + ActorID = a.Actor.ActorID, + Type = a.Actor.Info.Name, + Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.PlayerName, + Trait = a.Trait.GetType().Name, + Hash = sync + }); + } + } + + internal void DumpSyncReport(int frame) + { + foreach (var r in syncReports) + if (r.Frame == frame) + { + Log.Write("sync", "Sync for net frame {0} -------------", r.Frame); + Log.Write("sync", "SharedRandom: "+r.SyncedRandom); + Log.Write("sync", "Synced Traits:"); + foreach (var a in r.Traits) + Log.Write("sync", "\t {0} {1} {2} {3} ({4})".F( + a.ActorID, + a.Type, + a.Owner, + a.Trait, + a.Hash + )); + return; + } + Log.Write("sync", "No sync report available!"); + } + + class Report + { + public int Frame; + public int SyncedRandom; + public List Traits = new List(); + } + + struct TraitReport + { + public uint ActorID; + public string Type; + public string Owner; + public string Trait; + public int Hash; + } + + } +} diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index 5db779d5be..53ae574771 100755 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -1,194 +1,194 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using System.Linq; -using OpenRA.Traits; -using System; -using OpenRA.FileFormats; - -namespace OpenRA.Network -{ - static class UnitOrders - { - static Player FindPlayerByClient(this World world, Session.Client c) - { - /* todo: this is still a hack. - * the cases we're trying to avoid are the extra players on the host's client -- Neutral, other MapPlayers, - * bots,.. */ - return world.players.Values.FirstOrDefault( - p => p.ClientIndex == c.Index && p.PlayerName == c.Name); - } - - public static void ProcessOrder(OrderManager orderManager, World world, int clientId, Order order) - { - if (world != null) - { - if (!world.WorldActor.TraitsImplementing().All(vo => - vo.OrderValidation(orderManager, world, clientId, order))) - return; - } - - switch (order.OrderString) - { - case "Chat": - { - var client = orderManager.LobbyInfo.ClientWithIndex(clientId); - if (client != null) - { - var player = world != null ? world.FindPlayerByClient(client) : null; - var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : ""; - Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString); - } - else - Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString); - break; - } - case "Disconnected": /* reports that the target player disconnected */ - { - var client = orderManager.LobbyInfo.ClientWithIndex(clientId); - if (client != null) - { - client.State = Session.ClientState.Disconnected; - } - break; - } - case "TeamChat": - { - var client = orderManager.LobbyInfo.ClientWithIndex(clientId); - - if (client != null) - { - if (world == null) - { - if (client.Team == orderManager.LocalClient.Team) - Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + " (Team)", - order.TargetString); - } - else - { - var player = world.FindPlayerByClient(client); - var display = player != null - && - (world.LocalPlayer != null && - player.Stances[world.LocalPlayer] == Stance.Ally - || player.WinState == WinState.Lost); - - if (display) - { - var suffix = (player != null && player.WinState == WinState.Lost) - ? " (Dead)" - : " (Team)"; - Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString); - } - } - } - break; - } - case "StartGame": - { - Game.AddChatLine(Color.White, "Server", "The game has started."); - Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map); - break; - } - - case "HandshakeRequest": - { - var request = HandshakeRequest.Deserialize(order.TargetString); - - // Check that the map exists on the client - if (!Game.modData.AvailableMaps.ContainsKey(request.Map)) - throw new InvalidOperationException("Missing map {0}".F(request.Map)); - - var info = new Session.Client() - { - Name = Game.Settings.Player.Name, - ColorRamp = Game.Settings.Player.ColorRamp, - Country = "random", - SpawnPoint = 0, - Team = 0, - State = Session.ClientState.NotReady - }; - - var localMods = orderManager.LobbyInfo.GlobalSettings.Mods.Select(m => "{0}@{1}".F(m,Mod.AllMods[m].Version)).ToArray(); - var response = new HandshakeResponse() - { - Client = info, - Mods = localMods, - Password = "Foo" - }; - - orderManager.IssueOrder(Order.HandshakeResponse(response.Serialize())); - break; - } - case "ServerError": - orderManager.ServerError = order.TargetString; - break; - case "SyncInfo": - { - orderManager.LobbyInfo = Session.Deserialize(order.TargetString); - - if (orderManager.FramesAhead != orderManager.LobbyInfo.GlobalSettings.OrderLatency - && !orderManager.GameStarted) - { - orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency; - Game.Debug( - "Order lag is now {0} frames.".F(orderManager.LobbyInfo.GlobalSettings.OrderLatency)); - } - Game.SyncLobbyInfo(); - break; - } - - case "SetStance": - { - if (Game.orderManager.LobbyInfo.GlobalSettings.LockTeams) - return; - - var targetPlayer = order.Player.World.players[order.TargetLocation.X]; - var newStance = (Stance)order.TargetLocation.Y; - - SetPlayerStance(world, order.Player, targetPlayer, newStance); - - Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F( - order.Player.PlayerName, targetPlayer.PlayerName, newStance)); - - // automatically declare war reciprocally - if (newStance == Stance.Enemy && targetPlayer.Stances[order.Player] == Stance.Ally) - { - SetPlayerStance(world, targetPlayer, order.Player, newStance); - Game.Debug("{0} has reciprocated",targetPlayer.PlayerName); - } - - break; - } - default: - { - if( !order.IsImmediate ) - { - var self = order.Subject; - var health = self.TraitOrDefault(); - if( health == null || !health.IsDead ) - foreach( var t in self.TraitsImplementing() ) - t.ResolveOrder( self, order ); - } - break; - } - } - } - - static void SetPlayerStance(World w, Player p, Player target, Stance s) - { - var oldStance = p.Stances[target]; - p.Stances[target] = s; - if (target == w.LocalPlayer) - w.WorldActor.Trait().UpdatePlayerStance(w, p, oldStance, s); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using System.Linq; +using OpenRA.Traits; +using System; +using OpenRA.FileFormats; + +namespace OpenRA.Network +{ + static class UnitOrders + { + static Player FindPlayerByClient(this World world, Session.Client c) + { + /* todo: this is still a hack. + * the cases we're trying to avoid are the extra players on the host's client -- Neutral, other MapPlayers, + * bots,.. */ + return world.players.Values.FirstOrDefault( + p => p.ClientIndex == c.Index && p.PlayerName == c.Name); + } + + public static void ProcessOrder(OrderManager orderManager, World world, int clientId, Order order) + { + if (world != null) + { + if (!world.WorldActor.TraitsImplementing().All(vo => + vo.OrderValidation(orderManager, world, clientId, order))) + return; + } + + switch (order.OrderString) + { + case "Chat": + { + var client = orderManager.LobbyInfo.ClientWithIndex(clientId); + if (client != null) + { + var player = world != null ? world.FindPlayerByClient(client) : null; + var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : ""; + Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString); + } + else + Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString); + break; + } + case "Disconnected": /* reports that the target player disconnected */ + { + var client = orderManager.LobbyInfo.ClientWithIndex(clientId); + if (client != null) + { + client.State = Session.ClientState.Disconnected; + } + break; + } + case "TeamChat": + { + var client = orderManager.LobbyInfo.ClientWithIndex(clientId); + + if (client != null) + { + if (world == null) + { + if (client.Team == orderManager.LocalClient.Team) + Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + " (Team)", + order.TargetString); + } + else + { + var player = world.FindPlayerByClient(client); + var display = player != null + && + (world.LocalPlayer != null && + player.Stances[world.LocalPlayer] == Stance.Ally + || player.WinState == WinState.Lost); + + if (display) + { + var suffix = (player != null && player.WinState == WinState.Lost) + ? " (Dead)" + : " (Team)"; + Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString); + } + } + } + break; + } + case "StartGame": + { + Game.AddChatLine(Color.White, "Server", "The game has started."); + Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map); + break; + } + + case "HandshakeRequest": + { + var request = HandshakeRequest.Deserialize(order.TargetString); + + // Check that the map exists on the client + if (!Game.modData.AvailableMaps.ContainsKey(request.Map)) + throw new InvalidOperationException("Missing map {0}".F(request.Map)); + + var info = new Session.Client() + { + Name = Game.Settings.Player.Name, + ColorRamp = Game.Settings.Player.ColorRamp, + Country = "random", + SpawnPoint = 0, + Team = 0, + State = Session.ClientState.NotReady + }; + + var localMods = orderManager.LobbyInfo.GlobalSettings.Mods.Select(m => "{0}@{1}".F(m,Mod.AllMods[m].Version)).ToArray(); + var response = new HandshakeResponse() + { + Client = info, + Mods = localMods, + Password = "Foo" + }; + + orderManager.IssueOrder(Order.HandshakeResponse(response.Serialize())); + break; + } + case "ServerError": + orderManager.ServerError = order.TargetString; + break; + case "SyncInfo": + { + orderManager.LobbyInfo = Session.Deserialize(order.TargetString); + + if (orderManager.FramesAhead != orderManager.LobbyInfo.GlobalSettings.OrderLatency + && !orderManager.GameStarted) + { + orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency; + Game.Debug( + "Order lag is now {0} frames.".F(orderManager.LobbyInfo.GlobalSettings.OrderLatency)); + } + Game.SyncLobbyInfo(); + break; + } + + case "SetStance": + { + if (Game.orderManager.LobbyInfo.GlobalSettings.LockTeams) + return; + + var targetPlayer = order.Player.World.players[order.TargetLocation.X]; + var newStance = (Stance)order.TargetLocation.Y; + + SetPlayerStance(world, order.Player, targetPlayer, newStance); + + Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F( + order.Player.PlayerName, targetPlayer.PlayerName, newStance)); + + // automatically declare war reciprocally + if (newStance == Stance.Enemy && targetPlayer.Stances[order.Player] == Stance.Ally) + { + SetPlayerStance(world, targetPlayer, order.Player, newStance); + Game.Debug("{0} has reciprocated",targetPlayer.PlayerName); + } + + break; + } + default: + { + if( !order.IsImmediate ) + { + var self = order.Subject; + var health = self.TraitOrDefault(); + if( health == null || !health.IsDead ) + foreach( var t in self.TraitsImplementing() ) + t.ResolveOrder( self, order ); + } + break; + } + } + } + + static void SetPlayerStance(World w, Player p, Player target, Stance s) + { + var oldStance = p.Stances[target]; + p.Stances[target] = s; + if (target == w.LocalPlayer) + w.WorldActor.Trait().UpdatePlayerStance(w, p, oldStance, s); + } + } +} diff --git a/OpenRA.Game/ObjectCreator.cs b/OpenRA.Game/ObjectCreator.cs index 2cfa94f59f..51b8fc2ae1 100755 --- a/OpenRA.Game/ObjectCreator.cs +++ b/OpenRA.Game/ObjectCreator.cs @@ -1,105 +1,105 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using OpenRA.FileFormats; - -namespace OpenRA -{ - public class ObjectCreator - { - Pair[] ModAssemblies; - - public ObjectCreator( Manifest manifest ) - { - // All the core namespaces - var asms = typeof(Game).Assembly.GetNamespaces() - .Select(c => Pair.New(typeof(Game).Assembly, c)) - .ToList(); - - // Namespaces from each mod assembly - foreach (var a in manifest.Assemblies) - { - var asm = Assembly.LoadFile(Path.GetFullPath(a)); - asms.AddRange(asm.GetNamespaces().Select(ns => Pair.New(asm, ns))); - } - - ModAssemblies = asms.ToArray(); - } - - public static Action MissingTypeAction = - s => { throw new InvalidOperationException("Cannot locate type: {0}".F(s)); }; - - public T CreateObject(string className) - { - return CreateObject( className, new Dictionary() ); - } - - public T CreateObject( string className, Dictionary args ) - { - foreach( var mod in ModAssemblies ) - { - var type = mod.First.GetType( mod.Second + "." + className, false ); - if( type == null ) continue; - var ctors = type.GetConstructors( BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance ).Where( x => x.HasAttribute() ).ToList(); - if( ctors.Count == 0 ) - return (T)CreateBasic( type ); - else if( ctors.Count == 1 ) - return (T)CreateUsingArgs( ctors[ 0 ], args ); - else - throw new InvalidOperationException( "ObjectCreator: UseCtor on multiple constructors; invalid." ); - } - MissingTypeAction(className); - return default(T); - } - - public object CreateBasic( Type type ) - { - return type.GetConstructor( new Type[ 0 ] ).Invoke( new object[ 0 ] ); - } - - public object CreateUsingArgs( ConstructorInfo ctor, Dictionary args ) - { - var p = ctor.GetParameters(); - var a = new object[ p.Length ]; - for( int i = 0 ; i < p.Length ; i++ ) - { - var attrs = p[ i ].GetCustomAttributes(); - if( attrs.Length != 1 ) throw new InvalidOperationException( "ObjectCreator: argument in [UseCtor] doesn't have [Param]" ); - var key = attrs[ 0 ].ParamName ?? p[i].Name; - if ( !args.ContainsKey(key) ) throw new InvalidOperationException("ObjectCreator: key `{0}' not found".F(key)); - a[ i ] = args[ key ]; - } - return ctor.Invoke( a ); - } - - [AttributeUsage( AttributeTargets.Parameter )] - public class ParamAttribute : Attribute - { - public string ParamName { get; private set; } - - public ParamAttribute() { } - - public ParamAttribute( string paramName ) - { - ParamName = paramName; - } - } - - [AttributeUsage( AttributeTargets.Constructor )] - public class UseCtorAttribute : Attribute - { - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using OpenRA.FileFormats; + +namespace OpenRA +{ + public class ObjectCreator + { + Pair[] ModAssemblies; + + public ObjectCreator( Manifest manifest ) + { + // All the core namespaces + var asms = typeof(Game).Assembly.GetNamespaces() + .Select(c => Pair.New(typeof(Game).Assembly, c)) + .ToList(); + + // Namespaces from each mod assembly + foreach (var a in manifest.Assemblies) + { + var asm = Assembly.LoadFile(Path.GetFullPath(a)); + asms.AddRange(asm.GetNamespaces().Select(ns => Pair.New(asm, ns))); + } + + ModAssemblies = asms.ToArray(); + } + + public static Action MissingTypeAction = + s => { throw new InvalidOperationException("Cannot locate type: {0}".F(s)); }; + + public T CreateObject(string className) + { + return CreateObject( className, new Dictionary() ); + } + + public T CreateObject( string className, Dictionary args ) + { + foreach( var mod in ModAssemblies ) + { + var type = mod.First.GetType( mod.Second + "." + className, false ); + if( type == null ) continue; + var ctors = type.GetConstructors( BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance ).Where( x => x.HasAttribute() ).ToList(); + if( ctors.Count == 0 ) + return (T)CreateBasic( type ); + else if( ctors.Count == 1 ) + return (T)CreateUsingArgs( ctors[ 0 ], args ); + else + throw new InvalidOperationException( "ObjectCreator: UseCtor on multiple constructors; invalid." ); + } + MissingTypeAction(className); + return default(T); + } + + public object CreateBasic( Type type ) + { + return type.GetConstructor( new Type[ 0 ] ).Invoke( new object[ 0 ] ); + } + + public object CreateUsingArgs( ConstructorInfo ctor, Dictionary args ) + { + var p = ctor.GetParameters(); + var a = new object[ p.Length ]; + for( int i = 0 ; i < p.Length ; i++ ) + { + var attrs = p[ i ].GetCustomAttributes(); + if( attrs.Length != 1 ) throw new InvalidOperationException( "ObjectCreator: argument in [UseCtor] doesn't have [Param]" ); + var key = attrs[ 0 ].ParamName ?? p[i].Name; + if ( !args.ContainsKey(key) ) throw new InvalidOperationException("ObjectCreator: key `{0}' not found".F(key)); + a[ i ] = args[ key ]; + } + return ctor.Invoke( a ); + } + + [AttributeUsage( AttributeTargets.Parameter )] + public class ParamAttribute : Attribute + { + public string ParamName { get; private set; } + + public ParamAttribute() { } + + public ParamAttribute( string paramName ) + { + ParamName = paramName; + } + } + + [AttributeUsage( AttributeTargets.Constructor )] + public class UseCtorAttribute : Attribute + { + } + } +} diff --git a/OpenRA.Game/Orders/GenericSelectTarget.cs b/OpenRA.Game/Orders/GenericSelectTarget.cs index 4e7a446458..81a70d6df6 100644 --- a/OpenRA.Game/Orders/GenericSelectTarget.cs +++ b/OpenRA.Game/Orders/GenericSelectTarget.cs @@ -1,94 +1,94 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Orders -{ - public class GenericSelectTarget : IOrderGenerator - { - readonly IEnumerable subjects; - readonly string order; - readonly string cursor; - readonly MouseButton expectedButton; - - public GenericSelectTarget(IEnumerable subjects, string order, string cursor, MouseButton button) - { - this.subjects = subjects; - this.order = order; - this.cursor = cursor; - expectedButton = button; - } - - public GenericSelectTarget(IEnumerable subjects, string order, string cursor) - : this(subjects, order, cursor, MouseButton.Left) - { - - } - - public GenericSelectTarget(Actor subject, string order, string cursor) - : this(new Actor[] { subject }, order, cursor) - { - - } - - public GenericSelectTarget(Actor subject, string order, string cursor, MouseButton button) - : this(new Actor[] { subject }, order, cursor, button) - { - - } - - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - if (mi.Button != expectedButton) - world.CancelInputMode(); - return OrderInner(world, xy, mi); - } - - IEnumerable OrderInner(World world, int2 xy, MouseInput mi) - { - if (mi.Button == expectedButton && world.Map.IsInMap(xy)) - { - world.CancelInputMode(); - foreach (var subject in subjects) - yield return new Order(order, subject, false) { TargetLocation = xy }; - } - } - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Orders +{ + public class GenericSelectTarget : IOrderGenerator + { + readonly IEnumerable subjects; + readonly string order; + readonly string cursor; + readonly MouseButton expectedButton; + + public GenericSelectTarget(IEnumerable subjects, string order, string cursor, MouseButton button) + { + this.subjects = subjects; + this.order = order; + this.cursor = cursor; + expectedButton = button; + } + + public GenericSelectTarget(IEnumerable subjects, string order, string cursor) + : this(subjects, order, cursor, MouseButton.Left) + { + + } + + public GenericSelectTarget(Actor subject, string order, string cursor) + : this(new Actor[] { subject }, order, cursor) + { + + } + + public GenericSelectTarget(Actor subject, string order, string cursor, MouseButton button) + : this(new Actor[] { subject }, order, cursor, button) + { + + } + + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + if (mi.Button != expectedButton) + world.CancelInputMode(); + return OrderInner(world, xy, mi); + } + + IEnumerable OrderInner(World world, int2 xy, MouseInput mi) + { + if (mi.Button == expectedButton && world.Map.IsInMap(xy)) + { + world.CancelInputMode(); + foreach (var subject in subjects) + yield return new Order(order, subject, false) { TargetLocation = xy }; + } + } + public virtual void Tick(World world) { } - public void RenderBeforeWorld(WorldRenderer wr, World world) { } - public void RenderAfterWorld(WorldRenderer wr, World world) { } - public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; } - } - - // variant that requires a tag trait (T) to be present on some actor owned - // by the activating player - public class GenericSelectTargetWithBuilding : GenericSelectTarget - { - public GenericSelectTargetWithBuilding(Actor subject, string order, string cursor) - : base(subject, order, cursor) { } - - public GenericSelectTargetWithBuilding(Actor subject, string order, string cursor, MouseButton button) - : base(subject, order, cursor, button) { } - - public override void Tick(World world) - { - var hasStructure = world.Queries.OwnedBy[world.LocalPlayer] - .WithTrait() - .Any(); - - if (!hasStructure) - world.CancelInputMode(); - } - } -} + public void RenderBeforeWorld(WorldRenderer wr, World world) { } + public void RenderAfterWorld(WorldRenderer wr, World world) { } + public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; } + } + + // variant that requires a tag trait (T) to be present on some actor owned + // by the activating player + public class GenericSelectTargetWithBuilding : GenericSelectTarget + { + public GenericSelectTargetWithBuilding(Actor subject, string order, string cursor) + : base(subject, order, cursor) { } + + public GenericSelectTargetWithBuilding(Actor subject, string order, string cursor, MouseButton button) + : base(subject, order, cursor, button) { } + + public override void Tick(World world) + { + var hasStructure = world.Queries.OwnedBy[world.LocalPlayer] + .WithTrait() + .Any(); + + if (!hasStructure) + world.CancelInputMode(); + } + } +} diff --git a/OpenRA.Game/Orders/IOrderGenerator.cs b/OpenRA.Game/Orders/IOrderGenerator.cs index 7a3d6165af..c72dfa07da 100644 --- a/OpenRA.Game/Orders/IOrderGenerator.cs +++ b/OpenRA.Game/Orders/IOrderGenerator.cs @@ -1,24 +1,24 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Graphics; - -namespace OpenRA -{ - public interface IOrderGenerator - { - IEnumerable Order(World world, int2 xy, MouseInput mi); - void Tick(World world); - void RenderBeforeWorld(WorldRenderer wr, World world); - void RenderAfterWorld(WorldRenderer wr, World world); - string GetCursor(World world, int2 xy, MouseInput mi); - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Graphics; + +namespace OpenRA +{ + public interface IOrderGenerator + { + IEnumerable Order(World world, int2 xy, MouseInput mi); + void Tick(World world); + void RenderBeforeWorld(WorldRenderer wr, World world); + void RenderAfterWorld(WorldRenderer wr, World world); + string GetCursor(World world, int2 xy, MouseInput mi); + } +} diff --git a/OpenRA.Game/Orders/UnitOrderGenerator.cs b/OpenRA.Game/Orders/UnitOrderGenerator.cs index 6c8272f316..709ae26850 100644 --- a/OpenRA.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRA.Game/Orders/UnitOrderGenerator.cs @@ -1,122 +1,122 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Orders { class UnitOrderGenerator : IOrderGenerator { - public IEnumerable Order( World world, int2 xy, MouseInput mi ) - { - var custom = world.WorldActor.TraitOrDefault(); - if (custom != null) - { - var customOrders = custom.Order(world, xy, mi); - - foreach (var o in customOrders) - yield return o; - } - else - { - var underCursor = world.FindUnitsAtMouse(mi.Location) - .Where(a => a.HasTrait()) - .OrderByDescending( - a => - a.Info.Traits.Contains() - ? a.Info.Traits.Get().Priority - : int.MinValue) - .FirstOrDefault(); - - var orders = world.Selection.Actors - .Select(a => OrderForUnit(a, xy, mi, underCursor)) - .Where(o => o != null) - .ToArray(); - - var actorsInvolved = orders.Select(o => o.self).Distinct(); - if (actorsInvolved.Any()) - yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor, false) - { - TargetString = string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()) - }; - - - foreach (var o in orders) - yield return CheckSameOrder(o.iot, o.trait.IssueOrder(o.self, o.iot, o.target, mi.Modifiers.HasModifier(Modifiers.Shift))); - } + public IEnumerable Order( World world, int2 xy, MouseInput mi ) + { + var custom = world.WorldActor.TraitOrDefault(); + if (custom != null) + { + var customOrders = custom.Order(world, xy, mi); + + foreach (var o in customOrders) + yield return o; + } + else + { + var underCursor = world.FindUnitsAtMouse(mi.Location) + .Where(a => a.HasTrait()) + .OrderByDescending( + a => + a.Info.Traits.Contains() + ? a.Info.Traits.Get().Priority + : int.MinValue) + .FirstOrDefault(); + + var orders = world.Selection.Actors + .Select(a => OrderForUnit(a, xy, mi, underCursor)) + .Where(o => o != null) + .ToArray(); + + var actorsInvolved = orders.Select(o => o.self).Distinct(); + if (actorsInvolved.Any()) + yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor, false) + { + TargetString = string.Join(",", actorsInvolved.Select(a => a.ActorID.ToString()).ToArray()) + }; + + + foreach (var o in orders) + yield return CheckSameOrder(o.iot, o.trait.IssueOrder(o.self, o.iot, o.target, mi.Modifiers.HasModifier(Modifiers.Shift))); + } } - public void Tick( World world ) - { - var custom = world.WorldActor.TraitOrDefault(); - if (custom != null) - { - custom.Tick(world); - } + public void Tick( World world ) + { + var custom = world.WorldActor.TraitOrDefault(); + if (custom != null) + { + custom.Tick(world); + } } - public void RenderBeforeWorld( WorldRenderer wr, World world ) - { - var custom = world.WorldActor.TraitOrDefault(); - if (custom != null) - { - custom.RenderBeforeWorld(wr, world); - return; + public void RenderBeforeWorld( WorldRenderer wr, World world ) + { + var custom = world.WorldActor.TraitOrDefault(); + if (custom != null) + { + custom.RenderBeforeWorld(wr, world); + return; } Game.Renderer.Flush(); } - public void RenderAfterWorld( WorldRenderer wr, World world ) - { - var custom = world.WorldActor.TraitOrDefault(); - if (custom != null) - { - custom.RenderAfterWorld(wr, world); - return; + public void RenderAfterWorld( WorldRenderer wr, World world ) + { + var custom = world.WorldActor.TraitOrDefault(); + if (custom != null) + { + custom.RenderAfterWorld(wr, world); + return; } Game.Renderer.Flush(); } - public string GetCursor( World world, int2 xy, MouseInput mi ) - { + public string GetCursor( World world, int2 xy, MouseInput mi ) + { bool useSelect = false; - - var custom = world.WorldActor.TraitOrDefault(); - if (custom != null) - { - return custom.GetCursor(world, xy, mi); + + var custom = world.WorldActor.TraitOrDefault(); + if (custom != null) + { + return custom.GetCursor(world, xy, mi); } var underCursor = world.FindUnitsAtMouse(mi.Location) .Where(a => a.HasTrait()) .OrderByDescending(a => a.Info.Traits.Contains() ? a.Info.Traits.Get().Priority : int.MinValue) - .FirstOrDefault(); - - - if (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()) - if (underCursor != null) + .FirstOrDefault(); + + + if (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()) + if (underCursor != null) useSelect = true; var orders = world.Selection.Actors .Select(a => OrderForUnit(a, xy, mi, underCursor)) .Where(o => o != null) - .ToArray(); - - if( orders.Length == 0 ) return (useSelect) ? "select" : "default"; - - return orders[0].cursor ?? ((useSelect) ? "select" : "default"); + .ToArray(); + + if( orders.Length == 0 ) return (useSelect) ? "select" : "default"; + + return orders[0].cursor ?? ((useSelect) ? "select" : "default"); } static UnitOrderResult OrderForUnit( Actor self, int2 xy, MouseInput mi, Actor underCursor ) @@ -124,57 +124,57 @@ namespace OpenRA.Orders if (self.Owner != self.World.LocalPlayer) return null; - - if (self.Destroyed) - return null; - - if( mi.Button == MouseButton.Right ) - { - var uim = self.World.WorldActor.Trait(); - foreach( var o in self.TraitsImplementing() - .SelectMany( trait => trait.Orders - .Select( x => new { Trait = trait, Order = x } ) ) - .OrderByDescending( x => x.Order.OrderPriority ) ) - { - var actorsAt = uim.GetUnitsAt( xy ).ToList(); - - string cursor = null; - if( underCursor != null ) - if (o.Order.CanTargetActor(self, underCursor, mi.Modifiers.HasModifier(Modifiers.Ctrl), mi.Modifiers.HasModifier(Modifiers.Alt), mi.Modifiers.HasModifier(Modifiers.Shift), ref cursor)) - return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromActor( underCursor ) ); - if (o.Order.CanTargetLocation(self, xy, actorsAt, mi.Modifiers.HasModifier(Modifiers.Ctrl), mi.Modifiers.HasModifier(Modifiers.Alt), mi.Modifiers.HasModifier(Modifiers.Shift), ref cursor)) - return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromCell( xy ) ); - } - } - + + if (self.Destroyed) + return null; + + if( mi.Button == MouseButton.Right ) + { + var uim = self.World.WorldActor.Trait(); + foreach( var o in self.TraitsImplementing() + .SelectMany( trait => trait.Orders + .Select( x => new { Trait = trait, Order = x } ) ) + .OrderByDescending( x => x.Order.OrderPriority ) ) + { + var actorsAt = uim.GetUnitsAt( xy ).ToList(); + + string cursor = null; + if( underCursor != null ) + if (o.Order.CanTargetActor(self, underCursor, mi.Modifiers.HasModifier(Modifiers.Ctrl), mi.Modifiers.HasModifier(Modifiers.Alt), mi.Modifiers.HasModifier(Modifiers.Shift), ref cursor)) + return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromActor( underCursor ) ); + if (o.Order.CanTargetLocation(self, xy, actorsAt, mi.Modifiers.HasModifier(Modifiers.Ctrl), mi.Modifiers.HasModifier(Modifiers.Alt), mi.Modifiers.HasModifier(Modifiers.Shift), ref cursor)) + return new UnitOrderResult( self, o.Order, o.Trait, cursor, Target.FromCell( xy ) ); + } + } + return null; - } - - static Order CheckSameOrder( IOrderTargeter iot, Order order ) - { - if( order == null && iot.OrderID != null ) - Game.Debug( "BUG: in order targeter - decided on {0} but then didn't order", iot.OrderID ); - else if( iot.OrderID != order.OrderString ) - Game.Debug( "BUG: in order targeter - decided on {0} but ordered {1}", iot.OrderID, order.OrderString ); - return order; - } - - class UnitOrderResult - { - public readonly Actor self; - public readonly IOrderTargeter iot; - public readonly IIssueOrder trait; - public readonly string cursor; - public readonly Target target; - - public UnitOrderResult( Actor self, IOrderTargeter iot, IIssueOrder trait, string cursor, Target target ) - { - this.self = self; - this.iot = iot; - this.trait = trait; - this.cursor = cursor; - this.target = target; - } - } + } + + static Order CheckSameOrder( IOrderTargeter iot, Order order ) + { + if( order == null && iot.OrderID != null ) + Game.Debug( "BUG: in order targeter - decided on {0} but then didn't order", iot.OrderID ); + else if( iot.OrderID != order.OrderString ) + Game.Debug( "BUG: in order targeter - decided on {0} but ordered {1}", iot.OrderID, order.OrderString ); + return order; + } + + class UnitOrderResult + { + public readonly Actor self; + public readonly IOrderTargeter iot; + public readonly IIssueOrder trait; + public readonly string cursor; + public readonly Target target; + + public UnitOrderResult( Actor self, IOrderTargeter iot, IIssueOrder trait, string cursor, Target target ) + { + this.self = self; + this.iot = iot; + this.trait = trait; + this.cursor = cursor; + this.target = target; + } + } } } diff --git a/OpenRA.Game/Player.cs b/OpenRA.Game/Player.cs index f2dccea3f6..c0ef69661d 100644 --- a/OpenRA.Game/Player.cs +++ b/OpenRA.Game/Player.cs @@ -1,92 +1,92 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Network; -using OpenRA.Traits; - -namespace OpenRA -{ - public enum PowerState { Normal, Low, Critical }; - public enum WinState { Won, Lost, Undefined }; - - public class Player - { - public Actor PlayerActor; - public int Kills; - public int Deaths; - public WinState WinState = WinState.Undefined; - - public readonly string Palette; - public readonly ColorRamp ColorRamp; - - public readonly string PlayerName; - public readonly string InternalName; - public readonly CountryInfo Country; - public readonly int Index; - public readonly bool NonCombatant = false; - public readonly int ClientIndex; - public readonly PlayerReference PlayerRef; - public bool IsBot; - - public Shroud Shroud { get { return World.LocalShroud; }} - public World World { get; private set; } - - public Player(World world, PlayerReference pr, int index) - { - World = world; - - Index = index; - Palette = "player" + index; - - ColorRamp = pr.ColorRamp; - ClientIndex = 0; /* it's a map player, "owned" by host */ - - PlayerName = InternalName = pr.Name; - NonCombatant = pr.NonCombatant; - Country = world.GetCountries() - .FirstOrDefault(c => pr.Race == c.Race) - ?? world.GetCountries().Random(world.SharedRandom); - - PlayerRef = pr; - - PlayerActor = world.CreateActor("Player", new TypeDictionary { new OwnerInit(this) }); - } - - public Player(World world, Session.Client client, PlayerReference pr, int index) - { - World = world; - Index = index; - Palette = "player" + index; - ColorRamp = client.ColorRamp; - PlayerName = client.Name; +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion - InternalName = pr.Name; - Country = world.GetCountries() - .FirstOrDefault(c => client != null && client.Country == c.Race) - ?? world.GetCountries().Random(world.SharedRandom); - - ClientIndex = client.Index; - PlayerRef = pr; - - PlayerActor = world.CreateActor("Player", new TypeDictionary { new OwnerInit(this) }); - } - - public void GiveAdvice(string advice) - { - Sound.PlayToPlayer(this, advice); - } - - public Dictionary Stances = new Dictionary(); - } +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Network; +using OpenRA.Traits; + +namespace OpenRA +{ + public enum PowerState { Normal, Low, Critical }; + public enum WinState { Won, Lost, Undefined }; + + public class Player + { + public Actor PlayerActor; + public int Kills; + public int Deaths; + public WinState WinState = WinState.Undefined; + + public readonly string Palette; + public readonly ColorRamp ColorRamp; + + public readonly string PlayerName; + public readonly string InternalName; + public readonly CountryInfo Country; + public readonly int Index; + public readonly bool NonCombatant = false; + public readonly int ClientIndex; + public readonly PlayerReference PlayerRef; + public bool IsBot; + + public Shroud Shroud { get { return World.LocalShroud; }} + public World World { get; private set; } + + public Player(World world, PlayerReference pr, int index) + { + World = world; + + Index = index; + Palette = "player" + index; + + ColorRamp = pr.ColorRamp; + ClientIndex = 0; /* it's a map player, "owned" by host */ + + PlayerName = InternalName = pr.Name; + NonCombatant = pr.NonCombatant; + Country = world.GetCountries() + .FirstOrDefault(c => pr.Race == c.Race) + ?? world.GetCountries().Random(world.SharedRandom); + + PlayerRef = pr; + + PlayerActor = world.CreateActor("Player", new TypeDictionary { new OwnerInit(this) }); + } + + public Player(World world, Session.Client client, PlayerReference pr, int index) + { + World = world; + Index = index; + Palette = "player" + index; + ColorRamp = client.ColorRamp; + PlayerName = client.Name; + + InternalName = pr.Name; + Country = world.GetCountries() + .FirstOrDefault(c => client != null && client.Country == c.Race) + ?? world.GetCountries().Random(world.SharedRandom); + + ClientIndex = client.Index; + PlayerRef = pr; + + PlayerActor = world.CreateActor("Player", new TypeDictionary { new OwnerInit(this) }); + } + + public void GiveAdvice(string advice) + { + Sound.PlayToPlayer(this, advice); + } + + public Dictionary Stances = new Dictionary(); + } } diff --git a/OpenRA.Game/Selection.cs b/OpenRA.Game/Selection.cs index 7c99a6de2f..3091f84aa0 100644 --- a/OpenRA.Game/Selection.cs +++ b/OpenRA.Game/Selection.cs @@ -1,100 +1,100 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA -{ - public class Selection - { - List actors = new List(); - public void Add(World w, Actor a) - { - actors.Add(a); - foreach (var ns in w.WorldActor.TraitsImplementing()) - ns.SelectionChanged(); - } - - public bool Contains(Actor a) - { - return actors.AsEnumerable().Contains(a); - } - - public void Combine(World world, IEnumerable newSelection, bool isCombine, bool isClick) - { - var oldSelection = actors.AsEnumerable(); - - if (isClick) - { - var adjNewSelection = newSelection.Take(1); /* todo: select BEST, not FIRST */ - actors = (isCombine ? oldSelection.SymmetricDifference(adjNewSelection) : adjNewSelection).ToList(); - } - else - actors = (isCombine ? oldSelection.Union(newSelection) : newSelection).ToList(); - - var voicedUnit = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.IsInWorld && a.HasVoice()); - if (voicedUnit != null) - Sound.PlayVoice("Select", voicedUnit, voicedUnit.Owner.Country.Race); - - foreach (var ns in world.WorldActor.TraitsImplementing()) - ns.SelectionChanged(); - } - - public IEnumerable Actors { get { return actors; } } - public void Clear() { actors = new List(); } - - public void Tick(World world) - { - actors.RemoveAll(a => !a.IsInWorld); - - foreach (var cg in controlGroups.Values) - cg.RemoveAll(a => a.Destroyed); // note: NOT `!a.IsInWorld`, since that would remove things - // that are in transports. - } - - Cache> controlGroups = new Cache>(_ => new List()); - - public void DoControlGroup(World world, int group, Modifiers mods) - { - if (mods.HasModifier(Modifiers.Ctrl)) - { - if (actors.Count == 0) - return; - - controlGroups[group].Clear(); - - for (var i = 0; i < 10; i++) /* all control groups */ - controlGroups[i].RemoveAll(a => actors.Contains(a)); - - controlGroups[group].AddRange(actors); - return; - } - - if (mods.HasModifier(Modifiers.Alt)) - { - Game.viewport.Center(controlGroups[group]); - return; - } - - Combine(world, controlGroups[group], - mods.HasModifier(Modifiers.Shift), false); - } - - public int? GetControlGroupForActor(Actor a) - { - return controlGroups.Where(g => g.Value.Contains(a)) - .Select(g => (int?)g.Key) - .FirstOrDefault(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA +{ + public class Selection + { + List actors = new List(); + public void Add(World w, Actor a) + { + actors.Add(a); + foreach (var ns in w.WorldActor.TraitsImplementing()) + ns.SelectionChanged(); + } + + public bool Contains(Actor a) + { + return actors.AsEnumerable().Contains(a); + } + + public void Combine(World world, IEnumerable newSelection, bool isCombine, bool isClick) + { + var oldSelection = actors.AsEnumerable(); + + if (isClick) + { + var adjNewSelection = newSelection.Take(1); /* todo: select BEST, not FIRST */ + actors = (isCombine ? oldSelection.SymmetricDifference(adjNewSelection) : adjNewSelection).ToList(); + } + else + actors = (isCombine ? oldSelection.Union(newSelection) : newSelection).ToList(); + + var voicedUnit = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.IsInWorld && a.HasVoice()); + if (voicedUnit != null) + Sound.PlayVoice("Select", voicedUnit, voicedUnit.Owner.Country.Race); + + foreach (var ns in world.WorldActor.TraitsImplementing()) + ns.SelectionChanged(); + } + + public IEnumerable Actors { get { return actors; } } + public void Clear() { actors = new List(); } + + public void Tick(World world) + { + actors.RemoveAll(a => !a.IsInWorld); + + foreach (var cg in controlGroups.Values) + cg.RemoveAll(a => a.Destroyed); // note: NOT `!a.IsInWorld`, since that would remove things + // that are in transports. + } + + Cache> controlGroups = new Cache>(_ => new List()); + + public void DoControlGroup(World world, int group, Modifiers mods) + { + if (mods.HasModifier(Modifiers.Ctrl)) + { + if (actors.Count == 0) + return; + + controlGroups[group].Clear(); + + for (var i = 0; i < 10; i++) /* all control groups */ + controlGroups[i].RemoveAll(a => actors.Contains(a)); + + controlGroups[group].AddRange(actors); + return; + } + + if (mods.HasModifier(Modifiers.Alt)) + { + Game.viewport.Center(controlGroups[group]); + return; + } + + Combine(world, controlGroups[group], + mods.HasModifier(Modifiers.Shift), false); + } + + public int? GetControlGroupForActor(Actor a) + { + return controlGroups.Where(g => g.Value.Contains(a)) + .Select(g => (int?)g.Key) + .FirstOrDefault(); + } + } +} diff --git a/OpenRA.Game/Server/Connection.cs b/OpenRA.Game/Server/Connection.cs index 8ae3afa372..59bbd29ac9 100644 --- a/OpenRA.Game/Server/Connection.cs +++ b/OpenRA.Game/Server/Connection.cs @@ -1,97 +1,97 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Sockets; - -namespace OpenRA.Server -{ - public class Connection - { - public Socket socket; - public List data = new List(); - public ReceiveState State = ReceiveState.Header; - public int ExpectLength = 8; - public int Frame = 0; - - public int MostRecentFrame = 0; - - /* client data */ - public int PlayerIndex; - - public byte[] PopBytes(int n) - { - var result = data.GetRange(0, n); - data.RemoveRange(0, n); - return result.ToArray(); - } - - bool ReadDataInner( Server server ) - { - var rx = new byte[1024]; - var len = 0; - - for (; ; ) - { - try - { - if (0 < (len = socket.Receive(rx))) - data.AddRange(rx.Take(len)); - else - { - if (len == 0) - server.DropClient(this); - break; - } - - } - catch (SocketException e) - { - if (e.SocketErrorCode == SocketError.WouldBlock) break; - server.DropClient(this); - return false; - } - } - - return true; - } - - public void ReadData( Server server ) - { - if (ReadDataInner(server)) - while (data.Count >= ExpectLength) - { - var bytes = PopBytes(ExpectLength); - switch (State) - { - case ReceiveState.Header: - { - ExpectLength = BitConverter.ToInt32(bytes, 0) - 4; - Frame = BitConverter.ToInt32(bytes, 4); - State = ReceiveState.Data; - } break; - - case ReceiveState.Data: - { - server.DispatchOrders(this, Frame, bytes); - MostRecentFrame = Frame; - ExpectLength = 8; - State = ReceiveState.Header; - - server.UpdateInFlightFrames(this); - } break; - } - } - }} - - public enum ReceiveState { Header, Data }; -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; + +namespace OpenRA.Server +{ + public class Connection + { + public Socket socket; + public List data = new List(); + public ReceiveState State = ReceiveState.Header; + public int ExpectLength = 8; + public int Frame = 0; + + public int MostRecentFrame = 0; + + /* client data */ + public int PlayerIndex; + + public byte[] PopBytes(int n) + { + var result = data.GetRange(0, n); + data.RemoveRange(0, n); + return result.ToArray(); + } + + bool ReadDataInner( Server server ) + { + var rx = new byte[1024]; + var len = 0; + + for (; ; ) + { + try + { + if (0 < (len = socket.Receive(rx))) + data.AddRange(rx.Take(len)); + else + { + if (len == 0) + server.DropClient(this); + break; + } + + } + catch (SocketException e) + { + if (e.SocketErrorCode == SocketError.WouldBlock) break; + server.DropClient(this); + return false; + } + } + + return true; + } + + public void ReadData( Server server ) + { + if (ReadDataInner(server)) + while (data.Count >= ExpectLength) + { + var bytes = PopBytes(ExpectLength); + switch (State) + { + case ReceiveState.Header: + { + ExpectLength = BitConverter.ToInt32(bytes, 0) - 4; + Frame = BitConverter.ToInt32(bytes, 4); + State = ReceiveState.Data; + } break; + + case ReceiveState.Data: + { + server.DispatchOrders(this, Frame, bytes); + MostRecentFrame = Frame; + ExpectLength = 8; + State = ReceiveState.Header; + + server.UpdateInFlightFrames(this); + } break; + } + } + }} + + public enum ReceiveState { Header, Data }; +} diff --git a/OpenRA.Game/Server/Exts.cs b/OpenRA.Game/Server/Exts.cs index 823afc3df0..f916efec58 100755 --- a/OpenRA.Game/Server/Exts.cs +++ b/OpenRA.Game/Server/Exts.cs @@ -1,37 +1,37 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System; - -namespace OpenRA.Server -{ - static class Exts - { - public static void Write( this Stream s, byte[] data ) - { - s.Write( data, 0, data.Length ); - } - - public static byte[] Read( this Stream s, int len ) - { - var data = new byte[ len ]; - s.Read( data, 0, len ); - return data; - } - - public static IEnumerable Except( this IEnumerable ts, T t ) - { - return ts.Except( new[] { t } ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System; + +namespace OpenRA.Server +{ + static class Exts + { + public static void Write( this Stream s, byte[] data ) + { + s.Write( data, 0, data.Length ); + } + + public static byte[] Read( this Stream s, int len ) + { + var data = new byte[ len ]; + s.Read( data, 0, len ); + return data; + } + + public static IEnumerable Except( this IEnumerable ts, T t ) + { + return ts.Except( new[] { t } ); + } + } +} diff --git a/OpenRA.Game/Server/MasterServerQuery.cs b/OpenRA.Game/Server/MasterServerQuery.cs index 99d15c7c21..d6175dd085 100755 --- a/OpenRA.Game/Server/MasterServerQuery.cs +++ b/OpenRA.Game/Server/MasterServerQuery.cs @@ -1,82 +1,82 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading; -using OpenRA.FileFormats; -using OpenRA.Widgets; - -namespace OpenRA.Server -{ - public static class MasterServerQuery - { - public static event Action OnComplete = _ => { }; - public static event Action OnVersion = _ => { }; - - static GameServer[] Games = { }; - public static string ClientVersion = ""; - public static string ServerVersion = ""; - static AutoResetEvent ev = new AutoResetEvent(false); - static AutoResetEvent ev2 = new AutoResetEvent(false); - - public static void Refresh(string masterServerUrl) - { - new Thread(() => - { - try - { - var str = GetData(new Uri(masterServerUrl + "list.php")); - - var yaml = MiniYaml.FromString(str); - - Games = yaml.Select(a => FieldLoader.Load(a.Value)) - .Where(gs => gs.Address != null).ToArray(); - } - catch - { - Games = null; - } - - ev.Set(); - }).Start(); - } - - public static void Tick() - { - if (ev.WaitOne(TimeSpan.FromMilliseconds(0))) - OnComplete(Games); - if (ev2.WaitOne(TimeSpan.FromMilliseconds(0))) - OnVersion(ServerVersion); - } - - static string GetData(Uri uri) - { - var wc = new WebClient(); - wc.Proxy = null; - var data = wc.DownloadData(uri); - return Encoding.UTF8.GetString(data); - } - } - - public class GameServer - { - public readonly int Id = 0; - public readonly string Name = null; - public readonly string Address = null; - public readonly int State = 0; - public readonly int Players = 0; - public readonly string Map = null; - public readonly string[] Mods = { }; - public readonly int TTL = 0; - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading; +using OpenRA.FileFormats; +using OpenRA.Widgets; + +namespace OpenRA.Server +{ + public static class MasterServerQuery + { + public static event Action OnComplete = _ => { }; + public static event Action OnVersion = _ => { }; + + static GameServer[] Games = { }; + public static string ClientVersion = ""; + public static string ServerVersion = ""; + static AutoResetEvent ev = new AutoResetEvent(false); + static AutoResetEvent ev2 = new AutoResetEvent(false); + + public static void Refresh(string masterServerUrl) + { + new Thread(() => + { + try + { + var str = GetData(new Uri(masterServerUrl + "list.php")); + + var yaml = MiniYaml.FromString(str); + + Games = yaml.Select(a => FieldLoader.Load(a.Value)) + .Where(gs => gs.Address != null).ToArray(); + } + catch + { + Games = null; + } + + ev.Set(); + }).Start(); + } + + public static void Tick() + { + if (ev.WaitOne(TimeSpan.FromMilliseconds(0))) + OnComplete(Games); + if (ev2.WaitOne(TimeSpan.FromMilliseconds(0))) + OnVersion(ServerVersion); + } + + static string GetData(Uri uri) + { + var wc = new WebClient(); + wc.Proxy = null; + var data = wc.DownloadData(uri); + return Encoding.UTF8.GetString(data); + } + } + + public class GameServer + { + public readonly int Id = 0; + public readonly string Name = null; + public readonly string Address = null; + public readonly int State = 0; + public readonly int Players = 0; + public readonly string Map = null; + public readonly string[] Mods = { }; + public readonly int TTL = 0; + } +} diff --git a/OpenRA.Game/Server/ProtocolVersion.cs b/OpenRA.Game/Server/ProtocolVersion.cs index d7c2ef246c..84c55acf28 100644 --- a/OpenRA.Game/Server/ProtocolVersion.cs +++ b/OpenRA.Game/Server/ProtocolVersion.cs @@ -1,18 +1,18 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.Server -{ - public static class ProtocolVersion - { - // you *must* increment this whenever you make an incompatible protocol change - public static readonly int Version = 7; - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.Server +{ + public static class ProtocolVersion + { + // you *must* increment this whenever you make an incompatible protocol change + public static readonly int Version = 7; + } +} diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index fb75f0d2c9..0d4fe29adc 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -1,426 +1,426 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using OpenRA.FileFormats; -using OpenRA.GameRules; -using OpenRA.Network; - -namespace OpenRA.Server -{ - public class Server - { - // Valid player connections - public List conns = new List(); - - // Pre-verified player connections - public List preConns = new List(); - - TcpListener listener = null; - Dictionary> inFlightFrames - = new Dictionary>(); - - TypeDictionary ServerTraits = new TypeDictionary(); - public Session lobbyInfo; - public bool GameStarted = false; - public string Name; - int randomSeed; - - public ModData ModData; - public Map Map; - - bool shutdown = false; - public void Shutdown() - { - shutdown = true; - } - - public Server(ModData modData, Settings settings, string map) - { - Log.AddChannel("server", "server.log"); - - listener = new TcpListener(IPAddress.Any, settings.Server.ListenPort); - Name = settings.Server.Name; - randomSeed = (int)DateTime.Now.ToBinary(); - ModData = modData; - - foreach (var trait in modData.Manifest.ServerTraits) - ServerTraits.Add( modData.ObjectCreator.CreateObject(trait) ); - - lobbyInfo = new Session( settings.Game.Mods ); - lobbyInfo.GlobalSettings.RandomSeed = randomSeed; - lobbyInfo.GlobalSettings.Map = map; - lobbyInfo.GlobalSettings.AllowCheats = settings.Server.AllowCheats; - lobbyInfo.GlobalSettings.ServerName = settings.Server.Name; - - foreach (var t in ServerTraits.WithInterface()) - t.ServerStarted(this); - - Log.Write("server", "Initial mods: "); - foreach( var m in lobbyInfo.GlobalSettings.Mods ) - Log.Write("server","- {0}", m); - - Log.Write("server", "Initial map: {0}",lobbyInfo.GlobalSettings.Map); - - try - { - listener.Start(); - } - catch (Exception) - { - throw new InvalidOperationException( "Unable to start server: port is already in use" ); - } - - new Thread( _ => - { - var timeout = ServerTraits.WithInterface().Min(t => t.TickTimeout); - for( ; ; ) - { - var checkRead = new ArrayList(); - checkRead.Add( listener.Server ); - foreach( var c in conns ) checkRead.Add( c.socket ); - foreach( var c in preConns ) checkRead.Add( c.socket ); - - Socket.Select( checkRead, null, null, timeout ); - - foreach( Socket s in checkRead ) - if( s == listener.Server ) AcceptConnection(); - else if (preConns.Count > 0) - { - var p = preConns.SingleOrDefault( c => c.socket == s ); - if (p != null) p.ReadData( this ); - } - else if (conns.Count > 0) conns.Single( c => c.socket == s ).ReadData( this ); - - foreach (var t in ServerTraits.WithInterface()) - t.Tick(this); - - if (shutdown) - break; - } - - GameStarted = false; - foreach (var t in ServerTraits.WithInterface()) - t.ServerShutdown(this); - - preConns.Clear(); - conns.Clear(); - try { listener.Stop(); } - catch { } - } ) { IsBackground = true }.Start(); - } - - /* lobby rework todo: - * - "teams together" option for team games -- will eliminate most need - * for manual spawnpoint choosing. - * - 256 max players is a dirty hack - */ - int ChooseFreePlayerIndex() - { - for (var i = 0; i < 256; i++) - if (conns.All(c => c.PlayerIndex != i) && preConns.All(c => c.PlayerIndex != i)) - return i; - - throw new InvalidOperationException("Already got 256 players"); - } - - void AcceptConnection() - { - Socket newSocket = null; - - try - { - if (!listener.Server.IsBound) return; - newSocket = listener.AcceptSocket(); - } - catch - { - /* could have an exception here when listener 'goes away' when calling AcceptConnection! */ - /* alternative would be to use locking but the listener doesnt go away without a reason */ - return; - } - - var newConn = new Connection { socket = newSocket }; - try - { - newConn.socket.Blocking = false; - newConn.socket.NoDelay = true; - - // assign the player number. - newConn.PlayerIndex = ChooseFreePlayerIndex(); - newConn.socket.Send(BitConverter.GetBytes(ProtocolVersion.Version)); - newConn.socket.Send(BitConverter.GetBytes(newConn.PlayerIndex)); - preConns.Add(newConn); - - // Dispatch a handshake order - var request = new HandshakeRequest() - { - Map = lobbyInfo.GlobalSettings.Map, - Mods = lobbyInfo.GlobalSettings.Mods.Select(m => "{0}@{1}".F(m,Mod.AllMods[m].Version)).ToArray() - }; - DispatchOrdersToClient(newConn, 0, 0, new ServerOrder("HandshakeRequest", request.Serialize()).Serialize()); - } - catch (Exception) { DropClient(newConn); } - } - - void ValidateClient(Connection newConn, string data) - { - try - { - if (GameStarted) - { - Log.Write("server", "Rejected connection from {0}; game is already started.", - newConn.socket.RemoteEndPoint); - - SendOrderTo(newConn, "ServerError", "The game has already started"); - DropClient(newConn); - return; - } - - var handshake = HandshakeResponse.Deserialize(data); - var client = handshake.Client; - var mods = handshake.Mods; - - // Check that the client has compatable mods - var valid = mods.All( m => m.Contains('@')) && //valid format - mods.Count() == Game.CurrentMods.Count() && //same number - mods.Select( m => Pair.New(m.Split('@')[0], m.Split('@')[1])).All(kv => Game.CurrentMods.ContainsKey(kv.First) && - (kv.Second == "{DEV_VERSION}" || Game.CurrentMods[kv.First].Version == "{DEV_VERSION}" || kv.Second == Game.CurrentMods[kv.First].Version)); - if (!valid) - { - Log.Write("server", "Rejected connection from {0}; mods do not match.", - newConn.socket.RemoteEndPoint); - - SendOrderTo(newConn, "ServerError", "Your mods don't match the server"); - DropClient(newConn); - return; - } - - // Promote connection to a valid client - preConns.Remove(newConn); - conns.Add(newConn); - - // Enforce correct PlayerIndex and Slot - client.Index = newConn.PlayerIndex; - client.Slot = ChooseFreeSlot(); - - var slotData = lobbyInfo.Slots.FirstOrDefault( x => x.Index == client.Slot ); - if (slotData != null && slotData.MapPlayer != null) - SyncClientToPlayerReference(client, Map.Players[slotData.MapPlayer]); - - lobbyInfo.Clients.Add(client); - - Log.Write("server", "Client {0}: Accepted connection from {1}", - newConn.PlayerIndex, newConn.socket.RemoteEndPoint); - SendChat(newConn, "has joined the game."); - - foreach (var t in ServerTraits.WithInterface()) - t.ClientJoined(this, newConn); - - SyncLobbyInfo(); - } - catch (Exception) { DropClient(newConn); } - } - - int ChooseFreeSlot() - { - return lobbyInfo.Slots.First(s => !s.Closed && s.Bot == null - && !lobbyInfo.Clients.Any( c => c.Slot == s.Index )).Index; - } - - - public static void SyncClientToPlayerReference(Session.Client c, PlayerReference pr) - { - if (pr == null) - return; - if (pr.LockColor) - c.ColorRamp = pr.ColorRamp; - if (pr.LockRace) - c.Country = pr.Race; - } - - public void UpdateInFlightFrames(Connection conn) - { - if (conn.Frame == 0) - return; - - if (!inFlightFrames.ContainsKey(conn.Frame)) - inFlightFrames[conn.Frame] = new List { conn }; - else - inFlightFrames[conn.Frame].Add(conn); - - if (conns.All(c => inFlightFrames[conn.Frame].Contains(c))) - inFlightFrames.Remove(conn.Frame); - } - - void DispatchOrdersToClient(Connection c, int client, int frame, byte[] data) - { - try - { - var ms = new MemoryStream(); - ms.Write( BitConverter.GetBytes( data.Length + 4 ) ); - ms.Write( BitConverter.GetBytes( client ) ); - ms.Write( BitConverter.GetBytes( frame ) ); - ms.Write( data ); - c.socket.Send( ms.ToArray() ); - } - catch (Exception) { DropClient(c); } - } - - public void DispatchOrders(Connection conn, int frame, byte[] data) - { - if (frame == 0 && conn != null) - InterpretServerOrders(conn, data); - else - { - var from = conn != null ? conn.PlayerIndex : 0; - foreach (var c in conns.Except(conn).ToArray()) - DispatchOrdersToClient(c, from, frame, data); - } - } - - void InterpretServerOrders(Connection conn, byte[] data) - { - var ms = new MemoryStream(data); - var br = new BinaryReader(ms); - - try - { - for (; ; ) - { - var so = ServerOrder.Deserialize(br); - if (so == null) return; - InterpretServerOrder(conn, so); - } - } - catch (EndOfStreamException) { } - catch (NotImplementedException) { } - } - - public void SendChatTo(Connection conn, string text) - { - SendOrderTo(conn, "Chat", text); - } - - public void SendOrderTo(Connection conn, string order, string data) - { - DispatchOrdersToClient(conn, 0, 0, - new ServerOrder(order, data).Serialize()); - } - - public void SendChat(Connection asConn, string text) - { - DispatchOrders(asConn, 0, new ServerOrder("Chat", text).Serialize()); - } - - public void SendDisconnected(Connection asConn) - { - DispatchOrders(asConn, 0, new ServerOrder("Disconnected", "").Serialize()); - } - - void InterpretServerOrder(Connection conn, ServerOrder so) - { - switch (so.Name) - { - case "Command": - bool handled = false; - foreach (var t in ServerTraits.WithInterface()) - if ((handled = t.InterpretCommand(this, conn, GetClient(conn), so.Data))) - break; - - if (!handled) - { - Log.Write("server", "Unknown server command: {0}", so.Data); - SendChatTo(conn, "Unknown server command: {0}".F(so.Data)); - } - - break; - case "HandshakeResponse": - ValidateClient(conn, so.Data); - break; - case "Chat": - case "TeamChat": - var fromClient = GetClient(conn); - var fromIndex = fromClient != null ? fromClient.Index : 0; - - foreach (var c in conns.Except(conn).ToArray()) - DispatchOrdersToClient(c, fromIndex, 0, so.Serialize()); - break; - } - } - - public Session.Client GetClient(Connection conn) - { - return lobbyInfo.ClientWithIndex(conn.PlayerIndex); - } - - public void DropClient(Connection toDrop) - { - if (preConns.Contains(toDrop)) - preConns.Remove(toDrop); - else - { - conns.Remove(toDrop); - SendChat(toDrop, "Connection Dropped"); - - if (GameStarted) - SendDisconnected(toDrop); /* Report disconnection */ - - lobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex); - - DispatchOrders( toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf } ); - - if (conns.Count != 0) - SyncLobbyInfo(); - } - - try - { - toDrop.socket.Disconnect(false); - } - catch { } - } - - public void SyncLobbyInfo() - { - if (!GameStarted) /* don't do this while the game is running, it breaks things. */ - DispatchOrders(null, 0, - new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize()); - - foreach (var t in ServerTraits.WithInterface()) - t.LobbyInfoSynced(this); - } - - public void StartGame() - { - GameStarted = true; - foreach( var c in conns ) - foreach( var d in conns ) - DispatchOrdersToClient( c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF } ); - - // Drop any unvalidated clients - foreach (var c in preConns) - DropClient(c); - - DispatchOrders(null, 0, - new ServerOrder("StartGame", "").Serialize()); - - foreach (var t in ServerTraits.WithInterface()) - t.GameStarted(this); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using OpenRA.FileFormats; +using OpenRA.GameRules; +using OpenRA.Network; + +namespace OpenRA.Server +{ + public class Server + { + // Valid player connections + public List conns = new List(); + + // Pre-verified player connections + public List preConns = new List(); + + TcpListener listener = null; + Dictionary> inFlightFrames + = new Dictionary>(); + + TypeDictionary ServerTraits = new TypeDictionary(); + public Session lobbyInfo; + public bool GameStarted = false; + public string Name; + int randomSeed; + + public ModData ModData; + public Map Map; + + bool shutdown = false; + public void Shutdown() + { + shutdown = true; + } + + public Server(ModData modData, Settings settings, string map) + { + Log.AddChannel("server", "server.log"); + + listener = new TcpListener(IPAddress.Any, settings.Server.ListenPort); + Name = settings.Server.Name; + randomSeed = (int)DateTime.Now.ToBinary(); + ModData = modData; + + foreach (var trait in modData.Manifest.ServerTraits) + ServerTraits.Add( modData.ObjectCreator.CreateObject(trait) ); + + lobbyInfo = new Session( settings.Game.Mods ); + lobbyInfo.GlobalSettings.RandomSeed = randomSeed; + lobbyInfo.GlobalSettings.Map = map; + lobbyInfo.GlobalSettings.AllowCheats = settings.Server.AllowCheats; + lobbyInfo.GlobalSettings.ServerName = settings.Server.Name; + + foreach (var t in ServerTraits.WithInterface()) + t.ServerStarted(this); + + Log.Write("server", "Initial mods: "); + foreach( var m in lobbyInfo.GlobalSettings.Mods ) + Log.Write("server","- {0}", m); + + Log.Write("server", "Initial map: {0}",lobbyInfo.GlobalSettings.Map); + + try + { + listener.Start(); + } + catch (Exception) + { + throw new InvalidOperationException( "Unable to start server: port is already in use" ); + } + + new Thread( _ => + { + var timeout = ServerTraits.WithInterface().Min(t => t.TickTimeout); + for( ; ; ) + { + var checkRead = new ArrayList(); + checkRead.Add( listener.Server ); + foreach( var c in conns ) checkRead.Add( c.socket ); + foreach( var c in preConns ) checkRead.Add( c.socket ); + + Socket.Select( checkRead, null, null, timeout ); + + foreach( Socket s in checkRead ) + if( s == listener.Server ) AcceptConnection(); + else if (preConns.Count > 0) + { + var p = preConns.SingleOrDefault( c => c.socket == s ); + if (p != null) p.ReadData( this ); + } + else if (conns.Count > 0) conns.Single( c => c.socket == s ).ReadData( this ); + + foreach (var t in ServerTraits.WithInterface()) + t.Tick(this); + + if (shutdown) + break; + } + + GameStarted = false; + foreach (var t in ServerTraits.WithInterface()) + t.ServerShutdown(this); + + preConns.Clear(); + conns.Clear(); + try { listener.Stop(); } + catch { } + } ) { IsBackground = true }.Start(); + } + + /* lobby rework todo: + * - "teams together" option for team games -- will eliminate most need + * for manual spawnpoint choosing. + * - 256 max players is a dirty hack + */ + int ChooseFreePlayerIndex() + { + for (var i = 0; i < 256; i++) + if (conns.All(c => c.PlayerIndex != i) && preConns.All(c => c.PlayerIndex != i)) + return i; + + throw new InvalidOperationException("Already got 256 players"); + } + + void AcceptConnection() + { + Socket newSocket = null; + + try + { + if (!listener.Server.IsBound) return; + newSocket = listener.AcceptSocket(); + } + catch + { + /* could have an exception here when listener 'goes away' when calling AcceptConnection! */ + /* alternative would be to use locking but the listener doesnt go away without a reason */ + return; + } + + var newConn = new Connection { socket = newSocket }; + try + { + newConn.socket.Blocking = false; + newConn.socket.NoDelay = true; + + // assign the player number. + newConn.PlayerIndex = ChooseFreePlayerIndex(); + newConn.socket.Send(BitConverter.GetBytes(ProtocolVersion.Version)); + newConn.socket.Send(BitConverter.GetBytes(newConn.PlayerIndex)); + preConns.Add(newConn); + + // Dispatch a handshake order + var request = new HandshakeRequest() + { + Map = lobbyInfo.GlobalSettings.Map, + Mods = lobbyInfo.GlobalSettings.Mods.Select(m => "{0}@{1}".F(m,Mod.AllMods[m].Version)).ToArray() + }; + DispatchOrdersToClient(newConn, 0, 0, new ServerOrder("HandshakeRequest", request.Serialize()).Serialize()); + } + catch (Exception) { DropClient(newConn); } + } + + void ValidateClient(Connection newConn, string data) + { + try + { + if (GameStarted) + { + Log.Write("server", "Rejected connection from {0}; game is already started.", + newConn.socket.RemoteEndPoint); + + SendOrderTo(newConn, "ServerError", "The game has already started"); + DropClient(newConn); + return; + } + + var handshake = HandshakeResponse.Deserialize(data); + var client = handshake.Client; + var mods = handshake.Mods; + + // Check that the client has compatable mods + var valid = mods.All( m => m.Contains('@')) && //valid format + mods.Count() == Game.CurrentMods.Count() && //same number + mods.Select( m => Pair.New(m.Split('@')[0], m.Split('@')[1])).All(kv => Game.CurrentMods.ContainsKey(kv.First) && + (kv.Second == "{DEV_VERSION}" || Game.CurrentMods[kv.First].Version == "{DEV_VERSION}" || kv.Second == Game.CurrentMods[kv.First].Version)); + if (!valid) + { + Log.Write("server", "Rejected connection from {0}; mods do not match.", + newConn.socket.RemoteEndPoint); + + SendOrderTo(newConn, "ServerError", "Your mods don't match the server"); + DropClient(newConn); + return; + } + + // Promote connection to a valid client + preConns.Remove(newConn); + conns.Add(newConn); + + // Enforce correct PlayerIndex and Slot + client.Index = newConn.PlayerIndex; + client.Slot = ChooseFreeSlot(); + + var slotData = lobbyInfo.Slots.FirstOrDefault( x => x.Index == client.Slot ); + if (slotData != null && slotData.MapPlayer != null) + SyncClientToPlayerReference(client, Map.Players[slotData.MapPlayer]); + + lobbyInfo.Clients.Add(client); + + Log.Write("server", "Client {0}: Accepted connection from {1}", + newConn.PlayerIndex, newConn.socket.RemoteEndPoint); + SendChat(newConn, "has joined the game."); + + foreach (var t in ServerTraits.WithInterface()) + t.ClientJoined(this, newConn); + + SyncLobbyInfo(); + } + catch (Exception) { DropClient(newConn); } + } + + int ChooseFreeSlot() + { + return lobbyInfo.Slots.First(s => !s.Closed && s.Bot == null + && !lobbyInfo.Clients.Any( c => c.Slot == s.Index )).Index; + } + + + public static void SyncClientToPlayerReference(Session.Client c, PlayerReference pr) + { + if (pr == null) + return; + if (pr.LockColor) + c.ColorRamp = pr.ColorRamp; + if (pr.LockRace) + c.Country = pr.Race; + } + + public void UpdateInFlightFrames(Connection conn) + { + if (conn.Frame == 0) + return; + + if (!inFlightFrames.ContainsKey(conn.Frame)) + inFlightFrames[conn.Frame] = new List { conn }; + else + inFlightFrames[conn.Frame].Add(conn); + + if (conns.All(c => inFlightFrames[conn.Frame].Contains(c))) + inFlightFrames.Remove(conn.Frame); + } + + void DispatchOrdersToClient(Connection c, int client, int frame, byte[] data) + { + try + { + var ms = new MemoryStream(); + ms.Write( BitConverter.GetBytes( data.Length + 4 ) ); + ms.Write( BitConverter.GetBytes( client ) ); + ms.Write( BitConverter.GetBytes( frame ) ); + ms.Write( data ); + c.socket.Send( ms.ToArray() ); + } + catch (Exception) { DropClient(c); } + } + + public void DispatchOrders(Connection conn, int frame, byte[] data) + { + if (frame == 0 && conn != null) + InterpretServerOrders(conn, data); + else + { + var from = conn != null ? conn.PlayerIndex : 0; + foreach (var c in conns.Except(conn).ToArray()) + DispatchOrdersToClient(c, from, frame, data); + } + } + + void InterpretServerOrders(Connection conn, byte[] data) + { + var ms = new MemoryStream(data); + var br = new BinaryReader(ms); + + try + { + for (; ; ) + { + var so = ServerOrder.Deserialize(br); + if (so == null) return; + InterpretServerOrder(conn, so); + } + } + catch (EndOfStreamException) { } + catch (NotImplementedException) { } + } + + public void SendChatTo(Connection conn, string text) + { + SendOrderTo(conn, "Chat", text); + } + + public void SendOrderTo(Connection conn, string order, string data) + { + DispatchOrdersToClient(conn, 0, 0, + new ServerOrder(order, data).Serialize()); + } + + public void SendChat(Connection asConn, string text) + { + DispatchOrders(asConn, 0, new ServerOrder("Chat", text).Serialize()); + } + + public void SendDisconnected(Connection asConn) + { + DispatchOrders(asConn, 0, new ServerOrder("Disconnected", "").Serialize()); + } + + void InterpretServerOrder(Connection conn, ServerOrder so) + { + switch (so.Name) + { + case "Command": + bool handled = false; + foreach (var t in ServerTraits.WithInterface()) + if ((handled = t.InterpretCommand(this, conn, GetClient(conn), so.Data))) + break; + + if (!handled) + { + Log.Write("server", "Unknown server command: {0}", so.Data); + SendChatTo(conn, "Unknown server command: {0}".F(so.Data)); + } + + break; + case "HandshakeResponse": + ValidateClient(conn, so.Data); + break; + case "Chat": + case "TeamChat": + var fromClient = GetClient(conn); + var fromIndex = fromClient != null ? fromClient.Index : 0; + + foreach (var c in conns.Except(conn).ToArray()) + DispatchOrdersToClient(c, fromIndex, 0, so.Serialize()); + break; + } + } + + public Session.Client GetClient(Connection conn) + { + return lobbyInfo.ClientWithIndex(conn.PlayerIndex); + } + + public void DropClient(Connection toDrop) + { + if (preConns.Contains(toDrop)) + preConns.Remove(toDrop); + else + { + conns.Remove(toDrop); + SendChat(toDrop, "Connection Dropped"); + + if (GameStarted) + SendDisconnected(toDrop); /* Report disconnection */ + + lobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex); + + DispatchOrders( toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf } ); + + if (conns.Count != 0) + SyncLobbyInfo(); + } + + try + { + toDrop.socket.Disconnect(false); + } + catch { } + } + + public void SyncLobbyInfo() + { + if (!GameStarted) /* don't do this while the game is running, it breaks things. */ + DispatchOrders(null, 0, + new ServerOrder("SyncInfo", lobbyInfo.Serialize()).Serialize()); + + foreach (var t in ServerTraits.WithInterface()) + t.LobbyInfoSynced(this); + } + + public void StartGame() + { + GameStarted = true; + foreach( var c in conns ) + foreach( var d in conns ) + DispatchOrdersToClient( c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF } ); + + // Drop any unvalidated clients + foreach (var c in preConns) + DropClient(c); + + DispatchOrders(null, 0, + new ServerOrder("StartGame", "").Serialize()); + + foreach (var t in ServerTraits.WithInterface()) + t.GameStarted(this); + } + } +} diff --git a/OpenRA.Game/Server/ServerOrder.cs b/OpenRA.Game/Server/ServerOrder.cs index 99d6d7bdc1..2fd6787def 100644 --- a/OpenRA.Game/Server/ServerOrder.cs +++ b/OpenRA.Game/Server/ServerOrder.cs @@ -1,60 +1,60 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.IO; - -namespace OpenRA.Server -{ - class ServerOrder - { - public readonly string Name; - public readonly string Data; - - public ServerOrder(string name, string data) - { - Name = name; - Data = data; - } - - public static ServerOrder Deserialize(BinaryReader r) - { - byte b; - switch (b = r.ReadByte()) - { - case 0xff: - Console.WriteLine("This isn't a server order."); - return null; - - case 0xfe: - { - var name = r.ReadString(); - var data = r.ReadString(); - - return new ServerOrder(name, data); - } - - default: - throw new NotImplementedException(b.ToString("x2")); - } - } - - public byte[] Serialize() - { - var ms = new MemoryStream(); - var bw = new BinaryWriter(ms); - - bw.Write((byte)0xfe); - bw.Write(Name); - bw.Write(Data); - return ms.ToArray(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.IO; + +namespace OpenRA.Server +{ + class ServerOrder + { + public readonly string Name; + public readonly string Data; + + public ServerOrder(string name, string data) + { + Name = name; + Data = data; + } + + public static ServerOrder Deserialize(BinaryReader r) + { + byte b; + switch (b = r.ReadByte()) + { + case 0xff: + Console.WriteLine("This isn't a server order."); + return null; + + case 0xfe: + { + var name = r.ReadString(); + var data = r.ReadString(); + + return new ServerOrder(name, data); + } + + default: + throw new NotImplementedException(b.ToString("x2")); + } + } + + public byte[] Serialize() + { + var ms = new MemoryStream(); + var bw = new BinaryWriter(ms); + + bw.Write((byte)0xfe); + bw.Write(Name); + bw.Write(Data); + return ms.ToArray(); + } + } +} diff --git a/OpenRA.Game/Server/TraitInterfaces.cs b/OpenRA.Game/Server/TraitInterfaces.cs index 0e6ead6f9b..c6c89484d5 100644 --- a/OpenRA.Game/Server/TraitInterfaces.cs +++ b/OpenRA.Game/Server/TraitInterfaces.cs @@ -1,58 +1,58 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion -using System; -using OpenRA.Network; - -namespace OpenRA.Server -{ - // Returns true if order is handled - public interface IInterpretCommand { bool InterpretCommand(Server server, Connection conn, Session.Client client, string cmd); } - public interface INotifySyncLobbyInfo { void LobbyInfoSynced(Server server); } - public interface INotifyServerStart { void ServerStarted(Server server); } - public interface INotifyServerShutdown { void ServerShutdown(Server server); } - public interface IStartGame { void GameStarted(Server server); } - public interface IClientJoined { void ClientJoined(Server server, Connection conn); } - public interface ITick - { - void Tick(Server server); - int TickTimeout { get; } - } - - public abstract class ServerTrait {} - - public class DebugServerTrait : ServerTrait, IInterpretCommand, IStartGame, INotifySyncLobbyInfo, INotifyServerStart, INotifyServerShutdown - { - public bool InterpretCommand(Server server, Connection conn, Session.Client client, string cmd) - { - Console.WriteLine("Server received command from player {1}: {0}",cmd, conn.PlayerIndex); - return false; - } - - public void GameStarted(Server server) - { - Console.WriteLine("GameStarted()"); - } - - public void LobbyInfoSynced(Server server) - { - Console.WriteLine("LobbyInfoSynced()"); - } - - public void ServerStarted(Server server) - { - Console.WriteLine("ServerStarted()"); - } - - public void ServerShutdown(Server server) - { - Console.WriteLine("ServerShutdown()"); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion +using System; +using OpenRA.Network; + +namespace OpenRA.Server +{ + // Returns true if order is handled + public interface IInterpretCommand { bool InterpretCommand(Server server, Connection conn, Session.Client client, string cmd); } + public interface INotifySyncLobbyInfo { void LobbyInfoSynced(Server server); } + public interface INotifyServerStart { void ServerStarted(Server server); } + public interface INotifyServerShutdown { void ServerShutdown(Server server); } + public interface IStartGame { void GameStarted(Server server); } + public interface IClientJoined { void ClientJoined(Server server, Connection conn); } + public interface ITick + { + void Tick(Server server); + int TickTimeout { get; } + } + + public abstract class ServerTrait {} + + public class DebugServerTrait : ServerTrait, IInterpretCommand, IStartGame, INotifySyncLobbyInfo, INotifyServerStart, INotifyServerShutdown + { + public bool InterpretCommand(Server server, Connection conn, Session.Client client, string cmd) + { + Console.WriteLine("Server received command from player {1}: {0}",cmd, conn.PlayerIndex); + return false; + } + + public void GameStarted(Server server) + { + Console.WriteLine("GameStarted()"); + } + + public void LobbyInfoSynced(Server server) + { + Console.WriteLine("LobbyInfoSynced()"); + } + + public void ServerStarted(Server server) + { + Console.WriteLine("ServerStarted()"); + } + + public void ServerShutdown(Server server) + { + Console.WriteLine("ServerShutdown()"); + } + } +} diff --git a/OpenRA.Game/Sound.cs b/OpenRA.Game/Sound.cs index ae0af975bd..59ef4ee745 100644 --- a/OpenRA.Game/Sound.cs +++ b/OpenRA.Game/Sound.cs @@ -1,492 +1,492 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; -using Tao.OpenAl; - -namespace OpenRA -{ - public static class Sound - { - static ISoundEngine soundEngine; - static Cache sounds; - static ISoundSource rawSource; - static ISound music; - static ISound video; - static string currentMusic; - - static ISoundSource LoadSound(string filename) - { - return LoadSoundRaw(AudLoader.LoadSound(FileSystem.Open(filename))); - } - - static ISoundSource LoadSoundRaw(byte[] rawData) - { - return soundEngine.AddSoundSourceFromMemory(rawData, 1, 16, 22050); - } - - public static void Create() - { - soundEngine = new OpenAlSoundEngine(); - } - - public static void Initialize() - { - sounds = new Cache(LoadSound); - music = null; - currentMusic = null; - video = null; - } - - public static void SetListenerPosition(float2 position) { soundEngine.SetListenerPosition(position); } - - static ISound Play(Player player, string name, bool headRelative, float2 pos, float volumeModifier) - { - if (player != null && player != player.World.LocalPlayer) - return null; - if (name == "" || name == null) - return null; - - return soundEngine.Play2D(sounds[name], - false, headRelative, pos, - InternalSoundVolume * volumeModifier); - } - - public static ISound Play(string name) { return Play(null, name, true, float2.Zero, 1); } - public static ISound Play(string name, float2 pos) { return Play(null, name, false, pos, 1); } - public static ISound Play(string name, float volumeModifier) { return Play(null, name, true, float2.Zero, volumeModifier); } - public static ISound Play(string name, float2 pos, float volumeModifier) { return Play(null, name, false, pos, volumeModifier); } - public static ISound PlayToPlayer(Player player, string name) { return Play( player, name, true, float2.Zero, 1); } - public static ISound PlayToPlayer(Player player, string name, float2 pos) { return Play(player, name, false, pos, 1); } - - public static void PlayVideo(byte[] raw) - { - rawSource = LoadSoundRaw(raw); - video = soundEngine.Play2D(rawSource, false, true, float2.Zero, InternalSoundVolume); - } - - public static void PlayVideo() - { - if (video != null) - soundEngine.PauseSound(video, false); - } - - public static void PauseVideo() - { - if (video != null) - soundEngine.PauseSound(video, true); - } - - public static void StopVideo() - { - if (video != null) - soundEngine.StopSound(video); - } - - public static void Tick() - { - // Song finished - if (MusicPlaying && !music.Playing) - { - StopMusic(); - OnMusicComplete(); - } - } - - static Action OnMusicComplete; - public static bool MusicPlaying { get; private set; } - - public static void PlayMusic(string name) - { - PlayMusicThen(name, () => { }); - } - public static void PlayMusicThen(string name, Action then) - { - OnMusicComplete = then; - - if (name == "" || name == null) - return; - - if (name == currentMusic && music != null) - { - soundEngine.PauseSound(music, false); - return; - } - StopMusic(); - - currentMusic = name; - MusicPlaying = true; - var sound = sounds[name]; - music = soundEngine.Play2D(sound, false, true, float2.Zero, MusicVolume); - } - - public static void PlayMusic() - { - if (music == null) - return; - MusicPlaying = true; - soundEngine.PauseSound(music, false); - } - - public static void StopSound(ISound sound) - { - if (sound != null) - soundEngine.StopSound(sound); - } - - public static void StopMusic() - { - if (music != null) - soundEngine.StopSound(music); - - MusicPlaying = false; - currentMusic = null; - } - - public static void PauseMusic() - { - if (music == null) - return; - - MusicPlaying = false; - soundEngine.PauseSound(music, true); - } - - public static float GlobalVolume - { - get { return soundEngine.Volume; } - set { soundEngine.Volume = value; } - } - - static float soundVolumeModifier = 1.0f; - public static float SoundVolumeModifier - { - get { return soundVolumeModifier; } - set - { - soundVolumeModifier = value; - soundEngine.SetSoundVolume(InternalSoundVolume, music, video); - } - } - - static float InternalSoundVolume { get { return SoundVolume * soundVolumeModifier; } } - public static float SoundVolume - { - get { return Game.Settings.Sound.SoundVolume; } - set - { - Game.Settings.Sound.SoundVolume = value; - soundEngine.SetSoundVolume(InternalSoundVolume, music, video); - } - } - - public static float MusicVolume - { - get { return Game.Settings.Sound.MusicVolume; } - set - { - Game.Settings.Sound.MusicVolume = value; - if (music != null) - music.Volume = value; - } - } - - public static float VideoVolume - { - get { return Game.Settings.Sound.VideoVolume; } - set - { - Game.Settings.Sound.VideoVolume = value; - if (video != null) - video.Volume = value; - } - } - - public static float MusicSeekPosition - { - get { return (music != null) ? music.SeekPosition : 0; } - } - - public static float VideoSeekPosition - { - get { return (video != null) ? video.SeekPosition : 0; } - } - - // Returns true if it played a phrase - public static bool PlayVoice(string phrase, Actor voicedUnit, string variant) - { - if (voicedUnit == null) return false; - if (phrase == null) return false; - - var mi = voicedUnit.Info.Traits.GetOrDefault(); - if (mi == null) return false; - if (mi.Voice == null) return false; - - var vi = Rules.Voices[mi.Voice.ToLowerInvariant()]; - - var clip = vi.Pools.Value[phrase].GetNext(); - if (clip == null) - return false; - - var variantext = (vi.Variants.ContainsKey(variant) && !vi.DisableVariants.Contains(phrase)) ? - vi.Variants[variant][voicedUnit.ActorID % vi.Variants[variant].Length] : vi.DefaultVariant; - Play(clip + variantext); - return true; - } - } - - interface ISoundEngine - { - ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate); - ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume); - float Volume { get; set; } - void PauseSound(ISound sound, bool paused); - void StopSound(ISound sound); - void SetAllSoundsPaused(bool paused); - void StopAllSounds(); - void SetListenerPosition(float2 position); - void SetSoundVolume(float volume, ISound music, ISound video); - } - - interface ISoundSource { } - - public interface ISound - { - float Volume { get; set; } - float SeekPosition { get; } - bool Playing { get; } - } - - class OpenAlSoundEngine : ISoundEngine - { - float volume = 1f; - Dictionary sourcePool = new Dictionary(); - const int POOL_SIZE = 32; - - public OpenAlSoundEngine() - { - //var str = Alc.alcGetString(IntPtr.Zero, Alc.ALC_DEFAULT_DEVICE_SPECIFIER); - var dev = Alc.alcOpenDevice(null); - if (dev == IntPtr.Zero) - throw new InvalidOperationException("Can't create OpenAL device"); - var ctx = Alc.alcCreateContext(dev, IntPtr.Zero); - if (ctx == IntPtr.Zero) - throw new InvalidOperationException("Can't create OpenAL context"); - Alc.alcMakeContextCurrent(ctx); - - for (var i = 0; i < POOL_SIZE; i++) - { - var source = 0; - Al.alGenSources(1, out source); - if (0 != Al.alGetError()) - { - Log.Write("debug", "Failed generating OpenAL source {0}", i); - return; - } - - sourcePool.Add(source, false); - } - } - - int GetSourceFromPool() - { - foreach (var kvp in sourcePool) - { - if (!kvp.Value) - { - sourcePool[kvp.Key] = true; - return kvp.Key; - } - } - - List freeSources = new List(); - foreach (int key in sourcePool.Keys) - { - int state; - Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); - if (state != Al.AL_PLAYING && state != Al.AL_PAUSED) - freeSources.Add(key); - } - - if (freeSources.Count == 0) - return -1; - - foreach (int i in freeSources) - sourcePool[i] = false; - - sourcePool[freeSources[0]] = true; - - return freeSources[0]; - } - - public ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate) - { - return new OpenAlSoundSource(data, channels, sampleBits, sampleRate); - } - - public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume) - { - int source = GetSourceFromPool(); - return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop, relative, pos, volume); - } - - public float Volume - { - get { return volume; } - set { Al.alListenerf(Al.AL_GAIN, volume = value); } - } - - public void PauseSound(ISound sound, bool paused) - { - int key = ((OpenAlSound)sound).source; - int state; - Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); - if (state == Al.AL_PLAYING && paused) - Al.alSourcePause(key); - else if (state == Al.AL_PAUSED && !paused) - Al.alSourcePlay(key); - } - - public void SetAllSoundsPaused(bool paused) - { - foreach (int key in sourcePool.Keys) - { - int state; - Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); - if (state == Al.AL_PLAYING && paused) - Al.alSourcePause(key); - else if (state == Al.AL_PAUSED && !paused) - Al.alSourcePlay(key); - - } - } - - public void SetSoundVolume(float volume, ISound music, ISound video) - { - var sounds = sourcePool.Select(s => s.Key).Where(b => - { - int state; - Al.alGetSourcei(b, Al.AL_SOURCE_STATE, out state); - return ((state == Al.AL_PLAYING || state == Al.AL_PAUSED) && - ((music != null) ? b != ((OpenAlSound)music).source : true) && - ((video != null) ? b != ((OpenAlSound)video).source : true)); - }).ToList(); - foreach (var s in sounds) - { - Al.alSourcef(s, Al.AL_GAIN, volume); - } - } - - public void StopSound(ISound sound) - { - int key = ((OpenAlSound)sound).source; - int state; - Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); - if (state == Al.AL_PLAYING || state == Al.AL_PAUSED) - Al.alSourceStop(key); - } - - public void StopAllSounds() - { - foreach (int key in sourcePool.Keys) - { - int state; - Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); - if (state == Al.AL_PLAYING || state == Al.AL_PAUSED) - Al.alSourceStop(key); - } - } - - public void SetListenerPosition(float2 position) - { - var orientation = new[] { 0f, 0f, 1f, 0f, -1f, 0f }; - - Al.alListener3f(Al.AL_POSITION, position.X, position.Y, 50); - Al.alListenerfv(Al.AL_ORIENTATION, ref orientation[0]); - Al.alListenerf(Al.AL_METERS_PER_UNIT, .01f); - } - } - - class OpenAlSoundSource : ISoundSource - { - public readonly int buffer; - - static int MakeALFormat(int channels, int bits) - { - if (channels == 1) - return bits == 16 ? Al.AL_FORMAT_MONO16 : Al.AL_FORMAT_MONO8; - else - return bits == 16 ? Al.AL_FORMAT_STEREO16 : Al.AL_FORMAT_STEREO8; - } - - public OpenAlSoundSource(byte[] data, int channels, int sampleBits, int sampleRate) - { - Al.alGenBuffers(1, out buffer); - Al.alBufferData(buffer, MakeALFormat(channels, sampleBits), data, data.Length, sampleRate); - } - } - - class OpenAlSound : ISound - { - public readonly int source = -1; - float volume = 1f; - - public OpenAlSound(int source, int buffer, bool looping, bool relative, float2 pos, float volume) - { - if (source == -1) return; - this.source = source; - Al.alSourcef(source, Al.AL_PITCH, 1f); - Al.alSourcef(source, Al.AL_GAIN, 1f); - Al.alSource3f(source, Al.AL_POSITION, pos.X, pos.Y, 0f); - Al.alSource3f(source, Al.AL_VELOCITY, 0f, 0f, 0f); - Al.alSourcei(source, Al.AL_BUFFER, buffer); - Al.alSourcei(source, Al.AL_LOOPING, looping ? Al.AL_TRUE : Al.AL_FALSE); - Al.alSourcei(source, Al.AL_SOURCE_RELATIVE, relative ? 1 : 0); - Al.alSourcef(source, Al.AL_REFERENCE_DISTANCE, 200); - Al.alSourcef(source, Al.AL_MAX_DISTANCE, 1500); - Volume = volume; - Al.alSourcePlay(source); - } - - public float Volume - { - get { return volume; } - set - { - if (source != -1) - Al.alSourcef(source, Al.AL_GAIN, volume = value); - } - } - - public float SeekPosition - { - get - { - float pos; - Al.alGetSourcef(source, Al.AL_SAMPLE_OFFSET, out pos); - return pos / 22050f; - } - } - - public bool Playing - { - get - { - int state; - Al.alGetSourcei(source, Al.AL_SOURCE_STATE, out state); - return state == Al.AL_PLAYING; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; +using Tao.OpenAl; + +namespace OpenRA +{ + public static class Sound + { + static ISoundEngine soundEngine; + static Cache sounds; + static ISoundSource rawSource; + static ISound music; + static ISound video; + static string currentMusic; + + static ISoundSource LoadSound(string filename) + { + return LoadSoundRaw(AudLoader.LoadSound(FileSystem.Open(filename))); + } + + static ISoundSource LoadSoundRaw(byte[] rawData) + { + return soundEngine.AddSoundSourceFromMemory(rawData, 1, 16, 22050); + } + + public static void Create() + { + soundEngine = new OpenAlSoundEngine(); + } + + public static void Initialize() + { + sounds = new Cache(LoadSound); + music = null; + currentMusic = null; + video = null; + } + + public static void SetListenerPosition(float2 position) { soundEngine.SetListenerPosition(position); } + + static ISound Play(Player player, string name, bool headRelative, float2 pos, float volumeModifier) + { + if (player != null && player != player.World.LocalPlayer) + return null; + if (name == "" || name == null) + return null; + + return soundEngine.Play2D(sounds[name], + false, headRelative, pos, + InternalSoundVolume * volumeModifier); + } + + public static ISound Play(string name) { return Play(null, name, true, float2.Zero, 1); } + public static ISound Play(string name, float2 pos) { return Play(null, name, false, pos, 1); } + public static ISound Play(string name, float volumeModifier) { return Play(null, name, true, float2.Zero, volumeModifier); } + public static ISound Play(string name, float2 pos, float volumeModifier) { return Play(null, name, false, pos, volumeModifier); } + public static ISound PlayToPlayer(Player player, string name) { return Play( player, name, true, float2.Zero, 1); } + public static ISound PlayToPlayer(Player player, string name, float2 pos) { return Play(player, name, false, pos, 1); } + + public static void PlayVideo(byte[] raw) + { + rawSource = LoadSoundRaw(raw); + video = soundEngine.Play2D(rawSource, false, true, float2.Zero, InternalSoundVolume); + } + + public static void PlayVideo() + { + if (video != null) + soundEngine.PauseSound(video, false); + } + + public static void PauseVideo() + { + if (video != null) + soundEngine.PauseSound(video, true); + } + + public static void StopVideo() + { + if (video != null) + soundEngine.StopSound(video); + } + + public static void Tick() + { + // Song finished + if (MusicPlaying && !music.Playing) + { + StopMusic(); + OnMusicComplete(); + } + } + + static Action OnMusicComplete; + public static bool MusicPlaying { get; private set; } + + public static void PlayMusic(string name) + { + PlayMusicThen(name, () => { }); + } + public static void PlayMusicThen(string name, Action then) + { + OnMusicComplete = then; + + if (name == "" || name == null) + return; + + if (name == currentMusic && music != null) + { + soundEngine.PauseSound(music, false); + return; + } + StopMusic(); + + currentMusic = name; + MusicPlaying = true; + var sound = sounds[name]; + music = soundEngine.Play2D(sound, false, true, float2.Zero, MusicVolume); + } + + public static void PlayMusic() + { + if (music == null) + return; + MusicPlaying = true; + soundEngine.PauseSound(music, false); + } + + public static void StopSound(ISound sound) + { + if (sound != null) + soundEngine.StopSound(sound); + } + + public static void StopMusic() + { + if (music != null) + soundEngine.StopSound(music); + + MusicPlaying = false; + currentMusic = null; + } + + public static void PauseMusic() + { + if (music == null) + return; + + MusicPlaying = false; + soundEngine.PauseSound(music, true); + } + + public static float GlobalVolume + { + get { return soundEngine.Volume; } + set { soundEngine.Volume = value; } + } + + static float soundVolumeModifier = 1.0f; + public static float SoundVolumeModifier + { + get { return soundVolumeModifier; } + set + { + soundVolumeModifier = value; + soundEngine.SetSoundVolume(InternalSoundVolume, music, video); + } + } + + static float InternalSoundVolume { get { return SoundVolume * soundVolumeModifier; } } + public static float SoundVolume + { + get { return Game.Settings.Sound.SoundVolume; } + set + { + Game.Settings.Sound.SoundVolume = value; + soundEngine.SetSoundVolume(InternalSoundVolume, music, video); + } + } + + public static float MusicVolume + { + get { return Game.Settings.Sound.MusicVolume; } + set + { + Game.Settings.Sound.MusicVolume = value; + if (music != null) + music.Volume = value; + } + } + + public static float VideoVolume + { + get { return Game.Settings.Sound.VideoVolume; } + set + { + Game.Settings.Sound.VideoVolume = value; + if (video != null) + video.Volume = value; + } + } + + public static float MusicSeekPosition + { + get { return (music != null) ? music.SeekPosition : 0; } + } + + public static float VideoSeekPosition + { + get { return (video != null) ? video.SeekPosition : 0; } + } + + // Returns true if it played a phrase + public static bool PlayVoice(string phrase, Actor voicedUnit, string variant) + { + if (voicedUnit == null) return false; + if (phrase == null) return false; + + var mi = voicedUnit.Info.Traits.GetOrDefault(); + if (mi == null) return false; + if (mi.Voice == null) return false; + + var vi = Rules.Voices[mi.Voice.ToLowerInvariant()]; + + var clip = vi.Pools.Value[phrase].GetNext(); + if (clip == null) + return false; + + var variantext = (vi.Variants.ContainsKey(variant) && !vi.DisableVariants.Contains(phrase)) ? + vi.Variants[variant][voicedUnit.ActorID % vi.Variants[variant].Length] : vi.DefaultVariant; + Play(clip + variantext); + return true; + } + } + + interface ISoundEngine + { + ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate); + ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume); + float Volume { get; set; } + void PauseSound(ISound sound, bool paused); + void StopSound(ISound sound); + void SetAllSoundsPaused(bool paused); + void StopAllSounds(); + void SetListenerPosition(float2 position); + void SetSoundVolume(float volume, ISound music, ISound video); + } + + interface ISoundSource { } + + public interface ISound + { + float Volume { get; set; } + float SeekPosition { get; } + bool Playing { get; } + } + + class OpenAlSoundEngine : ISoundEngine + { + float volume = 1f; + Dictionary sourcePool = new Dictionary(); + const int POOL_SIZE = 32; + + public OpenAlSoundEngine() + { + //var str = Alc.alcGetString(IntPtr.Zero, Alc.ALC_DEFAULT_DEVICE_SPECIFIER); + var dev = Alc.alcOpenDevice(null); + if (dev == IntPtr.Zero) + throw new InvalidOperationException("Can't create OpenAL device"); + var ctx = Alc.alcCreateContext(dev, IntPtr.Zero); + if (ctx == IntPtr.Zero) + throw new InvalidOperationException("Can't create OpenAL context"); + Alc.alcMakeContextCurrent(ctx); + + for (var i = 0; i < POOL_SIZE; i++) + { + var source = 0; + Al.alGenSources(1, out source); + if (0 != Al.alGetError()) + { + Log.Write("debug", "Failed generating OpenAL source {0}", i); + return; + } + + sourcePool.Add(source, false); + } + } + + int GetSourceFromPool() + { + foreach (var kvp in sourcePool) + { + if (!kvp.Value) + { + sourcePool[kvp.Key] = true; + return kvp.Key; + } + } + + List freeSources = new List(); + foreach (int key in sourcePool.Keys) + { + int state; + Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); + if (state != Al.AL_PLAYING && state != Al.AL_PAUSED) + freeSources.Add(key); + } + + if (freeSources.Count == 0) + return -1; + + foreach (int i in freeSources) + sourcePool[i] = false; + + sourcePool[freeSources[0]] = true; + + return freeSources[0]; + } + + public ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate) + { + return new OpenAlSoundSource(data, channels, sampleBits, sampleRate); + } + + public ISound Play2D(ISoundSource sound, bool loop, bool relative, float2 pos, float volume) + { + int source = GetSourceFromPool(); + return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop, relative, pos, volume); + } + + public float Volume + { + get { return volume; } + set { Al.alListenerf(Al.AL_GAIN, volume = value); } + } + + public void PauseSound(ISound sound, bool paused) + { + int key = ((OpenAlSound)sound).source; + int state; + Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); + if (state == Al.AL_PLAYING && paused) + Al.alSourcePause(key); + else if (state == Al.AL_PAUSED && !paused) + Al.alSourcePlay(key); + } + + public void SetAllSoundsPaused(bool paused) + { + foreach (int key in sourcePool.Keys) + { + int state; + Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); + if (state == Al.AL_PLAYING && paused) + Al.alSourcePause(key); + else if (state == Al.AL_PAUSED && !paused) + Al.alSourcePlay(key); + + } + } + + public void SetSoundVolume(float volume, ISound music, ISound video) + { + var sounds = sourcePool.Select(s => s.Key).Where(b => + { + int state; + Al.alGetSourcei(b, Al.AL_SOURCE_STATE, out state); + return ((state == Al.AL_PLAYING || state == Al.AL_PAUSED) && + ((music != null) ? b != ((OpenAlSound)music).source : true) && + ((video != null) ? b != ((OpenAlSound)video).source : true)); + }).ToList(); + foreach (var s in sounds) + { + Al.alSourcef(s, Al.AL_GAIN, volume); + } + } + + public void StopSound(ISound sound) + { + int key = ((OpenAlSound)sound).source; + int state; + Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); + if (state == Al.AL_PLAYING || state == Al.AL_PAUSED) + Al.alSourceStop(key); + } + + public void StopAllSounds() + { + foreach (int key in sourcePool.Keys) + { + int state; + Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state); + if (state == Al.AL_PLAYING || state == Al.AL_PAUSED) + Al.alSourceStop(key); + } + } + + public void SetListenerPosition(float2 position) + { + var orientation = new[] { 0f, 0f, 1f, 0f, -1f, 0f }; + + Al.alListener3f(Al.AL_POSITION, position.X, position.Y, 50); + Al.alListenerfv(Al.AL_ORIENTATION, ref orientation[0]); + Al.alListenerf(Al.AL_METERS_PER_UNIT, .01f); + } + } + + class OpenAlSoundSource : ISoundSource + { + public readonly int buffer; + + static int MakeALFormat(int channels, int bits) + { + if (channels == 1) + return bits == 16 ? Al.AL_FORMAT_MONO16 : Al.AL_FORMAT_MONO8; + else + return bits == 16 ? Al.AL_FORMAT_STEREO16 : Al.AL_FORMAT_STEREO8; + } + + public OpenAlSoundSource(byte[] data, int channels, int sampleBits, int sampleRate) + { + Al.alGenBuffers(1, out buffer); + Al.alBufferData(buffer, MakeALFormat(channels, sampleBits), data, data.Length, sampleRate); + } + } + + class OpenAlSound : ISound + { + public readonly int source = -1; + float volume = 1f; + + public OpenAlSound(int source, int buffer, bool looping, bool relative, float2 pos, float volume) + { + if (source == -1) return; + this.source = source; + Al.alSourcef(source, Al.AL_PITCH, 1f); + Al.alSourcef(source, Al.AL_GAIN, 1f); + Al.alSource3f(source, Al.AL_POSITION, pos.X, pos.Y, 0f); + Al.alSource3f(source, Al.AL_VELOCITY, 0f, 0f, 0f); + Al.alSourcei(source, Al.AL_BUFFER, buffer); + Al.alSourcei(source, Al.AL_LOOPING, looping ? Al.AL_TRUE : Al.AL_FALSE); + Al.alSourcei(source, Al.AL_SOURCE_RELATIVE, relative ? 1 : 0); + Al.alSourcef(source, Al.AL_REFERENCE_DISTANCE, 200); + Al.alSourcef(source, Al.AL_MAX_DISTANCE, 1500); + Volume = volume; + Al.alSourcePlay(source); + } + + public float Volume + { + get { return volume; } + set + { + if (source != -1) + Al.alSourcef(source, Al.AL_GAIN, volume = value); + } + } + + public float SeekPosition + { + get + { + float pos; + Al.alGetSourcef(source, Al.AL_SAMPLE_OFFSET, out pos); + return pos / 22050f; + } + } + + public bool Playing + { + get + { + int state; + Al.alGetSourcei(source, Al.AL_SOURCE_STATE, out state); + return state == Al.AL_PLAYING; + } + } + } +} diff --git a/OpenRA.Game/Support/Arguments.cs b/OpenRA.Game/Support/Arguments.cs index 6db4a90562..f60bfa45f0 100644 --- a/OpenRA.Game/Support/Arguments.cs +++ b/OpenRA.Game/Support/Arguments.cs @@ -1,59 +1,59 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Text.RegularExpressions; - -namespace OpenRA -{ - public class Arguments - { - Dictionary args = new Dictionary(); - - public static Arguments Empty { get { return new Arguments(); } } - - public Arguments(params string[] src) - { - Regex regex = new Regex("([^=]+)=(.*)"); - foreach (string s in src) - { - Match m = regex.Match(s); - if (m == null || !m.Success) - continue; - - args[m.Groups[1].Value] = m.Groups[2].Value; - } - } - - public bool Contains(string key) { return args.ContainsKey(key); } - - public string GetValue(string key, string defaultValue) { return Contains(key) ? args[key] : defaultValue; } - - public int GetValue(string key, int defaultValue) - { - int result; - - if (!int.TryParse(GetValue(key, defaultValue.ToString()), out result)) - result = defaultValue; - - return result; - } - - public bool GetValue(string key, bool defaultValue) - { - bool result; - - if (!bool.TryParse(GetValue(key, defaultValue.ToString()), out result)) - result = defaultValue; - - return result; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace OpenRA +{ + public class Arguments + { + Dictionary args = new Dictionary(); + + public static Arguments Empty { get { return new Arguments(); } } + + public Arguments(params string[] src) + { + Regex regex = new Regex("([^=]+)=(.*)"); + foreach (string s in src) + { + Match m = regex.Match(s); + if (m == null || !m.Success) + continue; + + args[m.Groups[1].Value] = m.Groups[2].Value; + } + } + + public bool Contains(string key) { return args.ContainsKey(key); } + + public string GetValue(string key, string defaultValue) { return Contains(key) ? args[key] : defaultValue; } + + public int GetValue(string key, int defaultValue) + { + int result; + + if (!int.TryParse(GetValue(key, defaultValue.ToString()), out result)) + result = defaultValue; + + return result; + } + + public bool GetValue(string key, bool defaultValue) + { + bool result; + + if (!bool.TryParse(GetValue(key, defaultValue.ToString()), out result)) + result = defaultValue; + + return result; + } + } +} diff --git a/OpenRA.Game/Support/PerfHistory.cs b/OpenRA.Game/Support/PerfHistory.cs index b4471f9f11..4eaaedfdc1 100644 --- a/OpenRA.Game/Support/PerfHistory.cs +++ b/OpenRA.Game/Support/PerfHistory.cs @@ -1,108 +1,108 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using OpenRA.FileFormats; - -namespace OpenRA.Support -{ - public static class PerfHistory - { - static readonly Color[] colors = { Color.Red, Color.Green, - Color.Orange, Color.Yellow, - Color.Fuchsia, Color.Lime, - Color.LightBlue, Color.Blue, - Color.White, Color.Teal }; - static int nextColor; - - public static Cache items = new Cache( - s => - { - var x = new PerfItem(s, colors[nextColor++]); - if (nextColor >= colors.Length) nextColor = 0; - return x; - }); - - public static void Increment( string item, double x ) - { - items[item].val += x; - } - - public static void Tick() - { - foreach (var item in items.Values) - if (item.hasNormalTick) - item.Tick(); - } - } - - public class PerfItem - { - public readonly Color c; - public readonly string Name; - public double[] samples = new double[100]; - public double val = 0.0; - int head = 1, tail = 0; - public bool hasNormalTick = true; - - public PerfItem(string name, Color c) - { - Name = name; - this.c = c; - } - - public void Tick() - { - samples[head++] = val; - if (head == samples.Length) head = 0; - if (head == tail && ++tail == samples.Length) tail = 0; - val = 0.0; - } - - public IEnumerable Samples() - { - int n = head; - while (n != tail) - { - --n; - if (n < 0) n = samples.Length - 1; - yield return samples[n]; - } - } - - public double LastValue - { - get - { - int n = head; - if (--n < 0) n = samples.Length - 1; - return samples[n]; - } - } - } - - public class PerfSample : IDisposable - { - readonly Stopwatch sw = new Stopwatch(); - readonly string Item; - - public PerfSample(string item) - { - Item = item; - } - - public void Dispose() - { - PerfHistory.Increment(Item, sw.ElapsedTime() * 1000); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using OpenRA.FileFormats; + +namespace OpenRA.Support +{ + public static class PerfHistory + { + static readonly Color[] colors = { Color.Red, Color.Green, + Color.Orange, Color.Yellow, + Color.Fuchsia, Color.Lime, + Color.LightBlue, Color.Blue, + Color.White, Color.Teal }; + static int nextColor; + + public static Cache items = new Cache( + s => + { + var x = new PerfItem(s, colors[nextColor++]); + if (nextColor >= colors.Length) nextColor = 0; + return x; + }); + + public static void Increment( string item, double x ) + { + items[item].val += x; + } + + public static void Tick() + { + foreach (var item in items.Values) + if (item.hasNormalTick) + item.Tick(); + } + } + + public class PerfItem + { + public readonly Color c; + public readonly string Name; + public double[] samples = new double[100]; + public double val = 0.0; + int head = 1, tail = 0; + public bool hasNormalTick = true; + + public PerfItem(string name, Color c) + { + Name = name; + this.c = c; + } + + public void Tick() + { + samples[head++] = val; + if (head == samples.Length) head = 0; + if (head == tail && ++tail == samples.Length) tail = 0; + val = 0.0; + } + + public IEnumerable Samples() + { + int n = head; + while (n != tail) + { + --n; + if (n < 0) n = samples.Length - 1; + yield return samples[n]; + } + } + + public double LastValue + { + get + { + int n = head; + if (--n < 0) n = samples.Length - 1; + return samples[n]; + } + } + } + + public class PerfSample : IDisposable + { + readonly Stopwatch sw = new Stopwatch(); + readonly string Item; + + public PerfSample(string item) + { + Item = item; + } + + public void Dispose() + { + PerfHistory.Increment(Item, sw.ElapsedTime() * 1000); + } + } +} diff --git a/OpenRA.Game/Support/Program.cs b/OpenRA.Game/Support/Program.cs index 5c15085ecc..c35b1b4a44 100644 --- a/OpenRA.Game/Support/Program.cs +++ b/OpenRA.Game/Support/Program.cs @@ -1,52 +1,52 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Linq; -using System.Windows.Forms; - -namespace OpenRA -{ - static class Program - { - [STAThread] - static void Main( string[] args ) - { - // brutal hack - Application.CurrentCulture = CultureInfo.InvariantCulture; - - if (Debugger.IsAttached || args.Contains("--just-die")) - { - Run(args); - return; - } - - try - { - Run( args ); - } - catch( Exception e ) - { - Log.AddChannel("exception", "exception.log"); - Log.Write("exception", "{0}", e.ToString()); - throw; - } - } - - static void Run( string[] args ) - { - Game.Initialize( new Arguments(args) ); - GC.Collect(); - Game.Run(); - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Windows.Forms; + +namespace OpenRA +{ + static class Program + { + [STAThread] + static void Main( string[] args ) + { + // brutal hack + Application.CurrentCulture = CultureInfo.InvariantCulture; + + if (Debugger.IsAttached || args.Contains("--just-die")) + { + Run(args); + return; + } + + try + { + Run( args ); + } + catch( Exception e ) + { + Log.AddChannel("exception", "exception.log"); + Log.Write("exception", "{0}", e.ToString()); + throw; + } + } + + static void Run( string[] args ) + { + Game.Initialize( new Arguments(args) ); + GC.Collect(); + Game.Run(); + } + } } \ No newline at end of file diff --git a/OpenRA.Game/Sync.cs b/OpenRA.Game/Sync.cs index 996bcd166e..ebcef9ba1f 100755 --- a/OpenRA.Game/Sync.cs +++ b/OpenRA.Game/Sync.cs @@ -1,167 +1,167 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; -using OpenRA.FileFormats; - -namespace OpenRA -{ - public class SyncAttribute : Attribute { } - public interface ISync { } /* marker interface */ - - public static class Sync - { - static Cache> hashFuncCache = new Cache>( t => GenerateHashFunc( t ) ); - - public static int CalculateSyncHash( object obj ) - { - return hashFuncCache[ obj.GetType() ]( obj ); - } - - static void EmitSyncOpcodes(Type type, ILGenerator il) - { - if (type == typeof(int)) - { - il.Emit(OpCodes.Xor); - } - else if (type == typeof(bool)) - { - var l = il.DefineLabel(); - il.Emit(OpCodes.Ldc_I4, 0xaaa); - il.Emit(OpCodes.Brtrue, l); - il.Emit(OpCodes.Pop); - il.Emit(OpCodes.Ldc_I4, 0x555); - il.MarkLabel(l); - il.Emit(OpCodes.Xor); - } - else if (type == typeof(int2)) - { - il.EmitCall(OpCodes.Call, ((Func)hash_int2).Method, null); - il.Emit(OpCodes.Xor); - } - else if (type == typeof(TypeDictionary)) - { - il.EmitCall(OpCodes.Call, ((Func)hash_tdict).Method, null); - il.Emit(OpCodes.Xor); - } - else if (type == typeof(Actor)) - { - il.EmitCall(OpCodes.Call, ((Func)hash_actor).Method, null); - il.Emit(OpCodes.Xor); - } - else if (type == typeof(Player)) - { - il.EmitCall(OpCodes.Call, ((Func)hash_player).Method, null); - il.Emit(OpCodes.Xor); - } - else if (type.HasAttribute()) - { - il.EmitCall(OpCodes.Call, ((Func)CalculateSyncHash).Method, null); - il.Emit(OpCodes.Xor); - } - else - throw new NotImplementedException("SyncAttribute on member of unhashable type: {0}".F(type.FullName)); - } - - public static Func GenerateHashFunc(Type t) - { - var d = new DynamicMethod("hash_{0}".F(t.Name), typeof(int), new Type[] { typeof(object) }, t); - var il = d.GetILGenerator(); - var this_ = il.DeclareLocal(t).LocalIndex; - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Castclass, t); - il.Emit(OpCodes.Stloc, this_); - il.Emit(OpCodes.Ldc_I4_0); - - const BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - foreach (var field in t.GetFields(bf).Where(x => x.HasAttribute())) - { - il.Emit(OpCodes.Ldloc, this_); - il.Emit(OpCodes.Ldfld, field); - - EmitSyncOpcodes(field.FieldType, il); - } - - foreach (var prop in t.GetProperties(bf).Where(x => x.HasAttribute())) - { - il.Emit(OpCodes.Ldloc, this_); - il.EmitCall(OpCodes.Call, prop.GetGetMethod(), null); - - EmitSyncOpcodes(prop.PropertyType, il); - } - - il.Emit(OpCodes.Ret); - return (Func)d.CreateDelegate(typeof(Func)); - } - - public static int hash_int2( int2 i2 ) - { - return ( ( i2.X * 5 ) ^ ( i2.Y * 3 ) ) / 4; - } - - public static int hash_tdict( TypeDictionary d ) - { - int ret = 0; - foreach( var o in d ) - ret += CalculateSyncHash( o ); - return ret; - } - - public static int hash_actor( Actor a ) - { - if( a != null ) - return (int)( a.ActorID << 16 ); - return 0; - } - - public static int hash_player( Player p ) - { - if( p != null ) - return p.Index * 0x567; - return 0; - } - - public static void CheckSyncUnchanged( World world, Action fn ) - { - CheckSyncUnchanged( world, () => { fn(); return true; } ); - } - - static bool inUnsyncedCode = false; - - public static T CheckSyncUnchanged( World world, Func fn ) - { - if( world == null ) return fn(); - var shouldCheckSync = Game.Settings.Debug.SanityCheckUnsyncedCode; - int sync = shouldCheckSync ? world.SyncHash() : 0; - bool prevInUnsyncedCode = inUnsyncedCode; - inUnsyncedCode = true; - - try - { - return fn(); - } - finally - { - inUnsyncedCode = prevInUnsyncedCode; - if( shouldCheckSync && sync != world.SyncHash() ) - throw new InvalidOperationException( "CheckSyncUnchanged: sync-changing code may not run here" ); - } - } - - public static void AssertUnsynced( string message ) - { - if( !inUnsyncedCode ) - throw new InvalidOperationException( message ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using OpenRA.FileFormats; + +namespace OpenRA +{ + public class SyncAttribute : Attribute { } + public interface ISync { } /* marker interface */ + + public static class Sync + { + static Cache> hashFuncCache = new Cache>( t => GenerateHashFunc( t ) ); + + public static int CalculateSyncHash( object obj ) + { + return hashFuncCache[ obj.GetType() ]( obj ); + } + + static void EmitSyncOpcodes(Type type, ILGenerator il) + { + if (type == typeof(int)) + { + il.Emit(OpCodes.Xor); + } + else if (type == typeof(bool)) + { + var l = il.DefineLabel(); + il.Emit(OpCodes.Ldc_I4, 0xaaa); + il.Emit(OpCodes.Brtrue, l); + il.Emit(OpCodes.Pop); + il.Emit(OpCodes.Ldc_I4, 0x555); + il.MarkLabel(l); + il.Emit(OpCodes.Xor); + } + else if (type == typeof(int2)) + { + il.EmitCall(OpCodes.Call, ((Func)hash_int2).Method, null); + il.Emit(OpCodes.Xor); + } + else if (type == typeof(TypeDictionary)) + { + il.EmitCall(OpCodes.Call, ((Func)hash_tdict).Method, null); + il.Emit(OpCodes.Xor); + } + else if (type == typeof(Actor)) + { + il.EmitCall(OpCodes.Call, ((Func)hash_actor).Method, null); + il.Emit(OpCodes.Xor); + } + else if (type == typeof(Player)) + { + il.EmitCall(OpCodes.Call, ((Func)hash_player).Method, null); + il.Emit(OpCodes.Xor); + } + else if (type.HasAttribute()) + { + il.EmitCall(OpCodes.Call, ((Func)CalculateSyncHash).Method, null); + il.Emit(OpCodes.Xor); + } + else + throw new NotImplementedException("SyncAttribute on member of unhashable type: {0}".F(type.FullName)); + } + + public static Func GenerateHashFunc(Type t) + { + var d = new DynamicMethod("hash_{0}".F(t.Name), typeof(int), new Type[] { typeof(object) }, t); + var il = d.GetILGenerator(); + var this_ = il.DeclareLocal(t).LocalIndex; + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Castclass, t); + il.Emit(OpCodes.Stloc, this_); + il.Emit(OpCodes.Ldc_I4_0); + + const BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + foreach (var field in t.GetFields(bf).Where(x => x.HasAttribute())) + { + il.Emit(OpCodes.Ldloc, this_); + il.Emit(OpCodes.Ldfld, field); + + EmitSyncOpcodes(field.FieldType, il); + } + + foreach (var prop in t.GetProperties(bf).Where(x => x.HasAttribute())) + { + il.Emit(OpCodes.Ldloc, this_); + il.EmitCall(OpCodes.Call, prop.GetGetMethod(), null); + + EmitSyncOpcodes(prop.PropertyType, il); + } + + il.Emit(OpCodes.Ret); + return (Func)d.CreateDelegate(typeof(Func)); + } + + public static int hash_int2( int2 i2 ) + { + return ( ( i2.X * 5 ) ^ ( i2.Y * 3 ) ) / 4; + } + + public static int hash_tdict( TypeDictionary d ) + { + int ret = 0; + foreach( var o in d ) + ret += CalculateSyncHash( o ); + return ret; + } + + public static int hash_actor( Actor a ) + { + if( a != null ) + return (int)( a.ActorID << 16 ); + return 0; + } + + public static int hash_player( Player p ) + { + if( p != null ) + return p.Index * 0x567; + return 0; + } + + public static void CheckSyncUnchanged( World world, Action fn ) + { + CheckSyncUnchanged( world, () => { fn(); return true; } ); + } + + static bool inUnsyncedCode = false; + + public static T CheckSyncUnchanged( World world, Func fn ) + { + if( world == null ) return fn(); + var shouldCheckSync = Game.Settings.Debug.SanityCheckUnsyncedCode; + int sync = shouldCheckSync ? world.SyncHash() : 0; + bool prevInUnsyncedCode = inUnsyncedCode; + inUnsyncedCode = true; + + try + { + return fn(); + } + finally + { + inUnsyncedCode = prevInUnsyncedCode; + if( shouldCheckSync && sync != world.SyncHash() ) + throw new InvalidOperationException( "CheckSyncUnchanged: sync-changing code may not run here" ); + } + } + + public static void AssertUnsynced( string message ) + { + if( !inUnsyncedCode ) + throw new InvalidOperationException( message ); + } + } +} diff --git a/OpenRA.Game/TraitDictionary.cs b/OpenRA.Game/TraitDictionary.cs index 37a5e5988d..7d995c9a90 100755 --- a/OpenRA.Game/TraitDictionary.cs +++ b/OpenRA.Game/TraitDictionary.cs @@ -1,175 +1,175 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; - -namespace OpenRA -{ - class TraitDictionary - { - Dictionary traits = new Dictionary(); - - ITraitContainer InnerGet( Type t ) - { - return traits.GetOrAdd( t, CreateTraitContainer ); - } - - static ITraitContainer CreateTraitContainer( Type t ) - { - return (ITraitContainer)typeof( TraitContainer<> ).MakeGenericType( t ) - .GetConstructor( new Type[ 0 ] ).Invoke( new object[ 0 ] ); - } - - public void AddTrait( Actor actor, object val ) - { - var t = val.GetType(); - - foreach( var i in t.GetInterfaces() ) - InnerAdd( actor, i, val ); - foreach( var tt in t.BaseTypes() ) - InnerAdd( actor, tt, val ); - } - - void InnerAdd( Actor actor, Type t, object val ) - { - InnerGet( t ).Add( actor, val ); - } - - public bool Contains( Actor actor ) - { - if( actor.Destroyed ) - throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) ); - return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor.ActorID ).Count() != 0; - } - - public T Get( Actor actor ) - { - if( actor.Destroyed ) - throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) ); - return ( (TraitContainer)InnerGet( typeof( T ) ) ).Get( actor.ActorID ); - } - - public T GetOrDefault( Actor actor ) - { - if( actor.Destroyed ) - throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) ); - return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetOrDefault( actor.ActorID ); - } - - public IEnumerable WithInterface( Actor actor ) - { - if( actor.Destroyed ) - throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) ); - return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor.ActorID ); - } - - public IEnumerable> ActorsWithTraitMultiple( World world ) - { - return ( (TraitContainer)InnerGet( typeof( T ) ) ).All(); - } - - public void RemoveActor( Actor a ) - { - foreach( var t in traits ) - t.Value.RemoveActor( a.ActorID ); - } - - interface ITraitContainer - { - void Add( Actor actor, object trait ); - void RemoveActor( uint actor ); - } - - class TraitContainer : ITraitContainer - { - List actors = new List(); - List traits = new List(); - - public void Add( Actor actor, object trait ) - { - var insertIndex = actors.BinarySearchMany( actor.ActorID + 1 ); - actors.Insert( insertIndex, actor ); - traits.Insert( insertIndex, (T)trait ); - } - - public T Get( uint actor ) - { - var index = actors.BinarySearchMany( actor ); - if( index >= actors.Count || actors[ index ].ActorID != actor ) - throw new InvalidOperationException( string.Format( "TraitDictionary does not contain instance of type `{0}`", typeof( T ) ) ); - else if( index + 1 < actors.Count && actors[ index + 1 ].ActorID == actor ) - throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); - else - return traits[ index ]; - } - - public T GetOrDefault( uint actor ) - { - var index = actors.BinarySearchMany( actor ); - if( index >= actors.Count || actors[ index ].ActorID != actor ) - return default( T ); - else if( index + 1 < actors.Count && actors[ index + 1 ].ActorID == actor ) - throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); - else return traits[ index ]; - } - - public IEnumerable GetMultiple( uint actor ) - { - var index = actors.BinarySearchMany( actor ); - while( index < actors.Count && actors[ index ].ActorID == actor ) - { - yield return traits[ index ]; - ++index; - } - } - - public IEnumerable> All() - { - for( int i = 0 ; i < actors.Count ; i++ ) - yield return new TraitPair { Actor = actors[ i ], Trait = traits[ i ] }; - } - - public void RemoveActor( uint actor ) - { - for( int i = actors.Count - 1 ; i >= 0 ; i-- ) - { - if( actors[ i ].ActorID == actor ) - { - actors.RemoveAt( i ); - traits.RemoveAt( i ); - } - } - } - } - } - - static class ListExts - { - public static int BinarySearchMany( this List list, uint searchFor ) - { - int start = 0; - int end = list.Count; - int mid = 0; - while( start != end ) - { - mid = ( start + end ) / 2; - var c = list[ mid ].ActorID.CompareTo( searchFor ); - if( c < 0 ) - start = mid + 1; - else - end = mid; - } - return start; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; + +namespace OpenRA +{ + class TraitDictionary + { + Dictionary traits = new Dictionary(); + + ITraitContainer InnerGet( Type t ) + { + return traits.GetOrAdd( t, CreateTraitContainer ); + } + + static ITraitContainer CreateTraitContainer( Type t ) + { + return (ITraitContainer)typeof( TraitContainer<> ).MakeGenericType( t ) + .GetConstructor( new Type[ 0 ] ).Invoke( new object[ 0 ] ); + } + + public void AddTrait( Actor actor, object val ) + { + var t = val.GetType(); + + foreach( var i in t.GetInterfaces() ) + InnerAdd( actor, i, val ); + foreach( var tt in t.BaseTypes() ) + InnerAdd( actor, tt, val ); + } + + void InnerAdd( Actor actor, Type t, object val ) + { + InnerGet( t ).Add( actor, val ); + } + + public bool Contains( Actor actor ) + { + if( actor.Destroyed ) + throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) ); + return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor.ActorID ).Count() != 0; + } + + public T Get( Actor actor ) + { + if( actor.Destroyed ) + throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) ); + return ( (TraitContainer)InnerGet( typeof( T ) ) ).Get( actor.ActorID ); + } + + public T GetOrDefault( Actor actor ) + { + if( actor.Destroyed ) + throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) ); + return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetOrDefault( actor.ActorID ); + } + + public IEnumerable WithInterface( Actor actor ) + { + if( actor.Destroyed ) + throw new InvalidOperationException( "Attempted to get trait from destroyed object ({0})".F( actor.ToString() ) ); + return ( (TraitContainer)InnerGet( typeof( T ) ) ).GetMultiple( actor.ActorID ); + } + + public IEnumerable> ActorsWithTraitMultiple( World world ) + { + return ( (TraitContainer)InnerGet( typeof( T ) ) ).All(); + } + + public void RemoveActor( Actor a ) + { + foreach( var t in traits ) + t.Value.RemoveActor( a.ActorID ); + } + + interface ITraitContainer + { + void Add( Actor actor, object trait ); + void RemoveActor( uint actor ); + } + + class TraitContainer : ITraitContainer + { + List actors = new List(); + List traits = new List(); + + public void Add( Actor actor, object trait ) + { + var insertIndex = actors.BinarySearchMany( actor.ActorID + 1 ); + actors.Insert( insertIndex, actor ); + traits.Insert( insertIndex, (T)trait ); + } + + public T Get( uint actor ) + { + var index = actors.BinarySearchMany( actor ); + if( index >= actors.Count || actors[ index ].ActorID != actor ) + throw new InvalidOperationException( string.Format( "TraitDictionary does not contain instance of type `{0}`", typeof( T ) ) ); + else if( index + 1 < actors.Count && actors[ index + 1 ].ActorID == actor ) + throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); + else + return traits[ index ]; + } + + public T GetOrDefault( uint actor ) + { + var index = actors.BinarySearchMany( actor ); + if( index >= actors.Count || actors[ index ].ActorID != actor ) + return default( T ); + else if( index + 1 < actors.Count && actors[ index + 1 ].ActorID == actor ) + throw new InvalidOperationException( string.Format( "TraitDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); + else return traits[ index ]; + } + + public IEnumerable GetMultiple( uint actor ) + { + var index = actors.BinarySearchMany( actor ); + while( index < actors.Count && actors[ index ].ActorID == actor ) + { + yield return traits[ index ]; + ++index; + } + } + + public IEnumerable> All() + { + for( int i = 0 ; i < actors.Count ; i++ ) + yield return new TraitPair { Actor = actors[ i ], Trait = traits[ i ] }; + } + + public void RemoveActor( uint actor ) + { + for( int i = actors.Count - 1 ; i >= 0 ; i-- ) + { + if( actors[ i ].ActorID == actor ) + { + actors.RemoveAt( i ); + traits.RemoveAt( i ); + } + } + } + } + } + + static class ListExts + { + public static int BinarySearchMany( this List list, uint searchFor ) + { + int start = 0; + int end = list.Count; + int mid = 0; + while( start != end ) + { + mid = ( start + end ) / 2; + var c = list[ mid ].ActorID.CompareTo( searchFor ); + if( c < 0 ) + start = mid + 1; + else + end = mid; + } + return start; + } + } +} diff --git a/OpenRA.Game/Traits/ActorStance.cs b/OpenRA.Game/Traits/ActorStance.cs index dc9399d9b4..dd18a6664a 100644 --- a/OpenRA.Game/Traits/ActorStance.cs +++ b/OpenRA.Game/Traits/ActorStance.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Game/Traits/Armor.cs b/OpenRA.Game/Traits/Armor.cs index 4ddd317879..47dafb752e 100644 --- a/OpenRA.Game/Traits/Armor.cs +++ b/OpenRA.Game/Traits/Armor.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Game/Traits/DrawLineToTarget.cs b/OpenRA.Game/Traits/DrawLineToTarget.cs index a2f60d2d6d..a27882c33c 100644 --- a/OpenRA.Game/Traits/DrawLineToTarget.cs +++ b/OpenRA.Game/Traits/DrawLineToTarget.cs @@ -1,75 +1,75 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion -using System.Drawing; +using System.Drawing; using OpenRA.Graphics; -using OpenRA.Effects; - -namespace OpenRA.Traits -{ - public class DrawLineToTargetInfo : ITraitInfo - { - public readonly int Ticks = 60; - - public virtual object Create(ActorInitializer init) { return new DrawLineToTarget(this); } - } - - public class DrawLineToTarget : IPostRenderSelection - { - DrawLineToTargetInfo Info; - public DrawLineToTarget(DrawLineToTargetInfo info) - { - this.Info = info; - } - - Target target; - int lifetime; - Color c; - - public void SetTarget(Actor self, Target target, Color c) - { - this.target = target; - lifetime = Info.Ticks; - this.c = c; - } - - public void SetTargetSilently(Actor self, Target target, Color c) - { - this.target = target; - this.c = c; - } - - public void RenderAfterWorld(WorldRenderer wr, Actor self) - { - if (self.IsIdle) return; - - var force = Game.GetModifierKeys().HasModifier(Modifiers.Alt); - if ((lifetime <= 0 || --lifetime <= 0) && !force) - return; - - if (!target.IsValid) - return; - - var p = target.CenterLocation; - var move = self.TraitOrDefault(); - var origin = move != null ? self.CenterLocation - new int2(0, move.Altitude) : self.CenterLocation; - - Game.Renderer.LineRenderer.DrawLine(origin, p, c, c); - for (bool b = false; !b; p = origin, b = true) - { - Game.Renderer.LineRenderer.DrawLine(p + new float2(-1, -1), p + new float2(-1, 1), c, c); - Game.Renderer.LineRenderer.DrawLine(p + new float2(-1, 1), p + new float2(1, 1), c, c); - Game.Renderer.LineRenderer.DrawLine(p + new float2(1, 1), p + new float2(1, -1), c, c); - Game.Renderer.LineRenderer.DrawLine(p + new float2(1, -1), p + new float2(-1, -1), c, c); - } - } +using OpenRA.Effects; + +namespace OpenRA.Traits +{ + public class DrawLineToTargetInfo : ITraitInfo + { + public readonly int Ticks = 60; + + public virtual object Create(ActorInitializer init) { return new DrawLineToTarget(this); } + } + + public class DrawLineToTarget : IPostRenderSelection + { + DrawLineToTargetInfo Info; + public DrawLineToTarget(DrawLineToTargetInfo info) + { + this.Info = info; + } + + Target target; + int lifetime; + Color c; + + public void SetTarget(Actor self, Target target, Color c) + { + this.target = target; + lifetime = Info.Ticks; + this.c = c; + } + + public void SetTargetSilently(Actor self, Target target, Color c) + { + this.target = target; + this.c = c; + } + + public void RenderAfterWorld(WorldRenderer wr, Actor self) + { + if (self.IsIdle) return; + + var force = Game.GetModifierKeys().HasModifier(Modifiers.Alt); + if ((lifetime <= 0 || --lifetime <= 0) && !force) + return; + + if (!target.IsValid) + return; + + var p = target.CenterLocation; + var move = self.TraitOrDefault(); + var origin = move != null ? self.CenterLocation - new int2(0, move.Altitude) : self.CenterLocation; + + Game.Renderer.LineRenderer.DrawLine(origin, p, c, c); + for (bool b = false; !b; p = origin, b = true) + { + Game.Renderer.LineRenderer.DrawLine(p + new float2(-1, -1), p + new float2(-1, 1), c, c); + Game.Renderer.LineRenderer.DrawLine(p + new float2(-1, 1), p + new float2(1, 1), c, c); + Game.Renderer.LineRenderer.DrawLine(p + new float2(1, 1), p + new float2(1, -1), c, c); + Game.Renderer.LineRenderer.DrawLine(p + new float2(1, -1), p + new float2(-1, -1), c, c); + } + } } public static class LineTargetExts @@ -98,6 +98,6 @@ namespace OpenRA.Traits line.SetTargetSilently(self, target, color); }); } - } + } } diff --git a/OpenRA.Game/Traits/EditorAppearance.cs b/OpenRA.Game/Traits/EditorAppearance.cs index 3b4cce38e3..cfc65e87f0 100644 --- a/OpenRA.Game/Traits/EditorAppearance.cs +++ b/OpenRA.Game/Traits/EditorAppearance.cs @@ -1,19 +1,19 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.Traits -{ - public class EditorAppearanceInfo : TraitInfo - { - public readonly bool RelativeToTopLeft = false; - } - - public class EditorAppearance { } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.Traits +{ + public class EditorAppearanceInfo : TraitInfo + { + public readonly bool RelativeToTopLeft = false; + } + + public class EditorAppearance { } +} diff --git a/OpenRA.Game/Traits/Health.cs b/OpenRA.Game/Traits/Health.cs index 3a6995e8b2..18f27fb4da 100755 --- a/OpenRA.Game/Traits/Health.cs +++ b/OpenRA.Game/Traits/Health.cs @@ -1,15 +1,15 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Linq; -using OpenRA.FileFormats; +#endregion + +using System.Linq; +using OpenRA.FileFormats; using OpenRA.GameRules; namespace OpenRA.Traits @@ -17,7 +17,7 @@ namespace OpenRA.Traits public class HealthInfo : ITraitInfo { public readonly int HP = 0; - public readonly float Radius = 10; + public readonly float Radius = 10; public virtual object Create(ActorInitializer init) { return new Health(init, this); } } @@ -38,10 +38,10 @@ namespace OpenRA.Traits } public int HP { get { return hp; } } - public readonly int MaxHP; - public float HPFraction - { - get { return hp * 1f / MaxHP; } + public readonly int MaxHP; + public float HPFraction + { + get { return hp * 1f / MaxHP; } } public bool IsDead { get { return hp <= 0; } } @@ -76,14 +76,14 @@ namespace OpenRA.Traits var oldState = this.DamageState; - /* apply the damage modifiers, if we have any. */ + /* apply the damage modifiers, if we have any. */ var modifier = (float)self.TraitsImplementing().Concat(self.Owner.PlayerActor.TraitsImplementing()) .Select(t => t.GetDamageModifier(attacker, warhead)).Product(); damage = (int)(damage * modifier); - hp -= damage; - + hp -= damage; + foreach (var nd in self.TraitsImplementing().Concat(self.Owner.PlayerActor.TraitsImplementing())) nd.Damaged(self, new AttackInfo { @@ -92,7 +92,7 @@ namespace OpenRA.Traits DamageState = this.DamageState, PreviousDamageState = oldState, DamageStateChanged = this.DamageState != oldState, - Warhead = warhead, + Warhead = warhead, PreviousHealth = hp + damage < 0 ? 0 : hp + damage, Health = hp }); @@ -102,9 +102,9 @@ namespace OpenRA.Traits hp = 0; attacker.Owner.Kills++; - self.Owner.Deaths++; - - if( RemoveOnDeath ) + self.Owner.Deaths++; + + if( RemoveOnDeath ) self.Destroy(); Log.Write("debug", "{0} #{1} killed by {2} #{3}", self.Info.Name, self.ActorID, attacker.Info.Name, attacker.ActorID); diff --git a/OpenRA.Game/Traits/LintAttributes.cs b/OpenRA.Game/Traits/LintAttributes.cs index 24ddc0e8f7..0044db45b7 100644 --- a/OpenRA.Game/Traits/LintAttributes.cs +++ b/OpenRA.Game/Traits/LintAttributes.cs @@ -1,25 +1,25 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; - -namespace OpenRA.Traits -{ - /* attributes used by RALint to understand the rules */ - - [AttributeUsage(AttributeTargets.Field)] - public class ActorReferenceAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Field)] - public class WeaponReferenceAttribute : Attribute { } - - [AttributeUsage(AttributeTargets.Field)] - public class VoiceReferenceAttribute : Attribute { } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; + +namespace OpenRA.Traits +{ + /* attributes used by RALint to understand the rules */ + + [AttributeUsage(AttributeTargets.Field)] + public class ActorReferenceAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Field)] + public class WeaponReferenceAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.Field)] + public class VoiceReferenceAttribute : Attribute { } +} diff --git a/OpenRA.Game/Traits/Player/DeveloperMode.cs b/OpenRA.Game/Traits/Player/DeveloperMode.cs index c2b7b50649..0b8975f66d 100644 --- a/OpenRA.Game/Traits/Player/DeveloperMode.cs +++ b/OpenRA.Game/Traits/Player/DeveloperMode.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion @@ -18,9 +18,9 @@ namespace OpenRA.Traits public bool FastBuild = false; public bool FastCharge = false; public bool DisableShroud = false; - public bool PathDebug = false; - public bool UnitInfluenceDebug = false; - public bool UnlimitedPower; + public bool PathDebug = false; + public bool UnitInfluenceDebug = false; + public bool UnlimitedPower; public object Create (ActorInitializer init) { return new DeveloperMode(this); } } @@ -33,7 +33,7 @@ namespace OpenRA.Traits [Sync] public bool FastBuild; [Sync] public bool DisableShroud; [Sync] public bool PathDebug; - [Sync] public bool UnitInfluenceDebug; + [Sync] public bool UnitInfluenceDebug; [Sync] public bool UnlimitedPower; public DeveloperMode(DeveloperModeInfo info) @@ -42,8 +42,8 @@ namespace OpenRA.Traits FastBuild = Info.FastBuild; FastCharge = Info.FastCharge; DisableShroud = Info.DisableShroud; - PathDebug = Info.PathDebug; - UnitInfluenceDebug = info.UnitInfluenceDebug; + PathDebug = Info.PathDebug; + UnitInfluenceDebug = info.UnitInfluenceDebug; UnlimitedPower = info.UnlimitedPower; } @@ -86,7 +86,7 @@ namespace OpenRA.Traits break; } case "DevUnitDebug": - { + { UnitInfluenceDebug ^= true; break; } @@ -95,11 +95,11 @@ namespace OpenRA.Traits if (self.World.LocalPlayer == self.Owner) self.World.WorldActor.Trait().ExploreAll(self.World); break; - } - case "DevUnlimitedPower": - { - UnlimitedPower ^= true; - break; + } + case "DevUnlimitedPower": + { + UnlimitedPower ^= true; + break; } default: return; diff --git a/OpenRA.Game/Traits/Player/EvaAlerts.cs b/OpenRA.Game/Traits/Player/EvaAlerts.cs index a398ddd0c3..7f310df8e2 100644 --- a/OpenRA.Game/Traits/Player/EvaAlerts.cs +++ b/OpenRA.Game/Traits/Player/EvaAlerts.cs @@ -1,43 +1,43 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.Traits -{ - public class EvaAlertsInfo : TraitInfo - { - // Sound effects - public readonly string RadarUp = "radaron2.aud"; - public readonly string RadarDown = "radardn1.aud"; - - public readonly string CashTickUp = "cashup1.aud"; - public readonly string CashTickDown = "cashdn1.aud"; - - // Build Palette - public readonly string BuildingCannotPlaceAudio = "nodeply1.aud"; - public readonly string NewOptions = "newopt1.aud"; - - // For manual powerup/down in ra-ng - public readonly string DisablePower = "bleep11.aud"; - public readonly string EnablePower = "bleep12.aud"; - - // Eva speech - public readonly string Repairing = "repair1.aud"; - public readonly string LowPower = "lopower1.aud"; - public readonly string SilosNeeded = "silond1.aud"; - public readonly string PrimaryBuildingSelected = "pribldg1.aud"; - - // Special powers - public readonly string AbilityInsufficientPower = "nopowr1.aud"; - - public readonly string LevelUp = "hydrod1.aud"; - } - - public class EvaAlerts {} -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.Traits +{ + public class EvaAlertsInfo : TraitInfo + { + // Sound effects + public readonly string RadarUp = "radaron2.aud"; + public readonly string RadarDown = "radardn1.aud"; + + public readonly string CashTickUp = "cashup1.aud"; + public readonly string CashTickDown = "cashdn1.aud"; + + // Build Palette + public readonly string BuildingCannotPlaceAudio = "nodeply1.aud"; + public readonly string NewOptions = "newopt1.aud"; + + // For manual powerup/down in ra-ng + public readonly string DisablePower = "bleep11.aud"; + public readonly string EnablePower = "bleep12.aud"; + + // Eva speech + public readonly string Repairing = "repair1.aud"; + public readonly string LowPower = "lopower1.aud"; + public readonly string SilosNeeded = "silond1.aud"; + public readonly string PrimaryBuildingSelected = "pribldg1.aud"; + + // Special powers + public readonly string AbilityInsufficientPower = "nopowr1.aud"; + + public readonly string LevelUp = "hydrod1.aud"; + } + + public class EvaAlerts {} +} diff --git a/OpenRA.Game/Traits/Player/PlayerResources.cs b/OpenRA.Game/Traits/Player/PlayerResources.cs index e833840ea6..fc622289df 100644 --- a/OpenRA.Game/Traits/Player/PlayerResources.cs +++ b/OpenRA.Game/Traits/Player/PlayerResources.cs @@ -1,181 +1,181 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; - -namespace OpenRA.Traits -{ - public class PlayerResourcesInfo : ITraitInfo - { - public readonly int InitialCash = 10000; - public readonly int InitialOre = 0; - public readonly int AdviceInterval = 250; - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; + +namespace OpenRA.Traits +{ + public class PlayerResourcesInfo : ITraitInfo + { + public readonly int InitialCash = 10000; + public readonly int InitialOre = 0; + public readonly int AdviceInterval = 250; + public object Create(ActorInitializer init) { return new PlayerResources(init.self, this); } - } - - public class DebugResourceCashInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new DebugResourceCash(init.self); } - } - public class DebugResourceCash : ISync - { - readonly Actor self; - public DebugResourceCash(Actor self){this.self = self;} - [Sync] public int foo { get { return self.Trait().Cash; } } - } - - public class DebugResourceOreInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new DebugResourceOre(init.self); } - } - public class DebugResourceOre : ISync - { - readonly Actor self; - public DebugResourceOre(Actor self){this.self = self;} - [Sync] public int foo { get { return self.Trait().Ore; } } - } - - public class DebugResourceOreCapacityInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new DebugResourceOreCapacity(init.self); } - } - public class DebugResourceOreCapacity : ISync - { - readonly Actor self; - public DebugResourceOreCapacity(Actor self){this.self = self;} - [Sync] public int foo { get { return self.Trait().OreCapacity; } } - } - - public class PlayerResources : ITick, ISync - { - readonly Player Owner; - int AdviceInterval; - - public PlayerResources(Actor self, PlayerResourcesInfo info) - { - Owner = self.Owner; - - Cash = info.InitialCash; - Ore = info.InitialOre; - AdviceInterval = info.AdviceInterval; - } - - [Sync] - public int Cash; - - [Sync] - public int Ore; - [Sync] - public int OreCapacity; - - public int DisplayCash; - public int DisplayOre; - - public bool CanGiveOre(int amount) - { - return Ore + amount <= OreCapacity; - } - - public void GiveOre(int num) - { - Ore += num; - - if (Ore > OreCapacity) - { - nextSiloAdviceTime = 0; - Ore = OreCapacity; - } - } - - public bool TakeOre(int num) - { - if (Ore < num) return false; - Ore -= num; - - return true; - } - - public void GiveCash(int num) - { - Cash += num; - } - - public bool TakeCash(int num) - { - if (Cash + Ore < num) return false; - - // Spend ore before cash - Ore -= num; - if (Ore < 0) - { - Cash += Ore; - Ore = 0; - } - - return true; - } - - const float displayCashFracPerFrame = .07f; - const int displayCashDeltaPerFrame = 37; - int nextSiloAdviceTime = 0; - - public void Tick(Actor self) - { - var eva = self.World.WorldActor.Info.Traits.Get(); - - OreCapacity = self.World.Queries.OwnedBy[Owner].WithTrait() - .Sum(a => a.Trait.Capacity); - - if (Ore > OreCapacity) - Ore = OreCapacity; - - if (--nextSiloAdviceTime <= 0) - { - if (Ore > 0.8*OreCapacity) - Owner.GiveAdvice(eva.SilosNeeded); - - nextSiloAdviceTime = AdviceInterval; - } - - var diff = Math.Abs(Cash - DisplayCash); - var move = Math.Min(Math.Max((int)(diff * displayCashFracPerFrame), - displayCashDeltaPerFrame), diff); - - - if (DisplayCash < Cash) - { - DisplayCash += move; - Sound.PlayToPlayer(self.Owner, eva.CashTickUp); - } - else if (DisplayCash > Cash) - { - DisplayCash -= move; - Sound.PlayToPlayer(self.Owner, eva.CashTickDown); - } - - diff = Math.Abs(Ore - DisplayOre); - move = Math.Min(Math.Max((int)(diff * displayCashFracPerFrame), - displayCashDeltaPerFrame), diff); - - if (DisplayOre < Ore) - { - DisplayOre += move; - Sound.PlayToPlayer(self.Owner, eva.CashTickUp); - } - else if (DisplayOre > Ore) - { - DisplayOre -= move; - Sound.PlayToPlayer(self.Owner, eva.CashTickDown); - } - } - } -} + } + + public class DebugResourceCashInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new DebugResourceCash(init.self); } + } + public class DebugResourceCash : ISync + { + readonly Actor self; + public DebugResourceCash(Actor self){this.self = self;} + [Sync] public int foo { get { return self.Trait().Cash; } } + } + + public class DebugResourceOreInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new DebugResourceOre(init.self); } + } + public class DebugResourceOre : ISync + { + readonly Actor self; + public DebugResourceOre(Actor self){this.self = self;} + [Sync] public int foo { get { return self.Trait().Ore; } } + } + + public class DebugResourceOreCapacityInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new DebugResourceOreCapacity(init.self); } + } + public class DebugResourceOreCapacity : ISync + { + readonly Actor self; + public DebugResourceOreCapacity(Actor self){this.self = self;} + [Sync] public int foo { get { return self.Trait().OreCapacity; } } + } + + public class PlayerResources : ITick, ISync + { + readonly Player Owner; + int AdviceInterval; + + public PlayerResources(Actor self, PlayerResourcesInfo info) + { + Owner = self.Owner; + + Cash = info.InitialCash; + Ore = info.InitialOre; + AdviceInterval = info.AdviceInterval; + } + + [Sync] + public int Cash; + + [Sync] + public int Ore; + [Sync] + public int OreCapacity; + + public int DisplayCash; + public int DisplayOre; + + public bool CanGiveOre(int amount) + { + return Ore + amount <= OreCapacity; + } + + public void GiveOre(int num) + { + Ore += num; + + if (Ore > OreCapacity) + { + nextSiloAdviceTime = 0; + Ore = OreCapacity; + } + } + + public bool TakeOre(int num) + { + if (Ore < num) return false; + Ore -= num; + + return true; + } + + public void GiveCash(int num) + { + Cash += num; + } + + public bool TakeCash(int num) + { + if (Cash + Ore < num) return false; + + // Spend ore before cash + Ore -= num; + if (Ore < 0) + { + Cash += Ore; + Ore = 0; + } + + return true; + } + + const float displayCashFracPerFrame = .07f; + const int displayCashDeltaPerFrame = 37; + int nextSiloAdviceTime = 0; + + public void Tick(Actor self) + { + var eva = self.World.WorldActor.Info.Traits.Get(); + + OreCapacity = self.World.Queries.OwnedBy[Owner].WithTrait() + .Sum(a => a.Trait.Capacity); + + if (Ore > OreCapacity) + Ore = OreCapacity; + + if (--nextSiloAdviceTime <= 0) + { + if (Ore > 0.8*OreCapacity) + Owner.GiveAdvice(eva.SilosNeeded); + + nextSiloAdviceTime = AdviceInterval; + } + + var diff = Math.Abs(Cash - DisplayCash); + var move = Math.Min(Math.Max((int)(diff * displayCashFracPerFrame), + displayCashDeltaPerFrame), diff); + + + if (DisplayCash < Cash) + { + DisplayCash += move; + Sound.PlayToPlayer(self.Owner, eva.CashTickUp); + } + else if (DisplayCash > Cash) + { + DisplayCash -= move; + Sound.PlayToPlayer(self.Owner, eva.CashTickDown); + } + + diff = Math.Abs(Ore - DisplayOre); + move = Math.Min(Math.Max((int)(diff * displayCashFracPerFrame), + displayCashDeltaPerFrame), diff); + + if (DisplayOre < Ore) + { + DisplayOre += move; + Sound.PlayToPlayer(self.Owner, eva.CashTickUp); + } + else if (DisplayOre > Ore) + { + DisplayOre -= move; + Sound.PlayToPlayer(self.Owner, eva.CashTickDown); + } + } + } +} diff --git a/OpenRA.Game/Traits/Render/RenderSimple.cs b/OpenRA.Game/Traits/Render/RenderSimple.cs index 67e93f1002..ab5fe255fe 100755 --- a/OpenRA.Game/Traits/Render/RenderSimple.cs +++ b/OpenRA.Game/Traits/Render/RenderSimple.cs @@ -1,134 +1,134 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.Graphics; - -namespace OpenRA.Traits -{ - public abstract class RenderSimpleInfo : ITraitInfo - { - public readonly string Image = null; - public readonly string[] OverrideTileset = null; - public readonly string[] OverrideImage = null; - public readonly string Palette = null; - public readonly float Scale = 1f; - public abstract object Create(ActorInitializer init); - - public virtual IEnumerable RenderPreview(ActorInfo building, string Tileset) - { - var anim = new Animation(RenderSimple.GetImage(building, Tileset), () => 0); - anim.PlayRepeating("idle"); - var rb = building.Traits.Get(); - yield return new Renderable(anim.Image, 0.5f * anim.Image.size * (1 - Scale), rb.Palette, 0, Scale); - } - } - - public abstract class RenderSimple : IRender, ITick - { - public Dictionary anims = new Dictionary(); - public Animation anim { get { return anims[""].Animation; } protected set { anims[""].Animation = value; } } - - public static string GetImage(ActorInfo actor, string Tileset) - { - var Info = actor.Traits.Get(); - if (Info.OverrideTileset != null && Tileset != null) - for (int i = 0; i < Info.OverrideTileset.Length; i++) - if (Info.OverrideTileset[i] == Tileset) - return Info.OverrideImage[i]; - - return Info.Image ?? actor.Name; - } - - string cachedImage = null; - public string GetImage(Actor self) - { - if (cachedImage != null) - return cachedImage; - - return cachedImage = GetImage(self.Info, self.World.Map.Tileset); - } - - RenderSimpleInfo Info; - public RenderSimple(Actor self, Func baseFacing) - { - anims.Add( "", new Animation( GetImage(self), baseFacing ) ); - Info = self.Info.Traits.Get(); - } - - public virtual IEnumerable Render( Actor self ) - { - - foreach( var a in anims.Values ) - if( a.DisableFunc == null || !a.DisableFunc() ) - { - Renderable ret = a.Image( self ); - if (Info.Scale != 1f) - ret = ret.WithScale(Info.Scale).WithPos(ret.Pos + 0.5f*ret.Sprite.size*(1 - Info.Scale)); - yield return ( Info.Palette == null ) ? ret : ret.WithPalette(Info.Palette); - } - } - - public virtual void Tick(Actor self) - { - foreach( var a in anims.Values ) - a.Animation.Tick(); - } - - protected virtual string NormalizeSequence(Actor self, string baseSequence) - { - string damageState = self.GetDamageState() >= DamageState.Heavy ? "damaged-" : ""; - if (anim.HasSequence(damageState + baseSequence)) - return damageState + baseSequence; - else - return baseSequence; - } - - public void PlayCustomAnim(Actor self, string name) - { - if (anim.HasSequence(name)) - anim.PlayThen(NormalizeSequence(self, name), - () => anim.PlayRepeating(NormalizeSequence(self, "idle"))); - } - - public class AnimationWithOffset - { - public Animation Animation; - public Func OffsetFunc; - public Func DisableFunc; - public int ZOffset; - - public AnimationWithOffset( Animation a ) - : this( a, null, null ) - { - } - - public AnimationWithOffset( Animation a, Func o, Func d ) - { - this.Animation = a; - this.OffsetFunc = o; - this.DisableFunc = d; - } - - public Renderable Image( Actor self ) - { - var r = Util.Centered( self, Animation.Image, self.CenterLocation - + (OffsetFunc != null ? OffsetFunc() : float2.Zero) ); - return ZOffset != 0 ? r.WithZOffset(ZOffset) : r; - } - - public static implicit operator AnimationWithOffset( Animation a ) - { - return new AnimationWithOffset( a ); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Graphics; + +namespace OpenRA.Traits +{ + public abstract class RenderSimpleInfo : ITraitInfo + { + public readonly string Image = null; + public readonly string[] OverrideTileset = null; + public readonly string[] OverrideImage = null; + public readonly string Palette = null; + public readonly float Scale = 1f; + public abstract object Create(ActorInitializer init); + + public virtual IEnumerable RenderPreview(ActorInfo building, string Tileset) + { + var anim = new Animation(RenderSimple.GetImage(building, Tileset), () => 0); + anim.PlayRepeating("idle"); + var rb = building.Traits.Get(); + yield return new Renderable(anim.Image, 0.5f * anim.Image.size * (1 - Scale), rb.Palette, 0, Scale); + } + } + + public abstract class RenderSimple : IRender, ITick + { + public Dictionary anims = new Dictionary(); + public Animation anim { get { return anims[""].Animation; } protected set { anims[""].Animation = value; } } + + public static string GetImage(ActorInfo actor, string Tileset) + { + var Info = actor.Traits.Get(); + if (Info.OverrideTileset != null && Tileset != null) + for (int i = 0; i < Info.OverrideTileset.Length; i++) + if (Info.OverrideTileset[i] == Tileset) + return Info.OverrideImage[i]; + + return Info.Image ?? actor.Name; + } + + string cachedImage = null; + public string GetImage(Actor self) + { + if (cachedImage != null) + return cachedImage; + + return cachedImage = GetImage(self.Info, self.World.Map.Tileset); + } + + RenderSimpleInfo Info; + public RenderSimple(Actor self, Func baseFacing) + { + anims.Add( "", new Animation( GetImage(self), baseFacing ) ); + Info = self.Info.Traits.Get(); + } + + public virtual IEnumerable Render( Actor self ) + { + + foreach( var a in anims.Values ) + if( a.DisableFunc == null || !a.DisableFunc() ) + { + Renderable ret = a.Image( self ); + if (Info.Scale != 1f) + ret = ret.WithScale(Info.Scale).WithPos(ret.Pos + 0.5f*ret.Sprite.size*(1 - Info.Scale)); + yield return ( Info.Palette == null ) ? ret : ret.WithPalette(Info.Palette); + } + } + + public virtual void Tick(Actor self) + { + foreach( var a in anims.Values ) + a.Animation.Tick(); + } + + protected virtual string NormalizeSequence(Actor self, string baseSequence) + { + string damageState = self.GetDamageState() >= DamageState.Heavy ? "damaged-" : ""; + if (anim.HasSequence(damageState + baseSequence)) + return damageState + baseSequence; + else + return baseSequence; + } + + public void PlayCustomAnim(Actor self, string name) + { + if (anim.HasSequence(name)) + anim.PlayThen(NormalizeSequence(self, name), + () => anim.PlayRepeating(NormalizeSequence(self, "idle"))); + } + + public class AnimationWithOffset + { + public Animation Animation; + public Func OffsetFunc; + public Func DisableFunc; + public int ZOffset; + + public AnimationWithOffset( Animation a ) + : this( a, null, null ) + { + } + + public AnimationWithOffset( Animation a, Func o, Func d ) + { + this.Animation = a; + this.OffsetFunc = o; + this.DisableFunc = d; + } + + public Renderable Image( Actor self ) + { + var r = Util.Centered( self, Animation.Image, self.CenterLocation + + (OffsetFunc != null ? OffsetFunc() : float2.Zero) ); + return ZOffset != 0 ? r.WithZOffset(ZOffset) : r; + } + + public static implicit operator AnimationWithOffset( Animation a ) + { + return new AnimationWithOffset( a ); + } + } + } +} diff --git a/OpenRA.Game/Traits/RevealsShroud.cs b/OpenRA.Game/Traits/RevealsShroud.cs index bb1ef01d80..36ade2425d 100644 --- a/OpenRA.Game/Traits/RevealsShroud.cs +++ b/OpenRA.Game/Traits/RevealsShroud.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Game/Traits/Selectable.cs index 99200b83d1..fec48baa04 100644 --- a/OpenRA.Game/Traits/Selectable.cs +++ b/OpenRA.Game/Traits/Selectable.cs @@ -1,194 +1,194 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; - -namespace OpenRA.Traits -{ - public class SelectableInfo : TraitInfo - { - public readonly int Priority = 10; - public readonly int[] Bounds = null; - [VoiceReference] - public readonly string Voice = null; - } - - public class Selectable : IPostRenderSelection - { - // depends on the order of pips in TraitsInterfaces.cs! - static readonly string[] pipStrings = { "pip-empty", "pip-green", "pip-yellow", "pip-red", "pip-gray" }; - static readonly string[] tagStrings = { "", "tag-fake", "tag-primary" }; - - public void RenderAfterWorld (WorldRenderer wr, Actor self) - { - var bounds = self.GetBounds(false); - Color selectionColor = Color.White; - - var xy = new float2(bounds.Left, bounds.Top); - var Xy = new float2(bounds.Right, bounds.Top); - var xY = new float2(bounds.Left, bounds.Bottom); - var XY = new float2(bounds.Right, bounds.Bottom); - - var colorResults = self.TraitsImplementing().Select(t => t.GetSelectionColorModifier(self, selectionColor)).Where( - c => c.ToArgb() != selectionColor.ToArgb()); - - if (colorResults.Any()) - selectionColor = colorResults.First(); - - DrawSelectionBox(self, xy, Xy, xY, XY, selectionColor); - DrawHealthBar(self, xy, Xy); - DrawControlGroup(wr, self, xy); - DrawPips(wr, self, xY); - DrawTags(wr, self, new float2(.5f * (bounds.Left + bounds.Right), bounds.Top)); - DrawUnitPath(self); - } - - void DrawSelectionBox(Actor self, float2 xy, float2 Xy, float2 xY, float2 XY, Color c) - { - Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(4, 0), c, c); - Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(0, 4), c, c); - Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(-4, 0), c, c); - Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(0, 4), c, c); - - Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(4, 0), c, c); - Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(0, -4), c, c); - Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(-4, 0), c, c); - Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c); - } - - void DrawHealthBar(Actor self, float2 xy, float2 Xy) - { - if (!self.IsInWorld) return; - - var health = self.TraitOrDefault(); - if (health == null || health.IsDead) return; - - var c = Color.Gray; - Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), xy + new float2(0, -4), c, c); - Game.Renderer.LineRenderer.DrawLine(Xy + new float2(0, -2), Xy + new float2(0, -4), c, c); - - var healthColor = (health.DamageState == DamageState.Critical) ? Color.Red : - (health.DamageState == DamageState.Heavy) ? Color.Yellow : Color.LimeGreen; - - var healthColor2 = Color.FromArgb( - 255, - healthColor.R / 2, - healthColor.G / 2, - healthColor.B / 2); - - var z = float2.Lerp(xy, Xy, health.HPFraction); - - Game.Renderer.LineRenderer.DrawLine(z + new float2(0, -4), Xy + new float2(0, -4), c, c); - Game.Renderer.LineRenderer.DrawLine(z + new float2(0, -2), Xy + new float2(0, -2), c, c); - - Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -3), z + new float2(0, -3), healthColor, healthColor); - Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), z + new float2(0, -2), healthColor2, healthColor2); - Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -4), z + new float2(0, -4), healthColor2, healthColor2); - } - - void DrawControlGroup(WorldRenderer wr, Actor self, float2 basePosition) - { - var group = self.World.Selection.GetControlGroupForActor(self); - if (group == null) return; - - var pipImages = new Animation("pips"); - pipImages.PlayFetchIndex("groups", () => (int)group); - pipImages.Tick(); - pipImages.Image.DrawAt(wr, basePosition + new float2(-8, 1), "chrome"); - } - - void DrawPips(WorldRenderer wr, Actor self, float2 basePosition) - { - if (self.Owner != self.World.LocalPlayer) return; - - // If a mod wants to implement a unit with multiple pip sources, then they are placed on multiple rows - var pipxyBase = basePosition + new float2(-12, -7); // Correct for the offset in the shp file - var pipxyOffset = new float2(0, 0); // Correct for offset due to multiple columns/rows - - foreach (var pips in self.TraitsImplementing()) - { - var thisRow = pips.GetPips(self); - if (thisRow == null) - continue; - - foreach (var pip in thisRow) - { - if (pipxyOffset.X+5 > self.GetBounds(false).Width) - { - pipxyOffset.X = 0; - pipxyOffset.Y -= 4; - } - var pipImages = new Animation("pips"); - pipImages.PlayRepeating(pipStrings[(int)pip]); - pipImages.Image.DrawAt(wr, pipxyBase + pipxyOffset, "chrome"); - pipxyOffset += new float2(4, 0); - } - // Increment row - pipxyOffset.X = 0; - pipxyOffset.Y -= 5; - } - } - - void DrawTags(WorldRenderer wr, Actor self, float2 basePosition) - { - if (self.Owner != self.World.LocalPlayer) return; - - // If a mod wants to implement a unit with multiple tags, then they are placed on multiple rows - var tagxyBase = basePosition + new float2(-16, 2); // Correct for the offset in the shp file - var tagxyOffset = new float2(0, 0); // Correct for offset due to multiple rows - - foreach (var tags in self.TraitsImplementing()) - { - foreach (var tag in tags.GetTags()) - { - if (tag == TagType.None) - continue; - - var tagImages = new Animation("pips"); - tagImages.PlayRepeating(tagStrings[(int)tag]); - tagImages.Image.DrawAt(wr, tagxyBase + tagxyOffset, "chrome"); - - // Increment row - tagxyOffset.Y += 8; - } - } - } - - void DrawUnitPath(Actor self) - { - if (self.World.LocalPlayer == null ||!self.World.LocalPlayer.PlayerActor.Trait().PathDebug) return; - - var activity = self.GetCurrentActivity(); - var mobile = self.TraitOrDefault(); - if (activity != null && mobile != null) - { - var alt = new float2(0, -mobile.Altitude); - var path = activity.GetCurrentPath(); - var start = self.CenterLocation + alt; - - var c = Color.Green; - - foreach (var step in path) - { - var stp = step + alt; - Game.Renderer.LineRenderer.DrawLine(stp + new float2(-1, -1), stp + new float2(-1, 1), c, c); - Game.Renderer.LineRenderer.DrawLine(stp + new float2(-1, 1), stp + new float2(1, 1), c, c); - Game.Renderer.LineRenderer.DrawLine(stp + new float2(1, 1), stp + new float2(1, -1), c, c); - Game.Renderer.LineRenderer.DrawLine(stp + new float2(1, -1), stp + new float2(-1, -1), c, c); - Game.Renderer.LineRenderer.DrawLine(start, stp, c, c); - start = stp; - } - } - } - - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; + +namespace OpenRA.Traits +{ + public class SelectableInfo : TraitInfo + { + public readonly int Priority = 10; + public readonly int[] Bounds = null; + [VoiceReference] + public readonly string Voice = null; + } + + public class Selectable : IPostRenderSelection + { + // depends on the order of pips in TraitsInterfaces.cs! + static readonly string[] pipStrings = { "pip-empty", "pip-green", "pip-yellow", "pip-red", "pip-gray" }; + static readonly string[] tagStrings = { "", "tag-fake", "tag-primary" }; + + public void RenderAfterWorld (WorldRenderer wr, Actor self) + { + var bounds = self.GetBounds(false); + Color selectionColor = Color.White; + + var xy = new float2(bounds.Left, bounds.Top); + var Xy = new float2(bounds.Right, bounds.Top); + var xY = new float2(bounds.Left, bounds.Bottom); + var XY = new float2(bounds.Right, bounds.Bottom); + + var colorResults = self.TraitsImplementing().Select(t => t.GetSelectionColorModifier(self, selectionColor)).Where( + c => c.ToArgb() != selectionColor.ToArgb()); + + if (colorResults.Any()) + selectionColor = colorResults.First(); + + DrawSelectionBox(self, xy, Xy, xY, XY, selectionColor); + DrawHealthBar(self, xy, Xy); + DrawControlGroup(wr, self, xy); + DrawPips(wr, self, xY); + DrawTags(wr, self, new float2(.5f * (bounds.Left + bounds.Right), bounds.Top)); + DrawUnitPath(self); + } + + void DrawSelectionBox(Actor self, float2 xy, float2 Xy, float2 xY, float2 XY, Color c) + { + Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(4, 0), c, c); + Game.Renderer.LineRenderer.DrawLine(xy, xy + new float2(0, 4), c, c); + Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(-4, 0), c, c); + Game.Renderer.LineRenderer.DrawLine(Xy, Xy + new float2(0, 4), c, c); + + Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(4, 0), c, c); + Game.Renderer.LineRenderer.DrawLine(xY, xY + new float2(0, -4), c, c); + Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(-4, 0), c, c); + Game.Renderer.LineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c); + } + + void DrawHealthBar(Actor self, float2 xy, float2 Xy) + { + if (!self.IsInWorld) return; + + var health = self.TraitOrDefault(); + if (health == null || health.IsDead) return; + + var c = Color.Gray; + Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), xy + new float2(0, -4), c, c); + Game.Renderer.LineRenderer.DrawLine(Xy + new float2(0, -2), Xy + new float2(0, -4), c, c); + + var healthColor = (health.DamageState == DamageState.Critical) ? Color.Red : + (health.DamageState == DamageState.Heavy) ? Color.Yellow : Color.LimeGreen; + + var healthColor2 = Color.FromArgb( + 255, + healthColor.R / 2, + healthColor.G / 2, + healthColor.B / 2); + + var z = float2.Lerp(xy, Xy, health.HPFraction); + + Game.Renderer.LineRenderer.DrawLine(z + new float2(0, -4), Xy + new float2(0, -4), c, c); + Game.Renderer.LineRenderer.DrawLine(z + new float2(0, -2), Xy + new float2(0, -2), c, c); + + Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -3), z + new float2(0, -3), healthColor, healthColor); + Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -2), z + new float2(0, -2), healthColor2, healthColor2); + Game.Renderer.LineRenderer.DrawLine(xy + new float2(0, -4), z + new float2(0, -4), healthColor2, healthColor2); + } + + void DrawControlGroup(WorldRenderer wr, Actor self, float2 basePosition) + { + var group = self.World.Selection.GetControlGroupForActor(self); + if (group == null) return; + + var pipImages = new Animation("pips"); + pipImages.PlayFetchIndex("groups", () => (int)group); + pipImages.Tick(); + pipImages.Image.DrawAt(wr, basePosition + new float2(-8, 1), "chrome"); + } + + void DrawPips(WorldRenderer wr, Actor self, float2 basePosition) + { + if (self.Owner != self.World.LocalPlayer) return; + + // If a mod wants to implement a unit with multiple pip sources, then they are placed on multiple rows + var pipxyBase = basePosition + new float2(-12, -7); // Correct for the offset in the shp file + var pipxyOffset = new float2(0, 0); // Correct for offset due to multiple columns/rows + + foreach (var pips in self.TraitsImplementing()) + { + var thisRow = pips.GetPips(self); + if (thisRow == null) + continue; + + foreach (var pip in thisRow) + { + if (pipxyOffset.X+5 > self.GetBounds(false).Width) + { + pipxyOffset.X = 0; + pipxyOffset.Y -= 4; + } + var pipImages = new Animation("pips"); + pipImages.PlayRepeating(pipStrings[(int)pip]); + pipImages.Image.DrawAt(wr, pipxyBase + pipxyOffset, "chrome"); + pipxyOffset += new float2(4, 0); + } + // Increment row + pipxyOffset.X = 0; + pipxyOffset.Y -= 5; + } + } + + void DrawTags(WorldRenderer wr, Actor self, float2 basePosition) + { + if (self.Owner != self.World.LocalPlayer) return; + + // If a mod wants to implement a unit with multiple tags, then they are placed on multiple rows + var tagxyBase = basePosition + new float2(-16, 2); // Correct for the offset in the shp file + var tagxyOffset = new float2(0, 0); // Correct for offset due to multiple rows + + foreach (var tags in self.TraitsImplementing()) + { + foreach (var tag in tags.GetTags()) + { + if (tag == TagType.None) + continue; + + var tagImages = new Animation("pips"); + tagImages.PlayRepeating(tagStrings[(int)tag]); + tagImages.Image.DrawAt(wr, tagxyBase + tagxyOffset, "chrome"); + + // Increment row + tagxyOffset.Y += 8; + } + } + } + + void DrawUnitPath(Actor self) + { + if (self.World.LocalPlayer == null ||!self.World.LocalPlayer.PlayerActor.Trait().PathDebug) return; + + var activity = self.GetCurrentActivity(); + var mobile = self.TraitOrDefault(); + if (activity != null && mobile != null) + { + var alt = new float2(0, -mobile.Altitude); + var path = activity.GetCurrentPath(); + var start = self.CenterLocation + alt; + + var c = Color.Green; + + foreach (var step in path) + { + var stp = step + alt; + Game.Renderer.LineRenderer.DrawLine(stp + new float2(-1, -1), stp + new float2(-1, 1), c, c); + Game.Renderer.LineRenderer.DrawLine(stp + new float2(-1, 1), stp + new float2(1, 1), c, c); + Game.Renderer.LineRenderer.DrawLine(stp + new float2(1, 1), stp + new float2(1, -1), c, c); + Game.Renderer.LineRenderer.DrawLine(stp + new float2(1, -1), stp + new float2(-1, -1), c, c); + Game.Renderer.LineRenderer.DrawLine(start, stp, c, c); + start = stp; + } + } + } + + } +} diff --git a/OpenRA.Game/Traits/Target.cs b/OpenRA.Game/Traits/Target.cs index 2462b59881..9e8c1fa91d 100644 --- a/OpenRA.Game/Traits/Target.cs +++ b/OpenRA.Game/Traits/Target.cs @@ -1,47 +1,47 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.Traits -{ - public struct Target // a target: either an actor, or a fixed location. - { - Actor actor; - Player owner; - int2 pos; - bool valid; - - public static Target FromActor(Actor a) - { - return new Target - { - actor = a, - valid = (a != null), - owner = (a != null) ? a.Owner : null - }; - } - public static Target FromPos(int2 p) { return new Target { pos = p, valid = true }; } - public static Target FromCell(int2 c) { return new Target { pos = Util.CenterOfCell(c), valid = true }; } - public static Target FromOrder(Order o) - { - return o.TargetActor != null - ? Target.FromActor(o.TargetActor) - : Target.FromCell(o.TargetLocation); - } - - public static readonly Target None = new Target(); - - public bool IsValid { get { return valid && (actor == null || (actor.IsInWorld && actor.Owner == owner)); } } - public int2 PxPosition { get { return IsActor ? actor.Trait().PxPosition : pos; } } - public int2 CenterLocation { get { return PxPosition; } } - - public Actor Actor { get { return IsActor ? actor : null; } } - public bool IsActor { get { return actor != null && !actor.Destroyed; } } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.Traits +{ + public struct Target // a target: either an actor, or a fixed location. + { + Actor actor; + Player owner; + int2 pos; + bool valid; + + public static Target FromActor(Actor a) + { + return new Target + { + actor = a, + valid = (a != null), + owner = (a != null) ? a.Owner : null + }; + } + public static Target FromPos(int2 p) { return new Target { pos = p, valid = true }; } + public static Target FromCell(int2 c) { return new Target { pos = Util.CenterOfCell(c), valid = true }; } + public static Target FromOrder(Order o) + { + return o.TargetActor != null + ? Target.FromActor(o.TargetActor) + : Target.FromCell(o.TargetLocation); + } + + public static readonly Target None = new Target(); + + public bool IsValid { get { return valid && (actor == null || (actor.IsInWorld && actor.Owner == owner)); } } + public int2 PxPosition { get { return IsActor ? actor.Trait().PxPosition : pos; } } + public int2 CenterLocation { get { return PxPosition; } } + + public Actor Actor { get { return IsActor ? actor : null; } } + public bool IsActor { get { return actor != null && !actor.Destroyed; } } + } +} diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 5975f12cf6..e80d6071d3 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -1,232 +1,232 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using OpenRA.FileFormats; -using OpenRA.GameRules; -using OpenRA.Graphics; -using OpenRA.Network; - -namespace OpenRA.Traits -{ - // depends on the order of pips in WorldRenderer.cs! - public enum PipType { Transparent, Green, Yellow, Red, Gray }; - public enum TagType { None, Fake, Primary }; - public enum Stance { Enemy, Neutral, Ally }; - - public class AttackInfo - { - public Actor Attacker; - public WarheadInfo Warhead; - public int Damage; - public DamageState DamageState; - public DamageState PreviousDamageState; - public bool DamageStateChanged; - public int PreviousHealth; - public int Health; - } - - public interface ITick { void Tick(Actor self); } - public interface IRender { IEnumerable Render(Actor self); } - - public interface IIssueOrder - { - IEnumerable Orders { get; } - Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ); - } - public interface IOrderTargeter - { - string OrderID { get; } - int OrderPriority { get; } - bool CanTargetActor( Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueue, ref string cursor ); - bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceQueue, bool forceMove, ref string cursor); - bool IsQueued { get; } - } - public interface IResolveOrder { void ResolveOrder(Actor self, Order order); } - public interface IValidateOrder { bool OrderValidation(OrderManager orderManager, World world, int clientId, Order order); - } - public interface IOrderCursor { string CursorForOrder(Actor self, Order order); } - public interface IOrderVoice { string VoicePhraseForOrder(Actor self, Order order); } - public interface ICustomUnitOrderGenerator : IOrderGenerator {}; - public interface INotifySold { void Selling( Actor self ); void Sold( Actor self ); } - public interface INotifyDamage { void Damaged(Actor self, AttackInfo e); } - public interface INotifyBuildComplete { void BuildingComplete(Actor self); } - public interface INotifyProduction { void UnitProduced(Actor self, Actor other, int2 exit); } - public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); } - public interface INotifyOtherCaptured { void OnActorCaptured(Actor self, Actor captured, Actor captor, Player oldOwner, Player newOwner); } - public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); } - public interface IStoreOre { int Capacity { get; }} - - public interface IDisable { bool Disabled { get; } } - public interface IExplodeModifier { bool ShouldExplode(Actor self); } - public interface INudge { void OnNudge(Actor self, Actor nudger); } - - public interface IRadarSignature - { - IEnumerable RadarSignatureCells(Actor self); - Color RadarSignatureColor(Actor self); - } - - public interface IVisibilityModifier { bool IsVisible(Actor self); } - public interface IRadarColorModifier { Color RadarColorOverride(Actor self); } - public interface IHasLocation - { - int2 PxPosition { get; } - } - - public enum SubCell - { - FullCell, - TopLeft, - TopRight, - Center, - BottomLeft, - BottomRight - } - - public interface IOccupySpace : IHasLocation - { - int2 TopLeft { get; } - IEnumerable> OccupiedCells(); - } - - public static class IOccupySpaceExts - { - public static int2 NearestCellTo( this IOccupySpace ios, int2 other ) - { - var nearest = ios.TopLeft; - var nearestDistance = int.MaxValue; - foreach( var cell in ios.OccupiedCells() ) - { - var dist = ( other - cell.First ).LengthSquared; - if( dist < nearestDistance ) - { - nearest = cell.First; - nearestDistance = dist; - } - } - return nearest; - } - } - - public interface INotifyAttack { void Attacking(Actor self, Target target); } - public interface IRenderModifier { IEnumerable ModifyRender(Actor self, IEnumerable r); } - public interface IDamageModifier { float GetDamageModifier(Actor attacker, WarheadInfo warhead); } - public interface ISpeedModifier { decimal GetSpeedModifier(); } - public interface IFirepowerModifier { float GetFirepowerModifier(); } - public interface ISelectionColorModifier { Color GetSelectionColorModifier(Actor self, Color defaultColor); } - public interface IPalette { void InitPalette( WorldRenderer wr ); } - public interface IPaletteModifier { void AdjustPalette(Dictionary b); } - public interface IPips { IEnumerable GetPips(Actor self); } - public interface ITags { IEnumerable GetTags(); } - - public interface ITeleportable : IHasLocation /* crap name! */ - { - bool CanEnterCell(int2 location); - void SetPosition(Actor self, int2 cell); - void SetPxPosition(Actor self, int2 px); - void AdjustPxPosition(Actor self, int2 px); /* works like SetPxPosition, but visual only */ - } - - public interface IMove : ITeleportable - { - int Altitude { get; set; } - } - - public interface IFacing - { - int ROT { get; } - int Facing { get; set; } - int InitialFacing { get; } - } - - public interface ICrushable - { - void OnCrush(Actor crusher); - IEnumerable CrushClasses { get; } - } - - public struct Renderable - { - public readonly Sprite Sprite; - public readonly float2 Pos; - public readonly string Palette; - public readonly int Z; - public readonly int ZOffset; - public float Scale; - - public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset, float scale) - { - Sprite = sprite; - Pos = pos; - Palette = palette; - Z = z; - ZOffset = zOffset; - Scale = scale; /* default */ - } - - public Renderable(Sprite sprite, float2 pos, string palette, int z) - : this(sprite, pos, palette, z, 0, 1f) { } - - public Renderable(Sprite sprite, float2 pos, string palette, int z, float scale) - : this(sprite, pos, palette, z, 0, scale) { } - - public Renderable WithScale(float newScale) { return new Renderable(Sprite, Pos, Palette, Z, ZOffset, newScale); } - public Renderable WithPalette(string newPalette) { return new Renderable(Sprite, Pos, newPalette, Z, ZOffset, Scale); } - public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, Z, newOffset, Scale); } - public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, Z, ZOffset, Scale); } - } - - public interface ITraitInfo { object Create(ActorInitializer init); } - - public class TraitInfo : ITraitInfo where T : new() { public virtual object Create(ActorInitializer init) { return new T(); } } - - public interface ITraitPrerequisite where T : ITraitInfo { } - - public interface INotifySelection { void SelectionChanged(); } - public interface IWorldLoaded { void WorldLoaded(World w); } - public interface ICreatePlayers { void CreatePlayers(World w); } - - public interface IBotInfo { string Name { get; } } - public interface IBot - { - void Activate(Player p); - IBotInfo Info { get; } - } - - public interface IActivity - { - IActivity Tick(Actor self); - void Cancel(Actor self); - void Queue(IActivity activity); - IEnumerable GetCurrentPath(); - } - - public interface IRenderOverlay { void Render( WorldRenderer wr ); } - public interface INotifyIdle { void TickIdle(Actor self); } - - public interface IBlocksBullets { } - - public interface IPostRender { void RenderAfterWorld(WorldRenderer wr, Actor self); } - - public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr, Actor self); } - public interface IPreRenderSelection { void RenderBeforeWorld(WorldRenderer wr, Actor self); } - public interface IRenderAsTerrain { IEnumerable RenderAsTerrain(Actor self); } - - public interface ITargetable - { - string[] TargetTypes { get; } - IEnumerable TargetableCells( Actor self ); - bool TargetableBy(Actor self, Actor byActor); - } - - public interface INotifyKeyPress { bool KeyPressed(Actor self, KeyInput e); } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using OpenRA.FileFormats; +using OpenRA.GameRules; +using OpenRA.Graphics; +using OpenRA.Network; + +namespace OpenRA.Traits +{ + // depends on the order of pips in WorldRenderer.cs! + public enum PipType { Transparent, Green, Yellow, Red, Gray }; + public enum TagType { None, Fake, Primary }; + public enum Stance { Enemy, Neutral, Ally }; + + public class AttackInfo + { + public Actor Attacker; + public WarheadInfo Warhead; + public int Damage; + public DamageState DamageState; + public DamageState PreviousDamageState; + public bool DamageStateChanged; + public int PreviousHealth; + public int Health; + } + + public interface ITick { void Tick(Actor self); } + public interface IRender { IEnumerable Render(Actor self); } + + public interface IIssueOrder + { + IEnumerable Orders { get; } + Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ); + } + public interface IOrderTargeter + { + string OrderID { get; } + int OrderPriority { get; } + bool CanTargetActor( Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueue, ref string cursor ); + bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceQueue, bool forceMove, ref string cursor); + bool IsQueued { get; } + } + public interface IResolveOrder { void ResolveOrder(Actor self, Order order); } + public interface IValidateOrder { bool OrderValidation(OrderManager orderManager, World world, int clientId, Order order); + } + public interface IOrderCursor { string CursorForOrder(Actor self, Order order); } + public interface IOrderVoice { string VoicePhraseForOrder(Actor self, Order order); } + public interface ICustomUnitOrderGenerator : IOrderGenerator {}; + public interface INotifySold { void Selling( Actor self ); void Sold( Actor self ); } + public interface INotifyDamage { void Damaged(Actor self, AttackInfo e); } + public interface INotifyBuildComplete { void BuildingComplete(Actor self); } + public interface INotifyProduction { void UnitProduced(Actor self, Actor other, int2 exit); } + public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); } + public interface INotifyOtherCaptured { void OnActorCaptured(Actor self, Actor captured, Actor captor, Player oldOwner, Player newOwner); } + public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); } + public interface IStoreOre { int Capacity { get; }} + + public interface IDisable { bool Disabled { get; } } + public interface IExplodeModifier { bool ShouldExplode(Actor self); } + public interface INudge { void OnNudge(Actor self, Actor nudger); } + + public interface IRadarSignature + { + IEnumerable RadarSignatureCells(Actor self); + Color RadarSignatureColor(Actor self); + } + + public interface IVisibilityModifier { bool IsVisible(Actor self); } + public interface IRadarColorModifier { Color RadarColorOverride(Actor self); } + public interface IHasLocation + { + int2 PxPosition { get; } + } + + public enum SubCell + { + FullCell, + TopLeft, + TopRight, + Center, + BottomLeft, + BottomRight + } + + public interface IOccupySpace : IHasLocation + { + int2 TopLeft { get; } + IEnumerable> OccupiedCells(); + } + + public static class IOccupySpaceExts + { + public static int2 NearestCellTo( this IOccupySpace ios, int2 other ) + { + var nearest = ios.TopLeft; + var nearestDistance = int.MaxValue; + foreach( var cell in ios.OccupiedCells() ) + { + var dist = ( other - cell.First ).LengthSquared; + if( dist < nearestDistance ) + { + nearest = cell.First; + nearestDistance = dist; + } + } + return nearest; + } + } + + public interface INotifyAttack { void Attacking(Actor self, Target target); } + public interface IRenderModifier { IEnumerable ModifyRender(Actor self, IEnumerable r); } + public interface IDamageModifier { float GetDamageModifier(Actor attacker, WarheadInfo warhead); } + public interface ISpeedModifier { decimal GetSpeedModifier(); } + public interface IFirepowerModifier { float GetFirepowerModifier(); } + public interface ISelectionColorModifier { Color GetSelectionColorModifier(Actor self, Color defaultColor); } + public interface IPalette { void InitPalette( WorldRenderer wr ); } + public interface IPaletteModifier { void AdjustPalette(Dictionary b); } + public interface IPips { IEnumerable GetPips(Actor self); } + public interface ITags { IEnumerable GetTags(); } + + public interface ITeleportable : IHasLocation /* crap name! */ + { + bool CanEnterCell(int2 location); + void SetPosition(Actor self, int2 cell); + void SetPxPosition(Actor self, int2 px); + void AdjustPxPosition(Actor self, int2 px); /* works like SetPxPosition, but visual only */ + } + + public interface IMove : ITeleportable + { + int Altitude { get; set; } + } + + public interface IFacing + { + int ROT { get; } + int Facing { get; set; } + int InitialFacing { get; } + } + + public interface ICrushable + { + void OnCrush(Actor crusher); + IEnumerable CrushClasses { get; } + } + + public struct Renderable + { + public readonly Sprite Sprite; + public readonly float2 Pos; + public readonly string Palette; + public readonly int Z; + public readonly int ZOffset; + public float Scale; + + public Renderable(Sprite sprite, float2 pos, string palette, int z, int zOffset, float scale) + { + Sprite = sprite; + Pos = pos; + Palette = palette; + Z = z; + ZOffset = zOffset; + Scale = scale; /* default */ + } + + public Renderable(Sprite sprite, float2 pos, string palette, int z) + : this(sprite, pos, palette, z, 0, 1f) { } + + public Renderable(Sprite sprite, float2 pos, string palette, int z, float scale) + : this(sprite, pos, palette, z, 0, scale) { } + + public Renderable WithScale(float newScale) { return new Renderable(Sprite, Pos, Palette, Z, ZOffset, newScale); } + public Renderable WithPalette(string newPalette) { return new Renderable(Sprite, Pos, newPalette, Z, ZOffset, Scale); } + public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, Z, newOffset, Scale); } + public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, Z, ZOffset, Scale); } + } + + public interface ITraitInfo { object Create(ActorInitializer init); } + + public class TraitInfo : ITraitInfo where T : new() { public virtual object Create(ActorInitializer init) { return new T(); } } + + public interface ITraitPrerequisite where T : ITraitInfo { } + + public interface INotifySelection { void SelectionChanged(); } + public interface IWorldLoaded { void WorldLoaded(World w); } + public interface ICreatePlayers { void CreatePlayers(World w); } + + public interface IBotInfo { string Name { get; } } + public interface IBot + { + void Activate(Player p); + IBotInfo Info { get; } + } + + public interface IActivity + { + IActivity Tick(Actor self); + void Cancel(Actor self); + void Queue(IActivity activity); + IEnumerable GetCurrentPath(); + } + + public interface IRenderOverlay { void Render( WorldRenderer wr ); } + public interface INotifyIdle { void TickIdle(Actor self); } + + public interface IBlocksBullets { } + + public interface IPostRender { void RenderAfterWorld(WorldRenderer wr, Actor self); } + + public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr, Actor self); } + public interface IPreRenderSelection { void RenderBeforeWorld(WorldRenderer wr, Actor self); } + public interface IRenderAsTerrain { IEnumerable RenderAsTerrain(Actor self); } + + public interface ITargetable + { + string[] TargetTypes { get; } + IEnumerable TargetableCells( Actor self ); + bool TargetableBy(Actor self, Actor byActor); + } + + public interface INotifyKeyPress { bool KeyPressed(Actor self, KeyInput e); } +} diff --git a/OpenRA.Game/Traits/Util.cs b/OpenRA.Game/Traits/Util.cs index 921803f13a..7db273f44a 100755 --- a/OpenRA.Game/Traits/Util.cs +++ b/OpenRA.Game/Traits/Util.cs @@ -1,443 +1,443 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Support; -using System.Collections.Generic; - -namespace OpenRA.Traits -{ - public static class Util - { - public static int TickFacing( int facing, int desiredFacing, int rot ) - { - var leftTurn = ( facing - desiredFacing ) & 0xFF; - var rightTurn = ( desiredFacing - facing ) & 0xFF; - if( Math.Min( leftTurn, rightTurn ) < rot ) - return desiredFacing & 0xFF; - else if( rightTurn < leftTurn ) - return ( facing + rot ) & 0xFF; - else - return ( facing - rot ) & 0xFF; - } - - public static int GetFacing( int2 d, int currentFacing ) - { - if (d == int2.Zero) - return currentFacing; - - int highest = -1; - int highestDot = -1; - - for( int i = 0 ; i < fvecs.Length ; i++ ) - { - int dot = int2.Dot( fvecs[ i ], d ); - if( dot > highestDot ) - { - highestDot = dot; - highest = i; - } - } - - return highest * 8; - } - - public static int GetNearestFacing( int facing, int desiredFacing ) - { - var turn = desiredFacing - facing; - if( turn > 128 ) - turn -= 256; - if( turn < -128 ) - turn += 256; - - return facing + turn; - } - - public static int QuantizeFacing(int facing, int numFrames) - { - var step = 256 / numFrames; - var a = (facing + step / 2) & 0xff; - return a / step; - } - - public static float2 RotateVectorByFacing(float2 v, int facing, float ecc) - { - var angle = (facing / 256f) * (2 * (float)Math.PI); - var sinAngle = (float)Math.Sin(angle); - var cosAngle = (float)Math.Cos(angle); - - return new float2( - (cosAngle * v.X + sinAngle * v.Y), - ecc * (cosAngle * v.Y - sinAngle * v.X)); - } - - public static int2 CenterOfCell(int2 loc) - { - return new int2( Game.CellSize / 2, Game.CellSize / 2 ) + Game.CellSize * loc; - } - - public static int2 BetweenCells(int2 from, int2 to) - { - return int2.Lerp( CenterOfCell( from ), CenterOfCell( to ), 1, 2 ); - } - - public static int2 AsInt2(this int[] xs) { return new int2(xs[0], xs[1]); } - public static float2 RelOffset(this int[] offset) { return new float2(offset[0], offset[1]); } - public static float2 AbsOffset(this int[] offset) { return new float2(offset.ElementAtOrDefault(2), offset.ElementAtOrDefault(3)); } - - public static Renderable Centered(Actor self, Sprite s, float2 location) - { - var pal = self.Owner == null ? "player0" : self.Owner.Palette; - var loc = location - 0.5f * s.size; - - return new Renderable(s, loc.Round(), pal, (int)self.CenterLocation.Y); - } - - public static IActivity SequenceActivities(params IActivity[] acts) - { - return acts.Reverse().Aggregate( - (next, a) => { a.Queue( next ); return a; }); - } - - public static IActivity RunActivity( Actor self, IActivity act ) - { - while( act != null ) - { - var prev = act; - - var sw = new Stopwatch(); - act = act.Tick( self ); - var dt = sw.ElapsedTime(); - if(dt > Game.Settings.Debug.LongTickThreshold) - Log.Write("perf", "[{2}] Activity: {0} ({1:0.000} ms)", prev, dt * 1000, Game.LocalTick); - - if( prev == act ) - break; - } - return act; - } - - public static Color ArrayToColor(int[] x) { return Color.FromArgb(x[0], x[1], x[2]); } - - public static int2 CellContaining(float2 pos) { return (1f / Game.CellSize * pos).ToInt2(); } - - /* pretty crap */ - public static IEnumerable Shuffle(this IEnumerable ts, Thirdparty.Random random) - { - var items = ts.ToList(); - while (items.Count > 0) - { - var t = items.Random(random); - yield return t; - items.Remove(t); - } - } - - static int2[] fvecs = - { - new int2( 0, -1331 ), - new int2( -199, -1305 ), - new int2( -391, -1229 ), - new int2( -568, -1106 ), - new int2( -724, -941 ), - new int2( -851, -739 ), - new int2( -946, -509 ), - new int2( -1004, -259 ), - new int2( -1024, 0 ), - new int2( -1004, 259 ), - new int2( -946, 509 ), - new int2( -851, 739 ), - new int2( -724, 941 ), - new int2( -568, 1106 ), - new int2( -391, 1229 ), - new int2( -199, 1305 ), - new int2( 0, 1331 ), - new int2( 199, 1305 ), - new int2( 391, 1229 ), - new int2( 568, 1106 ), - new int2( 724, 941 ), - new int2( 851, 739 ), - new int2( 946, 509 ), - new int2( 1004, 259 ), - new int2( 1024, 0 ), - new int2( 1004, -259 ), - new int2( 946, -509 ), - new int2( 851, -739 ), - new int2( 724, -941 ), - new int2( 568, -1106 ), - new int2( 391, -1229 ), - new int2( 199, -1305 ) - }; - - - public static readonly int2[] SubPxVector = - { - new int2( 0, 1024 ), - new int2( 25, 1023 ), - new int2( 50, 1022 ), - new int2( 75, 1021 ), - new int2( 100, 1019 ), - new int2( 125, 1016 ), - new int2( 150, 1012 ), - new int2( 175, 1008 ), - new int2( 199, 1004 ), - new int2( 224, 999 ), - new int2( 248, 993 ), - new int2( 273, 986 ), - new int2( 297, 979 ), - new int2( 321, 972 ), - new int2( 344, 964 ), - new int2( 368, 955 ), - new int2( 391, 946 ), - new int2( 414, 936 ), - new int2( 437, 925 ), - new int2( 460, 914 ), - new int2( 482, 903 ), - new int2( 504, 890 ), - new int2( 526, 878 ), - new int2( 547, 865 ), - new int2( 568, 851 ), - new int2( 589, 837 ), - new int2( 609, 822 ), - new int2( 629, 807 ), - new int2( 649, 791 ), - new int2( 668, 775 ), - new int2( 687, 758 ), - new int2( 706, 741 ), - new int2( 724, 724 ), - new int2( 741, 706 ), - new int2( 758, 687 ), - new int2( 775, 668 ), - new int2( 791, 649 ), - new int2( 807, 629 ), - new int2( 822, 609 ), - new int2( 837, 589 ), - new int2( 851, 568 ), - new int2( 865, 547 ), - new int2( 878, 526 ), - new int2( 890, 504 ), - new int2( 903, 482 ), - new int2( 914, 460 ), - new int2( 925, 437 ), - new int2( 936, 414 ), - new int2( 946, 391 ), - new int2( 955, 368 ), - new int2( 964, 344 ), - new int2( 972, 321 ), - new int2( 979, 297 ), - new int2( 986, 273 ), - new int2( 993, 248 ), - new int2( 999, 224 ), - new int2( 1004, 199 ), - new int2( 1008, 175 ), - new int2( 1012, 150 ), - new int2( 1016, 125 ), - new int2( 1019, 100 ), - new int2( 1021, 75 ), - new int2( 1022, 50 ), - new int2( 1023, 25 ), - new int2( 1024, 0 ), - new int2( 1023, -25 ), - new int2( 1022, -50 ), - new int2( 1021, -75 ), - new int2( 1019, -100 ), - new int2( 1016, -125 ), - new int2( 1012, -150 ), - new int2( 1008, -175 ), - new int2( 1004, -199 ), - new int2( 999, -224 ), - new int2( 993, -248 ), - new int2( 986, -273 ), - new int2( 979, -297 ), - new int2( 972, -321 ), - new int2( 964, -344 ), - new int2( 955, -368 ), - new int2( 946, -391 ), - new int2( 936, -414 ), - new int2( 925, -437 ), - new int2( 914, -460 ), - new int2( 903, -482 ), - new int2( 890, -504 ), - new int2( 878, -526 ), - new int2( 865, -547 ), - new int2( 851, -568 ), - new int2( 837, -589 ), - new int2( 822, -609 ), - new int2( 807, -629 ), - new int2( 791, -649 ), - new int2( 775, -668 ), - new int2( 758, -687 ), - new int2( 741, -706 ), - new int2( 724, -724 ), - new int2( 706, -741 ), - new int2( 687, -758 ), - new int2( 668, -775 ), - new int2( 649, -791 ), - new int2( 629, -807 ), - new int2( 609, -822 ), - new int2( 589, -837 ), - new int2( 568, -851 ), - new int2( 547, -865 ), - new int2( 526, -878 ), - new int2( 504, -890 ), - new int2( 482, -903 ), - new int2( 460, -914 ), - new int2( 437, -925 ), - new int2( 414, -936 ), - new int2( 391, -946 ), - new int2( 368, -955 ), - new int2( 344, -964 ), - new int2( 321, -972 ), - new int2( 297, -979 ), - new int2( 273, -986 ), - new int2( 248, -993 ), - new int2( 224, -999 ), - new int2( 199, -1004 ), - new int2( 175, -1008 ), - new int2( 150, -1012 ), - new int2( 125, -1016 ), - new int2( 100, -1019 ), - new int2( 75, -1021 ), - new int2( 50, -1022 ), - new int2( 25, -1023 ), - new int2( 0, -1024 ), - new int2( -25, -1023 ), - new int2( -50, -1022 ), - new int2( -75, -1021 ), - new int2( -100, -1019 ), - new int2( -125, -1016 ), - new int2( -150, -1012 ), - new int2( -175, -1008 ), - new int2( -199, -1004 ), - new int2( -224, -999 ), - new int2( -248, -993 ), - new int2( -273, -986 ), - new int2( -297, -979 ), - new int2( -321, -972 ), - new int2( -344, -964 ), - new int2( -368, -955 ), - new int2( -391, -946 ), - new int2( -414, -936 ), - new int2( -437, -925 ), - new int2( -460, -914 ), - new int2( -482, -903 ), - new int2( -504, -890 ), - new int2( -526, -878 ), - new int2( -547, -865 ), - new int2( -568, -851 ), - new int2( -589, -837 ), - new int2( -609, -822 ), - new int2( -629, -807 ), - new int2( -649, -791 ), - new int2( -668, -775 ), - new int2( -687, -758 ), - new int2( -706, -741 ), - new int2( -724, -724 ), - new int2( -741, -706 ), - new int2( -758, -687 ), - new int2( -775, -668 ), - new int2( -791, -649 ), - new int2( -807, -629 ), - new int2( -822, -609 ), - new int2( -837, -589 ), - new int2( -851, -568 ), - new int2( -865, -547 ), - new int2( -878, -526 ), - new int2( -890, -504 ), - new int2( -903, -482 ), - new int2( -914, -460 ), - new int2( -925, -437 ), - new int2( -936, -414 ), - new int2( -946, -391 ), - new int2( -955, -368 ), - new int2( -964, -344 ), - new int2( -972, -321 ), - new int2( -979, -297 ), - new int2( -986, -273 ), - new int2( -993, -248 ), - new int2( -999, -224 ), - new int2( -1004, -199 ), - new int2( -1008, -175 ), - new int2( -1012, -150 ), - new int2( -1016, -125 ), - new int2( -1019, -100 ), - new int2( -1021, -75 ), - new int2( -1022, -50 ), - new int2( -1023, -25 ), - new int2( -1024, 0 ), - new int2( -1023, 25 ), - new int2( -1022, 50 ), - new int2( -1021, 75 ), - new int2( -1019, 100 ), - new int2( -1016, 125 ), - new int2( -1012, 150 ), - new int2( -1008, 175 ), - new int2( -1004, 199 ), - new int2( -999, 224 ), - new int2( -993, 248 ), - new int2( -986, 273 ), - new int2( -979, 297 ), - new int2( -972, 321 ), - new int2( -964, 344 ), - new int2( -955, 368 ), - new int2( -946, 391 ), - new int2( -936, 414 ), - new int2( -925, 437 ), - new int2( -914, 460 ), - new int2( -903, 482 ), - new int2( -890, 504 ), - new int2( -878, 526 ), - new int2( -865, 547 ), - new int2( -851, 568 ), - new int2( -837, 589 ), - new int2( -822, 609 ), - new int2( -807, 629 ), - new int2( -791, 649 ), - new int2( -775, 668 ), - new int2( -758, 687 ), - new int2( -741, 706 ), - new int2( -724, 724 ), - new int2( -706, 741 ), - new int2( -687, 758 ), - new int2( -668, 775 ), - new int2( -649, 791 ), - new int2( -629, 807 ), - new int2( -609, 822 ), - new int2( -589, 837 ), - new int2( -568, 851 ), - new int2( -547, 865 ), - new int2( -526, 878 ), - new int2( -504, 890 ), - new int2( -482, 903 ), - new int2( -460, 914 ), - new int2( -437, 925 ), - new int2( -414, 936 ), - new int2( -391, 946 ), - new int2( -368, 955 ), - new int2( -344, 964 ), - new int2( -321, 972 ), - new int2( -297, 979 ), - new int2( -273, 986 ), - new int2( -248, 993 ), - new int2( -224, 999 ), - new int2( -199, 1004 ), - new int2( -175, 1008 ), - new int2( -150, 1012 ), - new int2( -125, 1016 ), - new int2( -100, 1019 ), - new int2( -75, 1021 ), - new int2( -50, 1022 ), - new int2( -25, 1023 ) - }; - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Support; +using System.Collections.Generic; + +namespace OpenRA.Traits +{ + public static class Util + { + public static int TickFacing( int facing, int desiredFacing, int rot ) + { + var leftTurn = ( facing - desiredFacing ) & 0xFF; + var rightTurn = ( desiredFacing - facing ) & 0xFF; + if( Math.Min( leftTurn, rightTurn ) < rot ) + return desiredFacing & 0xFF; + else if( rightTurn < leftTurn ) + return ( facing + rot ) & 0xFF; + else + return ( facing - rot ) & 0xFF; + } + + public static int GetFacing( int2 d, int currentFacing ) + { + if (d == int2.Zero) + return currentFacing; + + int highest = -1; + int highestDot = -1; + + for( int i = 0 ; i < fvecs.Length ; i++ ) + { + int dot = int2.Dot( fvecs[ i ], d ); + if( dot > highestDot ) + { + highestDot = dot; + highest = i; + } + } + + return highest * 8; + } + + public static int GetNearestFacing( int facing, int desiredFacing ) + { + var turn = desiredFacing - facing; + if( turn > 128 ) + turn -= 256; + if( turn < -128 ) + turn += 256; + + return facing + turn; + } + + public static int QuantizeFacing(int facing, int numFrames) + { + var step = 256 / numFrames; + var a = (facing + step / 2) & 0xff; + return a / step; + } + + public static float2 RotateVectorByFacing(float2 v, int facing, float ecc) + { + var angle = (facing / 256f) * (2 * (float)Math.PI); + var sinAngle = (float)Math.Sin(angle); + var cosAngle = (float)Math.Cos(angle); + + return new float2( + (cosAngle * v.X + sinAngle * v.Y), + ecc * (cosAngle * v.Y - sinAngle * v.X)); + } + + public static int2 CenterOfCell(int2 loc) + { + return new int2( Game.CellSize / 2, Game.CellSize / 2 ) + Game.CellSize * loc; + } + + public static int2 BetweenCells(int2 from, int2 to) + { + return int2.Lerp( CenterOfCell( from ), CenterOfCell( to ), 1, 2 ); + } + + public static int2 AsInt2(this int[] xs) { return new int2(xs[0], xs[1]); } + public static float2 RelOffset(this int[] offset) { return new float2(offset[0], offset[1]); } + public static float2 AbsOffset(this int[] offset) { return new float2(offset.ElementAtOrDefault(2), offset.ElementAtOrDefault(3)); } + + public static Renderable Centered(Actor self, Sprite s, float2 location) + { + var pal = self.Owner == null ? "player0" : self.Owner.Palette; + var loc = location - 0.5f * s.size; + + return new Renderable(s, loc.Round(), pal, (int)self.CenterLocation.Y); + } + + public static IActivity SequenceActivities(params IActivity[] acts) + { + return acts.Reverse().Aggregate( + (next, a) => { a.Queue( next ); return a; }); + } + + public static IActivity RunActivity( Actor self, IActivity act ) + { + while( act != null ) + { + var prev = act; + + var sw = new Stopwatch(); + act = act.Tick( self ); + var dt = sw.ElapsedTime(); + if(dt > Game.Settings.Debug.LongTickThreshold) + Log.Write("perf", "[{2}] Activity: {0} ({1:0.000} ms)", prev, dt * 1000, Game.LocalTick); + + if( prev == act ) + break; + } + return act; + } + + public static Color ArrayToColor(int[] x) { return Color.FromArgb(x[0], x[1], x[2]); } + + public static int2 CellContaining(float2 pos) { return (1f / Game.CellSize * pos).ToInt2(); } + + /* pretty crap */ + public static IEnumerable Shuffle(this IEnumerable ts, Thirdparty.Random random) + { + var items = ts.ToList(); + while (items.Count > 0) + { + var t = items.Random(random); + yield return t; + items.Remove(t); + } + } + + static int2[] fvecs = + { + new int2( 0, -1331 ), + new int2( -199, -1305 ), + new int2( -391, -1229 ), + new int2( -568, -1106 ), + new int2( -724, -941 ), + new int2( -851, -739 ), + new int2( -946, -509 ), + new int2( -1004, -259 ), + new int2( -1024, 0 ), + new int2( -1004, 259 ), + new int2( -946, 509 ), + new int2( -851, 739 ), + new int2( -724, 941 ), + new int2( -568, 1106 ), + new int2( -391, 1229 ), + new int2( -199, 1305 ), + new int2( 0, 1331 ), + new int2( 199, 1305 ), + new int2( 391, 1229 ), + new int2( 568, 1106 ), + new int2( 724, 941 ), + new int2( 851, 739 ), + new int2( 946, 509 ), + new int2( 1004, 259 ), + new int2( 1024, 0 ), + new int2( 1004, -259 ), + new int2( 946, -509 ), + new int2( 851, -739 ), + new int2( 724, -941 ), + new int2( 568, -1106 ), + new int2( 391, -1229 ), + new int2( 199, -1305 ) + }; + + + public static readonly int2[] SubPxVector = + { + new int2( 0, 1024 ), + new int2( 25, 1023 ), + new int2( 50, 1022 ), + new int2( 75, 1021 ), + new int2( 100, 1019 ), + new int2( 125, 1016 ), + new int2( 150, 1012 ), + new int2( 175, 1008 ), + new int2( 199, 1004 ), + new int2( 224, 999 ), + new int2( 248, 993 ), + new int2( 273, 986 ), + new int2( 297, 979 ), + new int2( 321, 972 ), + new int2( 344, 964 ), + new int2( 368, 955 ), + new int2( 391, 946 ), + new int2( 414, 936 ), + new int2( 437, 925 ), + new int2( 460, 914 ), + new int2( 482, 903 ), + new int2( 504, 890 ), + new int2( 526, 878 ), + new int2( 547, 865 ), + new int2( 568, 851 ), + new int2( 589, 837 ), + new int2( 609, 822 ), + new int2( 629, 807 ), + new int2( 649, 791 ), + new int2( 668, 775 ), + new int2( 687, 758 ), + new int2( 706, 741 ), + new int2( 724, 724 ), + new int2( 741, 706 ), + new int2( 758, 687 ), + new int2( 775, 668 ), + new int2( 791, 649 ), + new int2( 807, 629 ), + new int2( 822, 609 ), + new int2( 837, 589 ), + new int2( 851, 568 ), + new int2( 865, 547 ), + new int2( 878, 526 ), + new int2( 890, 504 ), + new int2( 903, 482 ), + new int2( 914, 460 ), + new int2( 925, 437 ), + new int2( 936, 414 ), + new int2( 946, 391 ), + new int2( 955, 368 ), + new int2( 964, 344 ), + new int2( 972, 321 ), + new int2( 979, 297 ), + new int2( 986, 273 ), + new int2( 993, 248 ), + new int2( 999, 224 ), + new int2( 1004, 199 ), + new int2( 1008, 175 ), + new int2( 1012, 150 ), + new int2( 1016, 125 ), + new int2( 1019, 100 ), + new int2( 1021, 75 ), + new int2( 1022, 50 ), + new int2( 1023, 25 ), + new int2( 1024, 0 ), + new int2( 1023, -25 ), + new int2( 1022, -50 ), + new int2( 1021, -75 ), + new int2( 1019, -100 ), + new int2( 1016, -125 ), + new int2( 1012, -150 ), + new int2( 1008, -175 ), + new int2( 1004, -199 ), + new int2( 999, -224 ), + new int2( 993, -248 ), + new int2( 986, -273 ), + new int2( 979, -297 ), + new int2( 972, -321 ), + new int2( 964, -344 ), + new int2( 955, -368 ), + new int2( 946, -391 ), + new int2( 936, -414 ), + new int2( 925, -437 ), + new int2( 914, -460 ), + new int2( 903, -482 ), + new int2( 890, -504 ), + new int2( 878, -526 ), + new int2( 865, -547 ), + new int2( 851, -568 ), + new int2( 837, -589 ), + new int2( 822, -609 ), + new int2( 807, -629 ), + new int2( 791, -649 ), + new int2( 775, -668 ), + new int2( 758, -687 ), + new int2( 741, -706 ), + new int2( 724, -724 ), + new int2( 706, -741 ), + new int2( 687, -758 ), + new int2( 668, -775 ), + new int2( 649, -791 ), + new int2( 629, -807 ), + new int2( 609, -822 ), + new int2( 589, -837 ), + new int2( 568, -851 ), + new int2( 547, -865 ), + new int2( 526, -878 ), + new int2( 504, -890 ), + new int2( 482, -903 ), + new int2( 460, -914 ), + new int2( 437, -925 ), + new int2( 414, -936 ), + new int2( 391, -946 ), + new int2( 368, -955 ), + new int2( 344, -964 ), + new int2( 321, -972 ), + new int2( 297, -979 ), + new int2( 273, -986 ), + new int2( 248, -993 ), + new int2( 224, -999 ), + new int2( 199, -1004 ), + new int2( 175, -1008 ), + new int2( 150, -1012 ), + new int2( 125, -1016 ), + new int2( 100, -1019 ), + new int2( 75, -1021 ), + new int2( 50, -1022 ), + new int2( 25, -1023 ), + new int2( 0, -1024 ), + new int2( -25, -1023 ), + new int2( -50, -1022 ), + new int2( -75, -1021 ), + new int2( -100, -1019 ), + new int2( -125, -1016 ), + new int2( -150, -1012 ), + new int2( -175, -1008 ), + new int2( -199, -1004 ), + new int2( -224, -999 ), + new int2( -248, -993 ), + new int2( -273, -986 ), + new int2( -297, -979 ), + new int2( -321, -972 ), + new int2( -344, -964 ), + new int2( -368, -955 ), + new int2( -391, -946 ), + new int2( -414, -936 ), + new int2( -437, -925 ), + new int2( -460, -914 ), + new int2( -482, -903 ), + new int2( -504, -890 ), + new int2( -526, -878 ), + new int2( -547, -865 ), + new int2( -568, -851 ), + new int2( -589, -837 ), + new int2( -609, -822 ), + new int2( -629, -807 ), + new int2( -649, -791 ), + new int2( -668, -775 ), + new int2( -687, -758 ), + new int2( -706, -741 ), + new int2( -724, -724 ), + new int2( -741, -706 ), + new int2( -758, -687 ), + new int2( -775, -668 ), + new int2( -791, -649 ), + new int2( -807, -629 ), + new int2( -822, -609 ), + new int2( -837, -589 ), + new int2( -851, -568 ), + new int2( -865, -547 ), + new int2( -878, -526 ), + new int2( -890, -504 ), + new int2( -903, -482 ), + new int2( -914, -460 ), + new int2( -925, -437 ), + new int2( -936, -414 ), + new int2( -946, -391 ), + new int2( -955, -368 ), + new int2( -964, -344 ), + new int2( -972, -321 ), + new int2( -979, -297 ), + new int2( -986, -273 ), + new int2( -993, -248 ), + new int2( -999, -224 ), + new int2( -1004, -199 ), + new int2( -1008, -175 ), + new int2( -1012, -150 ), + new int2( -1016, -125 ), + new int2( -1019, -100 ), + new int2( -1021, -75 ), + new int2( -1022, -50 ), + new int2( -1023, -25 ), + new int2( -1024, 0 ), + new int2( -1023, 25 ), + new int2( -1022, 50 ), + new int2( -1021, 75 ), + new int2( -1019, 100 ), + new int2( -1016, 125 ), + new int2( -1012, 150 ), + new int2( -1008, 175 ), + new int2( -1004, 199 ), + new int2( -999, 224 ), + new int2( -993, 248 ), + new int2( -986, 273 ), + new int2( -979, 297 ), + new int2( -972, 321 ), + new int2( -964, 344 ), + new int2( -955, 368 ), + new int2( -946, 391 ), + new int2( -936, 414 ), + new int2( -925, 437 ), + new int2( -914, 460 ), + new int2( -903, 482 ), + new int2( -890, 504 ), + new int2( -878, 526 ), + new int2( -865, 547 ), + new int2( -851, 568 ), + new int2( -837, 589 ), + new int2( -822, 609 ), + new int2( -807, 629 ), + new int2( -791, 649 ), + new int2( -775, 668 ), + new int2( -758, 687 ), + new int2( -741, 706 ), + new int2( -724, 724 ), + new int2( -706, 741 ), + new int2( -687, 758 ), + new int2( -668, 775 ), + new int2( -649, 791 ), + new int2( -629, 807 ), + new int2( -609, 822 ), + new int2( -589, 837 ), + new int2( -568, 851 ), + new int2( -547, 865 ), + new int2( -526, 878 ), + new int2( -504, 890 ), + new int2( -482, 903 ), + new int2( -460, 914 ), + new int2( -437, 925 ), + new int2( -414, 936 ), + new int2( -391, 946 ), + new int2( -368, 955 ), + new int2( -344, 964 ), + new int2( -321, 972 ), + new int2( -297, 979 ), + new int2( -273, 986 ), + new int2( -248, 993 ), + new int2( -224, 999 ), + new int2( -199, 1004 ), + new int2( -175, 1008 ), + new int2( -150, 1012 ), + new int2( -125, 1016 ), + new int2( -100, 1019 ), + new int2( -75, 1021 ), + new int2( -50, 1022 ), + new int2( -25, 1023 ) + }; + } +} diff --git a/OpenRA.Game/Traits/ValidateOrder.cs b/OpenRA.Game/Traits/ValidateOrder.cs index f2af3c179f..02c3297b33 100644 --- a/OpenRA.Game/Traits/ValidateOrder.cs +++ b/OpenRA.Game/Traits/ValidateOrder.cs @@ -1,31 +1,31 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Network; - -namespace OpenRA.Traits -{ - public class ValidateOrderInfo : TraitInfo { } - - public class ValidateOrder : IValidateOrder - { - public bool OrderValidation(OrderManager orderManager, World world, int clientId, Order order) - { - // Drop exploiting orders - if (order.Subject != null && order.Subject.Owner.ClientIndex != clientId) - { - Game.Debug("Detected exploit order from {0}: {1}".F(clientId, order.OrderString)); - return false; - } - - return true; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Network; + +namespace OpenRA.Traits +{ + public class ValidateOrderInfo : TraitInfo { } + + public class ValidateOrder : IValidateOrder + { + public bool OrderValidation(OrderManager orderManager, World world, int clientId, Order order) + { + // Drop exploiting orders + if (order.Subject != null && order.Subject.Owner.ClientIndex != clientId) + { + Game.Debug("Detected exploit order from {0}: {1}".F(clientId, order.OrderString)); + return false; + } + + return true; + } + } +} diff --git a/OpenRA.Game/Traits/Waypoint.cs b/OpenRA.Game/Traits/Waypoint.cs index 0c80f0d8e7..7d49461ca8 100644 --- a/OpenRA.Game/Traits/Waypoint.cs +++ b/OpenRA.Game/Traits/Waypoint.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Game/Traits/World/Country.cs b/OpenRA.Game/Traits/World/Country.cs index bf31a86acc..5f4777d167 100644 --- a/OpenRA.Game/Traits/World/Country.cs +++ b/OpenRA.Game/Traits/World/Country.cs @@ -1,22 +1,22 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.Traits -{ - public class CountryInfo : TraitInfo - { - public readonly string Name = null; - public readonly string Race = null; - - /* todo: icon,... */ - } - - public class Country { /* we're only interested in the Info */ } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.Traits +{ + public class CountryInfo : TraitInfo + { + public readonly string Name = null; + public readonly string Race = null; + + /* todo: icon,... */ + } + + public class Country { /* we're only interested in the Info */ } +} diff --git a/OpenRA.Game/Traits/World/PlayerColorPalette.cs b/OpenRA.Game/Traits/World/PlayerColorPalette.cs index 1e48723746..6266c42d00 100644 --- a/OpenRA.Game/Traits/World/PlayerColorPalette.cs +++ b/OpenRA.Game/Traits/World/PlayerColorPalette.cs @@ -1,42 +1,42 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.FileFormats; -using OpenRA.Graphics; -namespace OpenRA.Traits -{ - public class PlayerColorPaletteInfo : ITraitInfo - { - public readonly string BasePalette = null; - public readonly string BaseName = "player"; - public readonly PaletteFormat PaletteFormat = PaletteFormat.ra; - - public object Create( ActorInitializer init ) { return new PlayerColorPalette( init.self.Owner, this ); } - } - - public class PlayerColorPalette : IPalette - { - readonly Player owner; - readonly PlayerColorPaletteInfo info; - public PlayerColorPalette( Player owner, PlayerColorPaletteInfo info ) - { - this.owner = owner; - this.info = info; - } - - public void InitPalette( WorldRenderer wr ) - { - var paletteName = "{0}{1}".F( info.BaseName, owner.Index ); +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.FileFormats; +using OpenRA.Graphics; +namespace OpenRA.Traits +{ + public class PlayerColorPaletteInfo : ITraitInfo + { + public readonly string BasePalette = null; + public readonly string BaseName = "player"; + public readonly PaletteFormat PaletteFormat = PaletteFormat.ra; + + public object Create( ActorInitializer init ) { return new PlayerColorPalette( init.self.Owner, this ); } + } + + public class PlayerColorPalette : IPalette + { + readonly Player owner; + readonly PlayerColorPaletteInfo info; + public PlayerColorPalette( Player owner, PlayerColorPaletteInfo info ) + { + this.owner = owner; + this.info = info; + } + + public void InitPalette( WorldRenderer wr ) + { + var paletteName = "{0}{1}".F( info.BaseName, owner.Index ); var newpal = new Palette(wr.GetPalette(info.BasePalette), new PlayerColorRemap(owner.ColorRamp, info.PaletteFormat)); wr.AddPalette(paletteName, newpal); - } - } -} + } + } +} diff --git a/OpenRA.Game/Traits/World/ResourceLayer.cs b/OpenRA.Game/Traits/World/ResourceLayer.cs index 8686bfb559..e910a76323 100644 --- a/OpenRA.Game/Traits/World/ResourceLayer.cs +++ b/OpenRA.Game/Traits/World/ResourceLayer.cs @@ -1,164 +1,164 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; - -namespace OpenRA.Traits -{ - public class ResourceLayerInfo : TraitInfo { } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion - public class ResourceLayer: IRenderOverlay, IWorldLoaded - { - World world; - - public ResourceType[] resourceTypes; - CellContents[,] content; - - public void Render( WorldRenderer wr ) - { - foreach( var rt in world.WorldActor.TraitsImplementing() ) - rt.info.PaletteIndex = wr.GetPaletteIndex(rt.info.Palette); - - var clip = Game.viewport.WorldBounds(world); - for (int x = clip.Left; x < clip.Right; x++) - for (int y = clip.Top; y < clip.Bottom; y++) - { - if (!world.LocalShroud.IsExplored(new int2(x, y))) - continue; - - var c = content[x, y]; - if (c.image != null) - c.image[c.density].DrawAt( - Game.CellSize * new int2(x, y), - c.type.info.PaletteIndex); - } - } - - public void WorldLoaded(World w) - { - this.world = w; - content = new CellContents[w.Map.MapSize.X, w.Map.MapSize.Y]; - - resourceTypes = w.WorldActor.TraitsImplementing().ToArray(); - foreach (var rt in resourceTypes) - rt.info.Sprites = rt.info.SpriteNames.Select(a => Game.modData.SpriteLoader.LoadAllSprites(a)).ToArray(); - - var map = w.Map; - - for (int x = map.Bounds.Left; x < map.Bounds.Right; x++) - for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++) - { - var type = resourceTypes.FirstOrDefault( - r => r.info.ResourceType == w.Map.MapResources.Value[x, y].type); - - if (type == null) - continue; - - if (!AllowResourceAt(type, new int2(x,y))) - continue; - - content[x, y].type = type; - content[x, y].image = ChooseContent(type); - } - - for (int x = map.Bounds.Left; x < map.Bounds.Right; x++) - for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++) - if (content[x, y].type != null) - { - content[x, y].density = GetIdealDensity(x, y); - w.Map.CustomTerrain[x, y] = content[x, y].type.info.TerrainType; - } - } - - public bool AllowResourceAt(ResourceType rt, int2 a) - { - if (!world.Map.IsInMap(a.X, a.Y)) return false; - if (!rt.info.AllowedTerrainTypes.Contains(world.GetTerrainInfo(a).Type)) return false; - if (!rt.info.AllowUnderActors && world.WorldActor.Trait().AnyUnitsAt(a)) return false; - return true; - } - - Sprite[] ChooseContent(ResourceType t) - { - return t.info.Sprites[world.SharedRandom.Next(t.info.Sprites.Length)]; - } - - int GetAdjacentCellsWith(ResourceType t, int i, int j) - { - int sum = 0; - for (var u = -1; u < 2; u++) - for (var v = -1; v < 2; v++) - if (content[i+u, j+v].type == t) - ++sum; - return sum; - } - - int GetIdealDensity(int x, int y) - { - return (GetAdjacentCellsWith(content[x, y].type, x, y) * - (content[x, y].image.Length - 1)) / 9; - } - - public void AddResource(ResourceType t, int i, int j, int n) - { - if (content[i, j].type == null) - { - content[i, j].type = t; - content[i, j].image = ChooseContent(t); - content[i, j].density = -1; - } - - if (content[i, j].type != t) - return; - - content[i, j].density = Math.Min( - content[i, j].image.Length - 1, - content[i, j].density + n); - - world.Map.CustomTerrain[i,j] = t.info.TerrainType; - } - - public bool IsFull(int i, int j) { return content[i, j].density == content[i, j].image.Length - 1; } - - public ResourceType Harvest(int2 p) - { - var type = content[p.X,p.Y].type; - if (type == null) return null; - - if (--content[p.X, p.Y].density < 0) - { - content[p.X, p.Y].type = null; - content[p.X, p.Y].image = null; - world.Map.CustomTerrain[p.X, p.Y] = null; - } - return type; - } - - public void Destroy(int2 p) - { - content[p.X, p.Y].type = null; - content[p.X, p.Y].image = null; - content[p.X, p.Y].density = 0; - world.Map.CustomTerrain[p.X, p.Y] = null; - } - - public ResourceType GetResource(int2 p) { return content[p.X, p.Y].type; } - - public struct CellContents - { - public ResourceType type; - public Sprite[] image; - public int density; - } - } -} +using System; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; + +namespace OpenRA.Traits +{ + public class ResourceLayerInfo : TraitInfo { } + + public class ResourceLayer: IRenderOverlay, IWorldLoaded + { + World world; + + public ResourceType[] resourceTypes; + CellContents[,] content; + + public void Render( WorldRenderer wr ) + { + foreach( var rt in world.WorldActor.TraitsImplementing() ) + rt.info.PaletteIndex = wr.GetPaletteIndex(rt.info.Palette); + + var clip = Game.viewport.WorldBounds(world); + for (int x = clip.Left; x < clip.Right; x++) + for (int y = clip.Top; y < clip.Bottom; y++) + { + if (!world.LocalShroud.IsExplored(new int2(x, y))) + continue; + + var c = content[x, y]; + if (c.image != null) + c.image[c.density].DrawAt( + Game.CellSize * new int2(x, y), + c.type.info.PaletteIndex); + } + } + + public void WorldLoaded(World w) + { + this.world = w; + content = new CellContents[w.Map.MapSize.X, w.Map.MapSize.Y]; + + resourceTypes = w.WorldActor.TraitsImplementing().ToArray(); + foreach (var rt in resourceTypes) + rt.info.Sprites = rt.info.SpriteNames.Select(a => Game.modData.SpriteLoader.LoadAllSprites(a)).ToArray(); + + var map = w.Map; + + for (int x = map.Bounds.Left; x < map.Bounds.Right; x++) + for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++) + { + var type = resourceTypes.FirstOrDefault( + r => r.info.ResourceType == w.Map.MapResources.Value[x, y].type); + + if (type == null) + continue; + + if (!AllowResourceAt(type, new int2(x,y))) + continue; + + content[x, y].type = type; + content[x, y].image = ChooseContent(type); + } + + for (int x = map.Bounds.Left; x < map.Bounds.Right; x++) + for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++) + if (content[x, y].type != null) + { + content[x, y].density = GetIdealDensity(x, y); + w.Map.CustomTerrain[x, y] = content[x, y].type.info.TerrainType; + } + } + + public bool AllowResourceAt(ResourceType rt, int2 a) + { + if (!world.Map.IsInMap(a.X, a.Y)) return false; + if (!rt.info.AllowedTerrainTypes.Contains(world.GetTerrainInfo(a).Type)) return false; + if (!rt.info.AllowUnderActors && world.WorldActor.Trait().AnyUnitsAt(a)) return false; + return true; + } + + Sprite[] ChooseContent(ResourceType t) + { + return t.info.Sprites[world.SharedRandom.Next(t.info.Sprites.Length)]; + } + + int GetAdjacentCellsWith(ResourceType t, int i, int j) + { + int sum = 0; + for (var u = -1; u < 2; u++) + for (var v = -1; v < 2; v++) + if (content[i+u, j+v].type == t) + ++sum; + return sum; + } + + int GetIdealDensity(int x, int y) + { + return (GetAdjacentCellsWith(content[x, y].type, x, y) * + (content[x, y].image.Length - 1)) / 9; + } + + public void AddResource(ResourceType t, int i, int j, int n) + { + if (content[i, j].type == null) + { + content[i, j].type = t; + content[i, j].image = ChooseContent(t); + content[i, j].density = -1; + } + + if (content[i, j].type != t) + return; + + content[i, j].density = Math.Min( + content[i, j].image.Length - 1, + content[i, j].density + n); + + world.Map.CustomTerrain[i,j] = t.info.TerrainType; + } + + public bool IsFull(int i, int j) { return content[i, j].density == content[i, j].image.Length - 1; } + + public ResourceType Harvest(int2 p) + { + var type = content[p.X,p.Y].type; + if (type == null) return null; + + if (--content[p.X, p.Y].density < 0) + { + content[p.X, p.Y].type = null; + content[p.X, p.Y].image = null; + world.Map.CustomTerrain[p.X, p.Y] = null; + } + return type; + } + + public void Destroy(int2 p) + { + content[p.X, p.Y].type = null; + content[p.X, p.Y].image = null; + content[p.X, p.Y].density = 0; + world.Map.CustomTerrain[p.X, p.Y] = null; + } + + public ResourceType GetResource(int2 p) { return content[p.X, p.Y].type; } + + public struct CellContents + { + public ResourceType type; + public Sprite[] image; + public int density; + } + } +} diff --git a/OpenRA.Game/Traits/World/ResourceType.cs b/OpenRA.Game/Traits/World/ResourceType.cs index a1bd2b0a23..008cf1db19 100644 --- a/OpenRA.Game/Traits/World/ResourceType.cs +++ b/OpenRA.Game/Traits/World/ResourceType.cs @@ -1,44 +1,44 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Graphics; - -namespace OpenRA.Traits -{ - public class ResourceTypeInfo : ITraitInfo - { - public readonly string[] SpriteNames = { }; - public readonly string Palette = "terrain"; - public readonly int ResourceType = 1; - - public readonly int ValuePerUnit = 0; - public readonly string Name = null; - public readonly string TerrainType = "Ore"; - - public readonly string[] AllowedTerrainTypes = { }; - public readonly bool AllowUnderActors = false; - - public Sprite[][] Sprites; - public int PaletteIndex; - - public PipType PipColor = PipType.Yellow; - - public object Create(ActorInitializer init) { return new ResourceType(this); } - } - - public class ResourceType - { - public ResourceTypeInfo info; - public ResourceType(ResourceTypeInfo info) - { - this.info = info; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Graphics; + +namespace OpenRA.Traits +{ + public class ResourceTypeInfo : ITraitInfo + { + public readonly string[] SpriteNames = { }; + public readonly string Palette = "terrain"; + public readonly int ResourceType = 1; + + public readonly int ValuePerUnit = 0; + public readonly string Name = null; + public readonly string TerrainType = "Ore"; + + public readonly string[] AllowedTerrainTypes = { }; + public readonly bool AllowUnderActors = false; + + public Sprite[][] Sprites; + public int PaletteIndex; + + public PipType PipColor = PipType.Yellow; + + public object Create(ActorInitializer init) { return new ResourceType(this); } + } + + public class ResourceType + { + public ResourceTypeInfo info; + public ResourceType(ResourceTypeInfo info) + { + this.info = info; + } + } +} diff --git a/OpenRA.Game/Traits/World/ScreenShaker.cs b/OpenRA.Game/Traits/World/ScreenShaker.cs index e1f7a15323..c6b9d0ddfa 100644 --- a/OpenRA.Game/Traits/World/ScreenShaker.cs +++ b/OpenRA.Game/Traits/World/ScreenShaker.cs @@ -1,17 +1,17 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ #endregion using System; using System.Collections.Generic; -using System.Linq; - +using System.Linq; + namespace OpenRA.Traits { class ScreenShakerInfo : TraitInfo {} @@ -22,17 +22,17 @@ namespace OpenRA.Traits List shakeEffects = new List(); public void Tick (Actor self) - { - if(shakeEffects.Any()) + { + if(shakeEffects.Any()) { Game.viewport.Scroll(GetScrollOffset(), true); - shakeEffects.RemoveAll(t => t.ExpiryTime == ticks); + shakeEffects.RemoveAll(t => t.ExpiryTime == ticks); } ticks++; } public void AddEffect(int time, float2 position, int intensity) - { + { shakeEffects.Add(new ShakeEffect { ExpiryTime = ticks + time, Position = position, Intensity = intensity }); } @@ -56,7 +56,7 @@ namespace OpenRA.Traits return Math.Min(intensity, 10); } - } - + } + class ShakeEffect { public int ExpiryTime; public float2 Position; public int Intensity; } } diff --git a/OpenRA.Game/Traits/World/Shroud.cs b/OpenRA.Game/Traits/World/Shroud.cs index 8ef65361e5..23bfdf091c 100644 --- a/OpenRA.Game/Traits/World/Shroud.cs +++ b/OpenRA.Game/Traits/World/Shroud.cs @@ -1,236 +1,236 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; - -namespace OpenRA.Traits -{ - public class ShroudInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new Shroud(init.world); } - } - - public class Shroud - { - Map map; - World world; - - public int[,] visibleCells; - public bool[,] exploredCells; - Rectangle? exploredBounds; - bool disabled = false; - public bool Disabled - { - get { return disabled || world.LocalPlayer == null; } - set { disabled = value; Dirty(); } - } - - public Rectangle? Bounds - { - get { return Disabled ? null : exploredBounds; } - } - - public event Action Dirty = () => { }; - - public Shroud(World world) - { - this.world = world; - map = world.Map; - visibleCells = new int[map.MapSize.X, map.MapSize.Y]; - exploredCells = new bool[map.MapSize.X, map.MapSize.Y]; - world.ActorAdded += AddActor; - world.ActorRemoved += RemoveActor; - } - - // cache of positions that were added, so no matter what crazy trait code does, it - // can't make us invalid. - class ActorVisibility { public int range; public int2[] vis; } - Dictionary vis = new Dictionary(); - - static IEnumerable FindVisibleTiles(World world, int2 a, int r) - { - var min = a - new int2(r, r); - var max = a + new int2(r, r); - if (min.X < world.Map.Bounds.Left - 1) min.X = world.Map.Bounds.Left - 1; - if (min.Y < world.Map.Bounds.Top - 1) min.Y = world.Map.Bounds.Top - 1; - if (max.X > world.Map.Bounds.Right) max.X = world.Map.Bounds.Right; - if (max.Y > world.Map.Bounds.Bottom) max.Y = world.Map.Bounds.Bottom; - - for (var j = min.Y; j <= max.Y; j++) - for (var i = min.X; i <= max.X; i++) - if (r * r >= (new int2(i, j) - a).LengthSquared) - yield return new int2(i, j); - } - - void AddActor(Actor a) - { - if (!a.HasTrait()) - return; - - if (a.Owner == null || a.Owner.World.LocalPlayer == null - || a.Owner.Stances[a.Owner.World.LocalPlayer] != Stance.Ally) return; - - if (vis.ContainsKey(a)) - { - Game.Debug("Warning: Actor {0}:{1} at {2} bad vis".F(a.Info.Name, a.ActorID, a.Location)); - RemoveActor(a); - } - - var v = new ActorVisibility - { - range = a.Trait().RevealRange, - vis = GetVisOrigins(a).ToArray() - }; - - if (v.range == 0) return; // don't bother for things that can't see - - foreach (var p in v.vis) - { - foreach (var q in FindVisibleTiles(a.World, p, v.range)) - { - ++visibleCells[q.X, q.Y]; - exploredCells[q.X, q.Y] = true; - } - - var box = new Rectangle(p.X - v.range, p.Y - v.range, 2 * v.range + 1, 2 * v.range + 1); - exploredBounds = (exploredBounds.HasValue) ? Rectangle.Union(exploredBounds.Value, box) : box; - } - - vis[a] = v; - - if (!Disabled) - Dirty(); - } - - public void UpdatePlayerStance(World w, Player player, Stance oldStance, Stance newStance) - { - if (oldStance == newStance) - return; - - // No longer our ally; remove unit vis - if (oldStance == Stance.Ally) - { - var toRemove = new List(vis.Select(a => a.Key).Where(a => a.Owner == player)); - foreach (var a in toRemove) - RemoveActor(a); - } - // Is now our ally; add unit vis - if (newStance == Stance.Ally) - foreach (var a in w.Queries.OwnedBy[player]) - AddActor(a); - } - - public static IEnumerable GetVisOrigins(Actor a) - { - var ios = a.TraitOrDefault(); - if (ios != null) - { - var cells = ios.OccupiedCells(); - if (cells.Any()) return cells.Select(c => c.First); - } - - return new[] { a.CenterLocation / Game.CellSize }; - } - - void RemoveActor(Actor a) - { - ActorVisibility v; - if (!vis.TryGetValue(a, out v)) return; - - foreach (var p in v.vis) - foreach (var q in FindVisibleTiles(a.World, p, v.range)) - --visibleCells[q.X, q.Y]; - - vis.Remove(a); - - if (!Disabled) - Dirty(); - } - - public void UpdateActor(Actor a) - { - if (a.Owner == null || a.Owner.World.LocalPlayer == null - || a.Owner.Stances[a.Owner.World.LocalPlayer] != Stance.Ally) return; - - RemoveActor(a); AddActor(a); - } - - public void Explore(World world, int2 center, int range) - { - foreach (var q in FindVisibleTiles(world, center, range)) - exploredCells[q.X, q.Y] = true; - - var box = new Rectangle(center.X - range, center.Y - range, 2 * range + 1, 2 * range + 1); - exploredBounds = (exploredBounds.HasValue) ? Rectangle.Union(exploredBounds.Value, box) : box; - - if (!Disabled) - Dirty(); - } - - public void ExploreAll(World world) - { - for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) - for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - exploredCells[i, j] = true; - exploredBounds = world.Map.Bounds; - - if (!Disabled) - Dirty(); - } - - public void ResetExploration() // for `hide map` crate - { - for (var j = 0; j <= exploredCells.GetUpperBound(1); j++) - for (var i = 0; i <= exploredCells.GetUpperBound(0); i++) - exploredCells[i, j] = visibleCells[i, j] > 0; - - if (!Disabled) - Dirty(); - } - - public bool IsExplored(int2 xy) { return IsExplored(xy.X, xy.Y); } - public bool IsExplored(int x, int y) - { - if (!map.IsInMap(x, y)) - return false; - - if (Disabled) - return true; - - return exploredCells[x,y]; - } - - public bool IsVisible(int2 xy) { return IsVisible(xy.X, xy.Y); } - public bool IsVisible(int x, int y) - { - if (Disabled) - return true; - - // Visibility is allowed to extend beyond the map cordon so that - // the fog tiles are not visible at the edge of the world - if (x < 0 || x >= map.MapSize.X || y < 0 || y >= map.MapSize.Y) - return false; - - return visibleCells[x,y] != 0; - } - - // Actors are hidden under shroud, but not under fog by default - public bool IsVisible(Actor a) - { - if (a.TraitsImplementing().Any(t => !t.IsVisible(a))) - return false; - - return Disabled || a.Owner == a.World.LocalPlayer || GetVisOrigins(a).Any(o => IsExplored(o)); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace OpenRA.Traits +{ + public class ShroudInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new Shroud(init.world); } + } + + public class Shroud + { + Map map; + World world; + + public int[,] visibleCells; + public bool[,] exploredCells; + Rectangle? exploredBounds; + bool disabled = false; + public bool Disabled + { + get { return disabled || world.LocalPlayer == null; } + set { disabled = value; Dirty(); } + } + + public Rectangle? Bounds + { + get { return Disabled ? null : exploredBounds; } + } + + public event Action Dirty = () => { }; + + public Shroud(World world) + { + this.world = world; + map = world.Map; + visibleCells = new int[map.MapSize.X, map.MapSize.Y]; + exploredCells = new bool[map.MapSize.X, map.MapSize.Y]; + world.ActorAdded += AddActor; + world.ActorRemoved += RemoveActor; + } + + // cache of positions that were added, so no matter what crazy trait code does, it + // can't make us invalid. + class ActorVisibility { public int range; public int2[] vis; } + Dictionary vis = new Dictionary(); + + static IEnumerable FindVisibleTiles(World world, int2 a, int r) + { + var min = a - new int2(r, r); + var max = a + new int2(r, r); + if (min.X < world.Map.Bounds.Left - 1) min.X = world.Map.Bounds.Left - 1; + if (min.Y < world.Map.Bounds.Top - 1) min.Y = world.Map.Bounds.Top - 1; + if (max.X > world.Map.Bounds.Right) max.X = world.Map.Bounds.Right; + if (max.Y > world.Map.Bounds.Bottom) max.Y = world.Map.Bounds.Bottom; + + for (var j = min.Y; j <= max.Y; j++) + for (var i = min.X; i <= max.X; i++) + if (r * r >= (new int2(i, j) - a).LengthSquared) + yield return new int2(i, j); + } + + void AddActor(Actor a) + { + if (!a.HasTrait()) + return; + + if (a.Owner == null || a.Owner.World.LocalPlayer == null + || a.Owner.Stances[a.Owner.World.LocalPlayer] != Stance.Ally) return; + + if (vis.ContainsKey(a)) + { + Game.Debug("Warning: Actor {0}:{1} at {2} bad vis".F(a.Info.Name, a.ActorID, a.Location)); + RemoveActor(a); + } + + var v = new ActorVisibility + { + range = a.Trait().RevealRange, + vis = GetVisOrigins(a).ToArray() + }; + + if (v.range == 0) return; // don't bother for things that can't see + + foreach (var p in v.vis) + { + foreach (var q in FindVisibleTiles(a.World, p, v.range)) + { + ++visibleCells[q.X, q.Y]; + exploredCells[q.X, q.Y] = true; + } + + var box = new Rectangle(p.X - v.range, p.Y - v.range, 2 * v.range + 1, 2 * v.range + 1); + exploredBounds = (exploredBounds.HasValue) ? Rectangle.Union(exploredBounds.Value, box) : box; + } + + vis[a] = v; + + if (!Disabled) + Dirty(); + } + + public void UpdatePlayerStance(World w, Player player, Stance oldStance, Stance newStance) + { + if (oldStance == newStance) + return; + + // No longer our ally; remove unit vis + if (oldStance == Stance.Ally) + { + var toRemove = new List(vis.Select(a => a.Key).Where(a => a.Owner == player)); + foreach (var a in toRemove) + RemoveActor(a); + } + // Is now our ally; add unit vis + if (newStance == Stance.Ally) + foreach (var a in w.Queries.OwnedBy[player]) + AddActor(a); + } + + public static IEnumerable GetVisOrigins(Actor a) + { + var ios = a.TraitOrDefault(); + if (ios != null) + { + var cells = ios.OccupiedCells(); + if (cells.Any()) return cells.Select(c => c.First); + } + + return new[] { a.CenterLocation / Game.CellSize }; + } + + void RemoveActor(Actor a) + { + ActorVisibility v; + if (!vis.TryGetValue(a, out v)) return; + + foreach (var p in v.vis) + foreach (var q in FindVisibleTiles(a.World, p, v.range)) + --visibleCells[q.X, q.Y]; + + vis.Remove(a); + + if (!Disabled) + Dirty(); + } + + public void UpdateActor(Actor a) + { + if (a.Owner == null || a.Owner.World.LocalPlayer == null + || a.Owner.Stances[a.Owner.World.LocalPlayer] != Stance.Ally) return; + + RemoveActor(a); AddActor(a); + } + + public void Explore(World world, int2 center, int range) + { + foreach (var q in FindVisibleTiles(world, center, range)) + exploredCells[q.X, q.Y] = true; + + var box = new Rectangle(center.X - range, center.Y - range, 2 * range + 1, 2 * range + 1); + exploredBounds = (exploredBounds.HasValue) ? Rectangle.Union(exploredBounds.Value, box) : box; + + if (!Disabled) + Dirty(); + } + + public void ExploreAll(World world) + { + for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) + for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) + exploredCells[i, j] = true; + exploredBounds = world.Map.Bounds; + + if (!Disabled) + Dirty(); + } + + public void ResetExploration() // for `hide map` crate + { + for (var j = 0; j <= exploredCells.GetUpperBound(1); j++) + for (var i = 0; i <= exploredCells.GetUpperBound(0); i++) + exploredCells[i, j] = visibleCells[i, j] > 0; + + if (!Disabled) + Dirty(); + } + + public bool IsExplored(int2 xy) { return IsExplored(xy.X, xy.Y); } + public bool IsExplored(int x, int y) + { + if (!map.IsInMap(x, y)) + return false; + + if (Disabled) + return true; + + return exploredCells[x,y]; + } + + public bool IsVisible(int2 xy) { return IsVisible(xy.X, xy.Y); } + public bool IsVisible(int x, int y) + { + if (Disabled) + return true; + + // Visibility is allowed to extend beyond the map cordon so that + // the fog tiles are not visible at the edge of the world + if (x < 0 || x >= map.MapSize.X || y < 0 || y >= map.MapSize.Y) + return false; + + return visibleCells[x,y] != 0; + } + + // Actors are hidden under shroud, but not under fog by default + public bool IsVisible(Actor a) + { + if (a.TraitsImplementing().Any(t => !t.IsVisible(a))) + return false; + + return Disabled || a.Owner == a.World.LocalPlayer || GetVisOrigins(a).Any(o => IsExplored(o)); + } + } +} diff --git a/OpenRA.Game/Traits/World/SpatialBins.cs b/OpenRA.Game/Traits/World/SpatialBins.cs index e8061f2181..54d3ccffb8 100644 --- a/OpenRA.Game/Traits/World/SpatialBins.cs +++ b/OpenRA.Game/Traits/World/SpatialBins.cs @@ -1,87 +1,87 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; - -namespace OpenRA.Traits -{ - class SpatialBinsInfo : ITraitInfo - { - public readonly int BinSize = 8; - public object Create(ActorInitializer init) { return new SpatialBins( init.self, this ); } - } - - class SpatialBins : ITick - { - List[,] bins; - int scale; - - public SpatialBins(Actor self, SpatialBinsInfo info) - { - bins = new List[ - self.World.Map.MapSize.X / info.BinSize, - self.World.Map.MapSize.Y / info.BinSize]; - - scale = Game.CellSize * info.BinSize; - - for (var j = 0; j <= bins.GetUpperBound(1); j++) - for (var i = 0; i <= bins.GetUpperBound(0); i++) - bins[i, j] = new List(); - } - - public void Tick(Actor self) - { - for (var j = 0; j <= bins.GetUpperBound(1); j++) - for (var i = 0; i <= bins.GetUpperBound(0); i++) - bins[i, j].Clear(); - - foreach (var a in self.World.Queries.WithTrait()) - { - var bounds = a.Actor.GetBounds(true); - - if (bounds.Right <= Game.CellSize * self.World.Map.Bounds.Left) continue; - if (bounds.Bottom <= Game.CellSize * self.World.Map.Bounds.Top) continue; - if (bounds.Left >= Game.CellSize * self.World.Map.Bounds.Right) continue; - if (bounds.Top >= Game.CellSize * self.World.Map.Bounds.Bottom) continue; - - var i1 = Math.Max(0, (int)bounds.Left / scale); - var i2 = Math.Min(bins.GetUpperBound(0), (int)bounds.Right / scale); - var j1 = Math.Max(0, (int)bounds.Top / scale); - var j2 = Math.Min(bins.GetUpperBound(1), (int)bounds.Bottom / scale); - - for (var j = j1; j <= j2; j++) - for (var i = i1; i <= i2; i++) - bins[i, j].Add(a.Actor); - } - } - - IEnumerable ActorsInBins(int i1, int i2, int j1, int j2) - { - j1 = Math.Max(0, j1); j2 = Math.Min(j2, bins.GetUpperBound(1)); - i1 = Math.Max(0, i1); i2 = Math.Min(i2, bins.GetUpperBound(0)); - for (var j = j1; j <= j2; j++) - for (var i = i1; i <= i2; i++) - foreach (var a in bins[i, j]) - yield return a; - } - - public IEnumerable ActorsInBox(int2 a, int2 b) - { - var r = RectangleF.FromLTRB(a.X, a.Y, b.X, b.Y); - - return ActorsInBins(a.X / scale, b.X / scale, a.Y / scale, b.Y / scale) - .Distinct() - .Where(u => u.IsInWorld && u.GetBounds(true).IntersectsWith(r)); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace OpenRA.Traits +{ + class SpatialBinsInfo : ITraitInfo + { + public readonly int BinSize = 8; + public object Create(ActorInitializer init) { return new SpatialBins( init.self, this ); } + } + + class SpatialBins : ITick + { + List[,] bins; + int scale; + + public SpatialBins(Actor self, SpatialBinsInfo info) + { + bins = new List[ + self.World.Map.MapSize.X / info.BinSize, + self.World.Map.MapSize.Y / info.BinSize]; + + scale = Game.CellSize * info.BinSize; + + for (var j = 0; j <= bins.GetUpperBound(1); j++) + for (var i = 0; i <= bins.GetUpperBound(0); i++) + bins[i, j] = new List(); + } + + public void Tick(Actor self) + { + for (var j = 0; j <= bins.GetUpperBound(1); j++) + for (var i = 0; i <= bins.GetUpperBound(0); i++) + bins[i, j].Clear(); + + foreach (var a in self.World.Queries.WithTrait()) + { + var bounds = a.Actor.GetBounds(true); + + if (bounds.Right <= Game.CellSize * self.World.Map.Bounds.Left) continue; + if (bounds.Bottom <= Game.CellSize * self.World.Map.Bounds.Top) continue; + if (bounds.Left >= Game.CellSize * self.World.Map.Bounds.Right) continue; + if (bounds.Top >= Game.CellSize * self.World.Map.Bounds.Bottom) continue; + + var i1 = Math.Max(0, (int)bounds.Left / scale); + var i2 = Math.Min(bins.GetUpperBound(0), (int)bounds.Right / scale); + var j1 = Math.Max(0, (int)bounds.Top / scale); + var j2 = Math.Min(bins.GetUpperBound(1), (int)bounds.Bottom / scale); + + for (var j = j1; j <= j2; j++) + for (var i = i1; i <= i2; i++) + bins[i, j].Add(a.Actor); + } + } + + IEnumerable ActorsInBins(int i1, int i2, int j1, int j2) + { + j1 = Math.Max(0, j1); j2 = Math.Min(j2, bins.GetUpperBound(1)); + i1 = Math.Max(0, i1); i2 = Math.Min(i2, bins.GetUpperBound(0)); + for (var j = j1; j <= j2; j++) + for (var i = i1; i <= i2; i++) + foreach (var a in bins[i, j]) + yield return a; + } + + public IEnumerable ActorsInBox(int2 a, int2 b) + { + var r = RectangleF.FromLTRB(a.X, a.Y, b.X, b.Y); + + return ActorsInBins(a.X / scale, b.X / scale, a.Y / scale, b.Y / scale) + .Distinct() + .Where(u => u.IsInWorld && u.GetBounds(true).IntersectsWith(r)); + } + } +} diff --git a/OpenRA.Game/Traits/World/UnitInfluence.cs b/OpenRA.Game/Traits/World/UnitInfluence.cs index 9461fa5fb2..532428add7 100644 --- a/OpenRA.Game/Traits/World/UnitInfluence.cs +++ b/OpenRA.Game/Traits/World/UnitInfluence.cs @@ -1,117 +1,117 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using OpenRA.FileFormats; - -namespace OpenRA.Traits -{ - public class UnitInfluenceInfo : ITraitInfo - { - public object Create( ActorInitializer init ) { return new UnitInfluence( init.world ); } - } - - public class UnitInfluence - { - class InfluenceNode - { - public InfluenceNode next; - public SubCell subCell; - public Actor actor; - } - - InfluenceNode[,] influence; - Map map; - - public UnitInfluence( World world ) - { - map = world.Map; - influence = new InfluenceNode[world.Map.MapSize.X, world.Map.MapSize.Y]; - - world.ActorAdded += a => Add( a, a.TraitOrDefault() ); - world.ActorRemoved += a => Remove( a, a.TraitOrDefault() ); - } - - public IEnumerable GetUnitsAt( int2 a ) - { - if (!map.IsInMap(a)) yield break; - - for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) - if (!i.actor.Destroyed) - yield return i.actor; - } - - public IEnumerable GetUnitsAt( int2 a, SubCell sub ) - { - if (!map.IsInMap(a)) yield break; - - for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) - if (!i.actor.Destroyed && (i.subCell == sub || i.subCell == SubCell.FullCell)) - yield return i.actor; - } - - public bool HasFreeSubCell(int2 a) - { - if (!AnyUnitsAt(a)) - return true; - - return new[]{SubCell.TopLeft, SubCell.TopRight, SubCell.Center, - SubCell.BottomLeft, SubCell.BottomRight}.Any(b => !AnyUnitsAt(a,b)); - } - - public bool AnyUnitsAt(int2 a) - { - return influence[ a.X, a.Y ] != null; - } - - public bool AnyUnitsAt(int2 a, SubCell sub) - { - for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) - if (i.subCell == sub || i.subCell == SubCell.FullCell) - return true; - - return false; - } - - public void Add( Actor self, IOccupySpace unit ) - { - if (unit != null) - foreach( var c in unit.OccupiedCells() ) - influence[ c.First.X, c.First.Y ] = new InfluenceNode { next = influence[ c.First.X, c.First.Y ], subCell = c.Second, actor = self }; - } - - public void Remove( Actor self, IOccupySpace unit ) - { - if (unit != null) - foreach (var c in unit.OccupiedCells()) - RemoveInner( ref influence[ c.First.X, c.First.Y ], self ); - } - - void RemoveInner( ref InfluenceNode influenceNode, Actor toRemove ) - { - if( influenceNode == null ) - return; - else if( influenceNode.actor == toRemove ) - influenceNode = influenceNode.next; - - if (influenceNode != null) - RemoveInner( ref influenceNode.next, toRemove ); - } - - public void Update(Actor self, IOccupySpace unit) - { - Remove(self, unit); - if (!self.IsDead()) Add(self, unit); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using OpenRA.FileFormats; + +namespace OpenRA.Traits +{ + public class UnitInfluenceInfo : ITraitInfo + { + public object Create( ActorInitializer init ) { return new UnitInfluence( init.world ); } + } + + public class UnitInfluence + { + class InfluenceNode + { + public InfluenceNode next; + public SubCell subCell; + public Actor actor; + } + + InfluenceNode[,] influence; + Map map; + + public UnitInfluence( World world ) + { + map = world.Map; + influence = new InfluenceNode[world.Map.MapSize.X, world.Map.MapSize.Y]; + + world.ActorAdded += a => Add( a, a.TraitOrDefault() ); + world.ActorRemoved += a => Remove( a, a.TraitOrDefault() ); + } + + public IEnumerable GetUnitsAt( int2 a ) + { + if (!map.IsInMap(a)) yield break; + + for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) + if (!i.actor.Destroyed) + yield return i.actor; + } + + public IEnumerable GetUnitsAt( int2 a, SubCell sub ) + { + if (!map.IsInMap(a)) yield break; + + for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) + if (!i.actor.Destroyed && (i.subCell == sub || i.subCell == SubCell.FullCell)) + yield return i.actor; + } + + public bool HasFreeSubCell(int2 a) + { + if (!AnyUnitsAt(a)) + return true; + + return new[]{SubCell.TopLeft, SubCell.TopRight, SubCell.Center, + SubCell.BottomLeft, SubCell.BottomRight}.Any(b => !AnyUnitsAt(a,b)); + } + + public bool AnyUnitsAt(int2 a) + { + return influence[ a.X, a.Y ] != null; + } + + public bool AnyUnitsAt(int2 a, SubCell sub) + { + for( var i = influence[ a.X, a.Y ] ; i != null ; i = i.next ) + if (i.subCell == sub || i.subCell == SubCell.FullCell) + return true; + + return false; + } + + public void Add( Actor self, IOccupySpace unit ) + { + if (unit != null) + foreach( var c in unit.OccupiedCells() ) + influence[ c.First.X, c.First.Y ] = new InfluenceNode { next = influence[ c.First.X, c.First.Y ], subCell = c.Second, actor = self }; + } + + public void Remove( Actor self, IOccupySpace unit ) + { + if (unit != null) + foreach (var c in unit.OccupiedCells()) + RemoveInner( ref influence[ c.First.X, c.First.Y ], self ); + } + + void RemoveInner( ref InfluenceNode influenceNode, Actor toRemove ) + { + if( influenceNode == null ) + return; + else if( influenceNode.actor == toRemove ) + influenceNode = influenceNode.next; + + if (influenceNode != null) + RemoveInner( ref influenceNode.next, toRemove ); + } + + public void Update(Actor self, IOccupySpace unit) + { + Remove(self, unit); + if (!self.IsDead()) Add(self, unit); + } + } +} diff --git a/OpenRA.Game/UiOverlay.cs b/OpenRA.Game/UiOverlay.cs index 56e3e6f2bb..eec3943b04 100644 --- a/OpenRA.Game/UiOverlay.cs +++ b/OpenRA.Game/UiOverlay.cs @@ -1,61 +1,61 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA -{ - public class UiOverlay - { - Sprite buildOk, buildBlocked, unitDebug; - - public UiOverlay() - { - buildOk = SynthesizeTile(0x0f); - buildBlocked = SynthesizeTile(0x08); - unitDebug = SynthesizeTile(0x04); - } - - public static Sprite SynthesizeTile(byte paletteIndex) - { - byte[] data = new byte[Game.CellSize * Game.CellSize]; - - for (int i = 0; i < Game.CellSize; i++) - for (int j = 0; j < Game.CellSize; j++) - data[i * Game.CellSize + j] = ((i+j) % 4 != 0) ? (byte)0 : paletteIndex; - - return Game.modData.SheetBuilder.Add(data, new Size(Game.CellSize, Game.CellSize)); - } - - public void Draw( WorldRenderer wr, World world ) - { - if( world.LocalPlayer == null ) return; - if (world.LocalPlayer.PlayerActor.Trait().UnitInfluenceDebug) - { - var uim = world.WorldActor.Trait(); - - for (var i = world.Map.Bounds.Left; i < world.Map.Bounds.Right; i++) - for (var j = world.Map.Bounds.Top; j < world.Map.Bounds.Bottom; j++) - if (uim.GetUnitsAt(new int2(i, j)).Any()) - unitDebug.DrawAt(wr, Game.CellSize * new float2(i, j), "terrain"); - } - } - - public void DrawGrid( WorldRenderer wr, Dictionary cells ) - { - foreach( var c in cells ) - ( c.Value ? buildOk : buildBlocked ).DrawAt( wr, Game.CellSize * c.Key, "terrain" ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA +{ + public class UiOverlay + { + Sprite buildOk, buildBlocked, unitDebug; + + public UiOverlay() + { + buildOk = SynthesizeTile(0x0f); + buildBlocked = SynthesizeTile(0x08); + unitDebug = SynthesizeTile(0x04); + } + + public static Sprite SynthesizeTile(byte paletteIndex) + { + byte[] data = new byte[Game.CellSize * Game.CellSize]; + + for (int i = 0; i < Game.CellSize; i++) + for (int j = 0; j < Game.CellSize; j++) + data[i * Game.CellSize + j] = ((i+j) % 4 != 0) ? (byte)0 : paletteIndex; + + return Game.modData.SheetBuilder.Add(data, new Size(Game.CellSize, Game.CellSize)); + } + + public void Draw( WorldRenderer wr, World world ) + { + if( world.LocalPlayer == null ) return; + if (world.LocalPlayer.PlayerActor.Trait().UnitInfluenceDebug) + { + var uim = world.WorldActor.Trait(); + + for (var i = world.Map.Bounds.Left; i < world.Map.Bounds.Right; i++) + for (var j = world.Map.Bounds.Top; j < world.Map.Bounds.Bottom; j++) + if (uim.GetUnitsAt(new int2(i, j)).Any()) + unitDebug.DrawAt(wr, Game.CellSize * new float2(i, j), "terrain"); + } + } + + public void DrawGrid( WorldRenderer wr, Dictionary cells ) + { + foreach( var c in cells ) + ( c.Value ? buildOk : buildBlocked ).DrawAt( wr, Game.CellSize * c.Key, "terrain" ); + } + } +} diff --git a/OpenRA.Game/Utilities.cs b/OpenRA.Game/Utilities.cs index 700c833b30..2111d4f2bb 100644 --- a/OpenRA.Game/Utilities.cs +++ b/OpenRA.Game/Utilities.cs @@ -1,84 +1,84 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Diagnostics; -using System.Threading; - -namespace OpenRA -{ - public class Utilities - { - readonly string Utility; - - public Utilities(string utility) - { - Utility = utility; - } - - public void ExtractZipAsync(string zipFile, string path, Action parseOutput, Action onComplete) - { - ExecuteUtilityAsync("--extract-zip \"{0}\" \"{1}\"".F(zipFile, path), parseOutput, onComplete); - } - - public void InstallRAFilesAsync(string cdPath, string path, Action parseOutput, Action onComplete) - { - ExecuteUtilityAsync("--install-ra-packages \"{0}\" \"{1}\"".F(cdPath, path), parseOutput, onComplete); - } - - public void PromptFilepathAsync(string title, Action withPath) - { - ExecuteUtility("--display-filepicker \"{0}\"".F(title), withPath); - } - - void ExecuteUtility(string args, Action onComplete) - { - Process p = new Process(); - p.StartInfo.FileName = Utility; - p.StartInfo.Arguments = args; - p.StartInfo.UseShellExecute = false; - p.StartInfo.CreateNoWindow = true; - p.StartInfo.RedirectStandardOutput = true; - p.EnableRaisingEvents = true; - p.Exited += (_,e) => - { - onComplete(p.StandardOutput.ReadToEnd().Trim()); - }; - p.Start(); - } - - void ExecuteUtilityAsync(string args, Action parseOutput, Action onComplete) - { - Process p = new Process(); - p.StartInfo.FileName = Utility; - p.StartInfo.Arguments = args; - p.StartInfo.UseShellExecute = false; - p.StartInfo.CreateNoWindow = true; - p.StartInfo.RedirectStandardOutput = true; - p.Start(); - - var t = new Thread( _ => - { - using (var reader = p.StandardOutput) - { - // This is wrong, chrisf knows why - while (!p.HasExited) - { - string s = reader.ReadLine(); - if (string.IsNullOrEmpty(s)) continue; - parseOutput(s); - } - } - onComplete(); - }) { IsBackground = true }; - t.Start(); - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Diagnostics; +using System.Threading; + +namespace OpenRA +{ + public class Utilities + { + readonly string Utility; + + public Utilities(string utility) + { + Utility = utility; + } + + public void ExtractZipAsync(string zipFile, string path, Action parseOutput, Action onComplete) + { + ExecuteUtilityAsync("--extract-zip \"{0}\" \"{1}\"".F(zipFile, path), parseOutput, onComplete); + } + + public void InstallRAFilesAsync(string cdPath, string path, Action parseOutput, Action onComplete) + { + ExecuteUtilityAsync("--install-ra-packages \"{0}\" \"{1}\"".F(cdPath, path), parseOutput, onComplete); + } + + public void PromptFilepathAsync(string title, Action withPath) + { + ExecuteUtility("--display-filepicker \"{0}\"".F(title), withPath); + } + + void ExecuteUtility(string args, Action onComplete) + { + Process p = new Process(); + p.StartInfo.FileName = Utility; + p.StartInfo.Arguments = args; + p.StartInfo.UseShellExecute = false; + p.StartInfo.CreateNoWindow = true; + p.StartInfo.RedirectStandardOutput = true; + p.EnableRaisingEvents = true; + p.Exited += (_,e) => + { + onComplete(p.StandardOutput.ReadToEnd().Trim()); + }; + p.Start(); + } + + void ExecuteUtilityAsync(string args, Action parseOutput, Action onComplete) + { + Process p = new Process(); + p.StartInfo.FileName = Utility; + p.StartInfo.Arguments = args; + p.StartInfo.UseShellExecute = false; + p.StartInfo.CreateNoWindow = true; + p.StartInfo.RedirectStandardOutput = true; + p.Start(); + + var t = new Thread( _ => + { + using (var reader = p.StandardOutput) + { + // This is wrong, chrisf knows why + while (!p.HasExited) + { + string s = reader.ReadLine(); + if (string.IsNullOrEmpty(s)) continue; + parseOutput(s); + } + } + onComplete(); + }) { IsBackground = true }; + t.Start(); + } + } } diff --git a/OpenRA.Game/Widgets/BackgroundWidget.cs b/OpenRA.Game/Widgets/BackgroundWidget.cs index a6be4c44b5..720c166948 100644 --- a/OpenRA.Game/Widgets/BackgroundWidget.cs +++ b/OpenRA.Game/Widgets/BackgroundWidget.cs @@ -1,41 +1,41 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public class BackgroundWidget : Widget - { - public readonly string Background = "dialog"; - public readonly bool ClickThrough = false; - - public override void DrawInner() - { - WidgetUtils.DrawPanel(Background, RenderBounds); - } - - public BackgroundWidget() : base() { } - - public override bool HandleMouseInput(MouseInput mi) - { - return !ClickThrough; - } - - protected BackgroundWidget(BackgroundWidget other) - : base(other) - { - Background = other.Background; - ClickThrough = other.ClickThrough; - } - - public override Widget Clone() { return new BackgroundWidget(this); } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public class BackgroundWidget : Widget + { + public readonly string Background = "dialog"; + public readonly bool ClickThrough = false; + + public override void DrawInner() + { + WidgetUtils.DrawPanel(Background, RenderBounds); + } + + public BackgroundWidget() : base() { } + + public override bool HandleMouseInput(MouseInput mi) + { + return !ClickThrough; + } + + protected BackgroundWidget(BackgroundWidget other) + : base(other) + { + Background = other.Background; + ClickThrough = other.ClickThrough; + } + + public override Widget Clone() { return new BackgroundWidget(this); } + } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/ButtonWidget.cs b/OpenRA.Game/Widgets/ButtonWidget.cs index b1f4f04139..ec3304107d 100644 --- a/OpenRA.Game/Widgets/ButtonWidget.cs +++ b/OpenRA.Game/Widgets/ButtonWidget.cs @@ -1,195 +1,195 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.Graphics; -using System.Collections.Generic; - -namespace OpenRA.Widgets -{ - public class ButtonWidget : Widget - { - public string Text = ""; - public bool Bold = false; - public bool Depressed = false; - public int VisualHeight = 1; - public Func GetText; - - public ButtonWidget() - : base() - { - GetText = () => { return Text; }; - } - - protected ButtonWidget(ButtonWidget widget) - : base(widget) - { - Text = widget.Text; - Depressed = widget.Depressed; - VisualHeight = widget.VisualHeight; - GetText = widget.GetText; - } - - public override bool LoseFocus(MouseInput mi) - { - Depressed = false; - return base.LoseFocus(mi); - } - - public override bool HandleMouseInput(MouseInput mi) - { - if (mi.Button != MouseButton.Left) - return false; - - if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) - return false; - - // Only fire the onMouseUp order if we successfully lost focus, and were pressed - if (Focused && mi.Event == MouseInputEvent.Up) - { - if (Depressed) - OnMouseUp(mi); - - return LoseFocus(mi); - } - - if (mi.Event == MouseInputEvent.Down) - { - // OnMouseDown returns false if the button shouldn't be pressed - if (!OnMouseDown(mi)) - Depressed = true; - else - LoseFocus(mi); - } - - else if (mi.Event == MouseInputEvent.Move && Focused) - { - Depressed = RenderBounds.Contains(mi.Location.X, mi.Location.Y); - - // All widgets should recieve MouseMove events - OnMouseMove(mi); - } - - return Depressed; - } - - public override int2 ChildOrigin { get { return RenderOrigin + - ((Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0)); } } - - public override void DrawInner() - { - var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; - var stateOffset = (Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0); - WidgetUtils.DrawPanel(Depressed ? "dialog3" : "dialog2", RenderBounds); - - var text = GetText(); - - font.DrawText(text, - new int2(RenderOrigin.X + UsableWidth / 2, RenderOrigin.Y + Bounds.Height / 2) - - new int2(font.Measure(text).X / 2, - font.Measure(text).Y / 2) + stateOffset, Color.White); - } - - public override Widget Clone() { return new ButtonWidget(this); } - public virtual int UsableWidth { get { return Bounds.Width; } } - } - - public class DropDownButtonWidget : ButtonWidget - { - public DropDownButtonWidget() - : base() - { - } - - protected DropDownButtonWidget(DropDownButtonWidget widget) - : base(widget) - { - } - - public override void DrawInner() - { - base.DrawInner(); - var stateOffset = (Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0); - - var image = ChromeProvider.GetImage("scrollbar", "down_arrow"); - WidgetUtils.DrawRGBA( image, - stateOffset + new float2( RenderBounds.Right - RenderBounds.Height + 4, - RenderBounds.Top + (RenderBounds.Height - image.bounds.Height) / 2 )); - - WidgetUtils.FillRectWithColor(new Rectangle(stateOffset.X + RenderBounds.Right - RenderBounds.Height, - stateOffset.Y + RenderBounds.Top + 3, 1, RenderBounds.Height - 6), - Color.White); - } - - public override Widget Clone() { return new DropDownButtonWidget(this); } - public override int UsableWidth { get { return Bounds.Width - Bounds.Height; } } /* space for button */ - - public static void ShowDropPanel(Widget w, Widget panel, IEnumerable dismissAfter, Func onDismiss) - { - // Mask to prevent any clicks from being sent to other widgets - var fullscreenMask = new ContainerWidget(); - fullscreenMask.Bounds = new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height); - Widget.RootWidget.AddChild(fullscreenMask); - - Action HideDropDown = () => - { - Widget.RootWidget.RemoveChild(fullscreenMask); - Widget.RootWidget.RemoveChild(panel); - }; - - HideDropDown += () => Game.BeforeGameStart -= HideDropDown; - Game.BeforeGameStart += HideDropDown; - - fullscreenMask.OnMouseDown = mi => - { - if (onDismiss()) HideDropDown(); - return true; - }; - fullscreenMask.OnMouseUp = mi => true; - - var oldBounds = panel.Bounds; - panel.Bounds = new Rectangle(w.RenderOrigin.X, w.RenderOrigin.Y + w.Bounds.Height, oldBounds.Width, oldBounds.Height); - panel.OnMouseUp = mi => true; - - foreach (var ww in dismissAfter) - { - var origMouseUp = ww.OnMouseUp; - ww.OnMouseUp = mi => { var result = origMouseUp(mi); if (onDismiss()) HideDropDown(); return result; }; - } - Widget.RootWidget.AddChild(panel); - } - - public static void ShowDropDown(Widget w, IEnumerable ts, Func ft) - { - var dropDown = new ScrollPanelWidget(); - dropDown.Bounds = new Rectangle(w.RenderOrigin.X, w.RenderOrigin.Y + w.Bounds.Height, w.Bounds.Width, 100); - dropDown.ItemSpacing = 1; - - List items = new List(); - List dismissAfter = new List(); - foreach (var t in ts) - { - var ww = ft(t, dropDown.Bounds.Width - dropDown.ScrollbarWidth); - dismissAfter.Add(ww); - ww.OnMouseMove = mi => items.Do(lw => - { - lw.Background = null; ww.Background = "dialog2"; - }); - - dropDown.AddChild(ww); - items.Add(ww); - } - - dropDown.Bounds.Height = Math.Min(150, dropDown.ContentHeight); - ShowDropPanel(w, dropDown, dismissAfter, () => true); - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.Graphics; +using System.Collections.Generic; + +namespace OpenRA.Widgets +{ + public class ButtonWidget : Widget + { + public string Text = ""; + public bool Bold = false; + public bool Depressed = false; + public int VisualHeight = 1; + public Func GetText; + + public ButtonWidget() + : base() + { + GetText = () => { return Text; }; + } + + protected ButtonWidget(ButtonWidget widget) + : base(widget) + { + Text = widget.Text; + Depressed = widget.Depressed; + VisualHeight = widget.VisualHeight; + GetText = widget.GetText; + } + + public override bool LoseFocus(MouseInput mi) + { + Depressed = false; + return base.LoseFocus(mi); + } + + public override bool HandleMouseInput(MouseInput mi) + { + if (mi.Button != MouseButton.Left) + return false; + + if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) + return false; + + // Only fire the onMouseUp order if we successfully lost focus, and were pressed + if (Focused && mi.Event == MouseInputEvent.Up) + { + if (Depressed) + OnMouseUp(mi); + + return LoseFocus(mi); + } + + if (mi.Event == MouseInputEvent.Down) + { + // OnMouseDown returns false if the button shouldn't be pressed + if (!OnMouseDown(mi)) + Depressed = true; + else + LoseFocus(mi); + } + + else if (mi.Event == MouseInputEvent.Move && Focused) + { + Depressed = RenderBounds.Contains(mi.Location.X, mi.Location.Y); + + // All widgets should recieve MouseMove events + OnMouseMove(mi); + } + + return Depressed; + } + + public override int2 ChildOrigin { get { return RenderOrigin + + ((Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0)); } } + + public override void DrawInner() + { + var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; + var stateOffset = (Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0); + WidgetUtils.DrawPanel(Depressed ? "dialog3" : "dialog2", RenderBounds); + + var text = GetText(); + + font.DrawText(text, + new int2(RenderOrigin.X + UsableWidth / 2, RenderOrigin.Y + Bounds.Height / 2) + - new int2(font.Measure(text).X / 2, + font.Measure(text).Y / 2) + stateOffset, Color.White); + } + + public override Widget Clone() { return new ButtonWidget(this); } + public virtual int UsableWidth { get { return Bounds.Width; } } + } + + public class DropDownButtonWidget : ButtonWidget + { + public DropDownButtonWidget() + : base() + { + } + + protected DropDownButtonWidget(DropDownButtonWidget widget) + : base(widget) + { + } + + public override void DrawInner() + { + base.DrawInner(); + var stateOffset = (Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0); + + var image = ChromeProvider.GetImage("scrollbar", "down_arrow"); + WidgetUtils.DrawRGBA( image, + stateOffset + new float2( RenderBounds.Right - RenderBounds.Height + 4, + RenderBounds.Top + (RenderBounds.Height - image.bounds.Height) / 2 )); + + WidgetUtils.FillRectWithColor(new Rectangle(stateOffset.X + RenderBounds.Right - RenderBounds.Height, + stateOffset.Y + RenderBounds.Top + 3, 1, RenderBounds.Height - 6), + Color.White); + } + + public override Widget Clone() { return new DropDownButtonWidget(this); } + public override int UsableWidth { get { return Bounds.Width - Bounds.Height; } } /* space for button */ + + public static void ShowDropPanel(Widget w, Widget panel, IEnumerable dismissAfter, Func onDismiss) + { + // Mask to prevent any clicks from being sent to other widgets + var fullscreenMask = new ContainerWidget(); + fullscreenMask.Bounds = new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height); + Widget.RootWidget.AddChild(fullscreenMask); + + Action HideDropDown = () => + { + Widget.RootWidget.RemoveChild(fullscreenMask); + Widget.RootWidget.RemoveChild(panel); + }; + + HideDropDown += () => Game.BeforeGameStart -= HideDropDown; + Game.BeforeGameStart += HideDropDown; + + fullscreenMask.OnMouseDown = mi => + { + if (onDismiss()) HideDropDown(); + return true; + }; + fullscreenMask.OnMouseUp = mi => true; + + var oldBounds = panel.Bounds; + panel.Bounds = new Rectangle(w.RenderOrigin.X, w.RenderOrigin.Y + w.Bounds.Height, oldBounds.Width, oldBounds.Height); + panel.OnMouseUp = mi => true; + + foreach (var ww in dismissAfter) + { + var origMouseUp = ww.OnMouseUp; + ww.OnMouseUp = mi => { var result = origMouseUp(mi); if (onDismiss()) HideDropDown(); return result; }; + } + Widget.RootWidget.AddChild(panel); + } + + public static void ShowDropDown(Widget w, IEnumerable ts, Func ft) + { + var dropDown = new ScrollPanelWidget(); + dropDown.Bounds = new Rectangle(w.RenderOrigin.X, w.RenderOrigin.Y + w.Bounds.Height, w.Bounds.Width, 100); + dropDown.ItemSpacing = 1; + + List items = new List(); + List dismissAfter = new List(); + foreach (var t in ts) + { + var ww = ft(t, dropDown.Bounds.Width - dropDown.ScrollbarWidth); + dismissAfter.Add(ww); + ww.OnMouseMove = mi => items.Do(lw => + { + lw.Background = null; ww.Background = "dialog2"; + }); + + dropDown.AddChild(ww); + items.Add(ww); + } + + dropDown.Bounds.Height = Math.Min(150, dropDown.ContentHeight); + ShowDropPanel(w, dropDown, dismissAfter, () => true); + } + } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/ChatDisplayWidget.cs b/OpenRA.Game/Widgets/ChatDisplayWidget.cs index 23ba3ae93c..7ef62c02e2 100644 --- a/OpenRA.Game/Widgets/ChatDisplayWidget.cs +++ b/OpenRA.Game/Widgets/ChatDisplayWidget.cs @@ -1,106 +1,106 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public class ChatDisplayWidget : Widget - { - public readonly int RemoveTime = 0; - public readonly bool UseContrast = false; - - const int logLength = 9; - public string Notification = ""; - public bool DrawBackground = true; - int ticksUntilRemove = 0; - - internal List recentLines = new List(); - - public ChatDisplayWidget() - : base() { } - - protected ChatDisplayWidget(Widget widget) - : base(widget) { } - - public override Rectangle EventBounds { get { return Rectangle.Empty; } } - public override void DrawInner() - { - var pos = RenderOrigin; - var chatLogArea = new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height); - var chatpos = new int2(chatLogArea.X + 10, chatLogArea.Bottom - 6); - - if (DrawBackground) - WidgetUtils.DrawPanel("dialog3", chatLogArea); - - Game.Renderer.EnableScissor(chatLogArea.Left, chatLogArea.Top, chatLogArea.Width, chatLogArea.Height); - foreach (var line in recentLines.AsEnumerable().Reverse()) - { - chatpos.Y -= 20; - int inset = 0; - - if (!string.IsNullOrEmpty(line.Owner)) - { - var owner = line.Owner + ":"; - inset = Game.Renderer.RegularFont.Measure(owner).X + 10; - - Game.Renderer.RegularFont.DrawTextWithContrast(owner, chatpos, - line.Color, Color.Black, UseContrast ? 1 : 0); - } - - Game.Renderer.RegularFont.DrawTextWithContrast(line.Text, chatpos + new int2(inset, 0), - Color.White, Color.Black, UseContrast ? 1 : 0); - } - - Game.Renderer.DisableScissor(); - } - - public void AddLine(Color c, string from, string text) - { - recentLines.Add(new ChatLine { Color = c, Owner = from, Text = text }); - ticksUntilRemove = RemoveTime; - - if (Notification != null) - Sound.Play(Notification); - - while (recentLines.Count > logLength) recentLines.RemoveAt(0); - } - - public void RemoveLine() - { - if (recentLines.Count > 0) recentLines.RemoveAt(0); - } - - public void ClearChat() - { - recentLines = new List(); - } - - public override void Tick() - { - if (RemoveTime == 0) return; - if (--ticksUntilRemove > 0) return; - ticksUntilRemove = RemoveTime; - RemoveLine(); - } - - public override Widget Clone() { return new ChatDisplayWidget(this); } - } - - class ChatLine - { - public Color Color = Color.White; - public string Owner, Text; - public bool wrapped = false; - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public class ChatDisplayWidget : Widget + { + public readonly int RemoveTime = 0; + public readonly bool UseContrast = false; + + const int logLength = 9; + public string Notification = ""; + public bool DrawBackground = true; + int ticksUntilRemove = 0; + + internal List recentLines = new List(); + + public ChatDisplayWidget() + : base() { } + + protected ChatDisplayWidget(Widget widget) + : base(widget) { } + + public override Rectangle EventBounds { get { return Rectangle.Empty; } } + public override void DrawInner() + { + var pos = RenderOrigin; + var chatLogArea = new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height); + var chatpos = new int2(chatLogArea.X + 10, chatLogArea.Bottom - 6); + + if (DrawBackground) + WidgetUtils.DrawPanel("dialog3", chatLogArea); + + Game.Renderer.EnableScissor(chatLogArea.Left, chatLogArea.Top, chatLogArea.Width, chatLogArea.Height); + foreach (var line in recentLines.AsEnumerable().Reverse()) + { + chatpos.Y -= 20; + int inset = 0; + + if (!string.IsNullOrEmpty(line.Owner)) + { + var owner = line.Owner + ":"; + inset = Game.Renderer.RegularFont.Measure(owner).X + 10; + + Game.Renderer.RegularFont.DrawTextWithContrast(owner, chatpos, + line.Color, Color.Black, UseContrast ? 1 : 0); + } + + Game.Renderer.RegularFont.DrawTextWithContrast(line.Text, chatpos + new int2(inset, 0), + Color.White, Color.Black, UseContrast ? 1 : 0); + } + + Game.Renderer.DisableScissor(); + } + + public void AddLine(Color c, string from, string text) + { + recentLines.Add(new ChatLine { Color = c, Owner = from, Text = text }); + ticksUntilRemove = RemoveTime; + + if (Notification != null) + Sound.Play(Notification); + + while (recentLines.Count > logLength) recentLines.RemoveAt(0); + } + + public void RemoveLine() + { + if (recentLines.Count > 0) recentLines.RemoveAt(0); + } + + public void ClearChat() + { + recentLines = new List(); + } + + public override void Tick() + { + if (RemoveTime == 0) return; + if (--ticksUntilRemove > 0) return; + ticksUntilRemove = RemoveTime; + RemoveLine(); + } + + public override Widget Clone() { return new ChatDisplayWidget(this); } + } + + class ChatLine + { + public Color Color = Color.White; + public string Owner, Text; + public bool wrapped = false; + } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/ChatEntryWidget.cs b/OpenRA.Game/Widgets/ChatEntryWidget.cs index ef4e3e953b..2b2e08b5e0 100755 --- a/OpenRA.Game/Widgets/ChatEntryWidget.cs +++ b/OpenRA.Game/Widgets/ChatEntryWidget.cs @@ -1,115 +1,115 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.Graphics; -using OpenRA.Network; - -namespace OpenRA.Widgets -{ - // a dirty hack of a widget, which likes to steal the focus when \r is pressed, and then - // refuse to give it up until \r is pressed again. - - // this emulates the previous chat support, with one improvement: shift+enter can toggle the - // team/all mode *while* composing, not just on beginning to compose. - - public class ChatEntryWidget : Widget - { - string content = ""; - bool composing = false; - bool teamChat = false; - public readonly bool UseContrast = false; - - readonly OrderManager orderManager; - [ObjectCreator.UseCtor] - internal ChatEntryWidget( [ObjectCreator.Param] OrderManager orderManager ) - { - this.orderManager = orderManager; - } - - public override void DrawInner() - { - if (composing) - { - var text = teamChat ? "Chat (Team): " : "Chat (All): "; - var w = Game.Renderer.BoldFont.Measure(text).X; - - Game.Renderer.BoldFont.DrawTextWithContrast(text, RenderOrigin + new float2(3, 7), Color.White, Color.Black, UseContrast ? 1 : 0); - Game.Renderer.RegularFont.DrawTextWithContrast(content, RenderOrigin + new float2(3 + w, 7), Color.White, Color.Black, UseContrast ? 1 : 0); - } - } - - public override Rectangle EventBounds { get { return Rectangle.Empty; } } - public override bool LoseFocus(MouseInput mi) - { - return composing ? false : base.LoseFocus(mi); - } - - public override bool HandleKeyPressInner(KeyInput e) - { - if (e.Event == KeyInputEvent.Up) return false; - - if (e.KeyChar == '\r') - { - if (composing) - { - if (e.Modifiers.HasModifier(Modifiers.Shift)) - { - teamChat ^= true; - return true; - } - - composing = false; - if (content != "") - orderManager.IssueOrder(teamChat - ? Order.TeamChat(content) - : Order.Chat(content)); - content = ""; - - LoseFocus(); - return true; - } - else - { - TakeFocus(new MouseInput()); - composing = true; - if (Game.Settings.Game.TeamChatToggle) - { - teamChat ^= e.Modifiers.HasModifier(Modifiers.Shift); - } - else - { - teamChat = e.Modifiers.HasModifier(Modifiers.Shift); - } - return true; - } - } - - if (composing) - { - if (e.KeyChar == '\b' || e.KeyChar == 0x7f) - { - if (content.Length > 0) - content = content.Remove(content.Length - 1); - return true; - } - else if (!char.IsControl(e.KeyChar)) - { - content += e.KeyChar; - return true; - } - - return false; - } - - return base.HandleKeyPressInner(e); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.Graphics; +using OpenRA.Network; + +namespace OpenRA.Widgets +{ + // a dirty hack of a widget, which likes to steal the focus when \r is pressed, and then + // refuse to give it up until \r is pressed again. + + // this emulates the previous chat support, with one improvement: shift+enter can toggle the + // team/all mode *while* composing, not just on beginning to compose. + + public class ChatEntryWidget : Widget + { + string content = ""; + bool composing = false; + bool teamChat = false; + public readonly bool UseContrast = false; + + readonly OrderManager orderManager; + [ObjectCreator.UseCtor] + internal ChatEntryWidget( [ObjectCreator.Param] OrderManager orderManager ) + { + this.orderManager = orderManager; + } + + public override void DrawInner() + { + if (composing) + { + var text = teamChat ? "Chat (Team): " : "Chat (All): "; + var w = Game.Renderer.BoldFont.Measure(text).X; + + Game.Renderer.BoldFont.DrawTextWithContrast(text, RenderOrigin + new float2(3, 7), Color.White, Color.Black, UseContrast ? 1 : 0); + Game.Renderer.RegularFont.DrawTextWithContrast(content, RenderOrigin + new float2(3 + w, 7), Color.White, Color.Black, UseContrast ? 1 : 0); + } + } + + public override Rectangle EventBounds { get { return Rectangle.Empty; } } + public override bool LoseFocus(MouseInput mi) + { + return composing ? false : base.LoseFocus(mi); + } + + public override bool HandleKeyPressInner(KeyInput e) + { + if (e.Event == KeyInputEvent.Up) return false; + + if (e.KeyChar == '\r') + { + if (composing) + { + if (e.Modifiers.HasModifier(Modifiers.Shift)) + { + teamChat ^= true; + return true; + } + + composing = false; + if (content != "") + orderManager.IssueOrder(teamChat + ? Order.TeamChat(content) + : Order.Chat(content)); + content = ""; + + LoseFocus(); + return true; + } + else + { + TakeFocus(new MouseInput()); + composing = true; + if (Game.Settings.Game.TeamChatToggle) + { + teamChat ^= e.Modifiers.HasModifier(Modifiers.Shift); + } + else + { + teamChat = e.Modifiers.HasModifier(Modifiers.Shift); + } + return true; + } + } + + if (composing) + { + if (e.KeyChar == '\b' || e.KeyChar == 0x7f) + { + if (content.Length > 0) + content = content.Remove(content.Length - 1); + return true; + } + else if (!char.IsControl(e.KeyChar)) + { + content += e.KeyChar; + return true; + } + + return false; + } + + return base.HandleKeyPressInner(e); + } + } +} diff --git a/OpenRA.Game/Widgets/CheckboxWidget.cs b/OpenRA.Game/Widgets/CheckboxWidget.cs index 2233c19479..18d365811f 100644 --- a/OpenRA.Game/Widgets/CheckboxWidget.cs +++ b/OpenRA.Game/Widgets/CheckboxWidget.cs @@ -1,88 +1,88 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.Graphics; -using System.Reflection; - -namespace OpenRA.Widgets -{ - public class CheckboxWidget : Widget - { - public string Text = ""; - public int baseLine = 1; - public bool Bold = false; - public Func IsChecked = () => false; - public event Action OnChange = _ => {}; - - object boundObject; - bool boundReadOnly; - FieldInfo boundField; - - public override void DrawInner() - { - var font = Bold ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; - var pos = RenderOrigin; - var rect = RenderBounds; - var check = new Rectangle(rect.Location, - new Size(Bounds.Height, Bounds.Height)); - WidgetUtils.DrawPanel("dialog3", check); - - var textSize = font.Measure(Text); - font.DrawText(Text, - new float2(rect.Left + rect.Height * 1.5f, - pos.Y - baseLine + (Bounds.Height - textSize.Y)/2), Color.White); - - if ((boundObject != null && (bool)boundField.GetValue(boundObject)) || IsChecked()) - WidgetUtils.DrawRGBA( - ChromeProvider.GetImage("checkbox", "checked"), - new float2(rect.Left + 2, rect.Top + 2)); - } - - public void Bind(object obj, string field) { Bind(obj, field, false); } - public void BindReadOnly(object obj, string field) { Bind(obj, field, true); } - - void Bind(object obj, string field, bool readOnly) - { - boundObject = obj; - boundReadOnly = readOnly; - boundField = obj.GetType().GetField(field); - } - - // TODO: CheckboxWidget doesn't support delegate methods for mouse input - public override bool HandleMouseInput(MouseInput mi) - { - // Checkboxes require lmb - if (mi.Button != MouseButton.Left || mi.Event != MouseInputEvent.Down) - return false; - - bool newVal = !IsChecked(); - if (boundObject != null && !boundReadOnly) - { - newVal = !(bool)boundField.GetValue(boundObject); - boundField.SetValue(boundObject, newVal); - } - - OnChange(newVal); - return true; - } - - public CheckboxWidget() : base() { } - - protected CheckboxWidget(CheckboxWidget other) - : base(other) - { - Text = other.Text; - } - - public override Widget Clone() { return new CheckboxWidget(this); } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.Graphics; +using System.Reflection; + +namespace OpenRA.Widgets +{ + public class CheckboxWidget : Widget + { + public string Text = ""; + public int baseLine = 1; + public bool Bold = false; + public Func IsChecked = () => false; + public event Action OnChange = _ => {}; + + object boundObject; + bool boundReadOnly; + FieldInfo boundField; + + public override void DrawInner() + { + var font = Bold ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; + var pos = RenderOrigin; + var rect = RenderBounds; + var check = new Rectangle(rect.Location, + new Size(Bounds.Height, Bounds.Height)); + WidgetUtils.DrawPanel("dialog3", check); + + var textSize = font.Measure(Text); + font.DrawText(Text, + new float2(rect.Left + rect.Height * 1.5f, + pos.Y - baseLine + (Bounds.Height - textSize.Y)/2), Color.White); + + if ((boundObject != null && (bool)boundField.GetValue(boundObject)) || IsChecked()) + WidgetUtils.DrawRGBA( + ChromeProvider.GetImage("checkbox", "checked"), + new float2(rect.Left + 2, rect.Top + 2)); + } + + public void Bind(object obj, string field) { Bind(obj, field, false); } + public void BindReadOnly(object obj, string field) { Bind(obj, field, true); } + + void Bind(object obj, string field, bool readOnly) + { + boundObject = obj; + boundReadOnly = readOnly; + boundField = obj.GetType().GetField(field); + } + + // TODO: CheckboxWidget doesn't support delegate methods for mouse input + public override bool HandleMouseInput(MouseInput mi) + { + // Checkboxes require lmb + if (mi.Button != MouseButton.Left || mi.Event != MouseInputEvent.Down) + return false; + + bool newVal = !IsChecked(); + if (boundObject != null && !boundReadOnly) + { + newVal = !(bool)boundField.GetValue(boundObject); + boundField.SetValue(boundObject, newVal); + } + + OnChange(newVal); + return true; + } + + public CheckboxWidget() : base() { } + + protected CheckboxWidget(CheckboxWidget other) + : base(other) + { + Text = other.Text; + } + + public override Widget Clone() { return new CheckboxWidget(this); } + } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/ColorBlockWidget.cs b/OpenRA.Game/Widgets/ColorBlockWidget.cs index 0a30f7d1eb..2a0de7612d 100644 --- a/OpenRA.Game/Widgets/ColorBlockWidget.cs +++ b/OpenRA.Game/Widgets/ColorBlockWidget.cs @@ -1,43 +1,43 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public class ColorBlockWidget : Widget - { - public Func GetColor; - - public ColorBlockWidget() - : base() - { - GetColor = () => Color.White; - } - - protected ColorBlockWidget(ColorBlockWidget widget) - : base(widget) - { - GetColor = widget.GetColor; - } - - public override Widget Clone() - { - return new ColorBlockWidget(this); - } - - public override void DrawInner() - { - WidgetUtils.FillRectWithColor(RenderBounds, GetColor()); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public class ColorBlockWidget : Widget + { + public Func GetColor; + + public ColorBlockWidget() + : base() + { + GetColor = () => Color.White; + } + + protected ColorBlockWidget(ColorBlockWidget widget) + : base(widget) + { + GetColor = widget.GetColor; + } + + public override Widget Clone() + { + return new ColorBlockWidget(this); + } + + public override void DrawInner() + { + WidgetUtils.FillRectWithColor(RenderBounds, GetColor()); + } + } +} diff --git a/OpenRA.Game/Widgets/ImageWidget.cs b/OpenRA.Game/Widgets/ImageWidget.cs index e17fbb23f7..72a667b3f8 100644 --- a/OpenRA.Game/Widgets/ImageWidget.cs +++ b/OpenRA.Game/Widgets/ImageWidget.cs @@ -1,50 +1,50 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public class ImageWidget : Widget - { - public string ImageCollection = ""; - public string ImageName = ""; - public Func GetImageName; - public Func GetImageCollection; - - public ImageWidget() - : base() - { - GetImageName = () => ImageName; - GetImageCollection = () => ImageCollection; - } - - protected ImageWidget(ImageWidget other) - : base(other) - { - ImageName = other.ImageName; - GetImageName = other.GetImageName; - ImageCollection = other.ImageCollection; - GetImageCollection = other.GetImageCollection; - } - - public override Widget Clone() { return new ImageWidget(this); } - - public override void DrawInner() - { - var name = GetImageName(); - var collection = GetImageCollection(); - WidgetUtils.DrawRGBA( - ChromeProvider.GetImage(collection, name), - RenderOrigin); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public class ImageWidget : Widget + { + public string ImageCollection = ""; + public string ImageName = ""; + public Func GetImageName; + public Func GetImageCollection; + + public ImageWidget() + : base() + { + GetImageName = () => ImageName; + GetImageCollection = () => ImageCollection; + } + + protected ImageWidget(ImageWidget other) + : base(other) + { + ImageName = other.ImageName; + GetImageName = other.GetImageName; + ImageCollection = other.ImageCollection; + GetImageCollection = other.GetImageCollection; + } + + public override Widget Clone() { return new ImageWidget(this); } + + public override void DrawInner() + { + var name = GetImageName(); + var collection = GetImageCollection(); + WidgetUtils.DrawRGBA( + ChromeProvider.GetImage(collection, name), + RenderOrigin); + } + } +} diff --git a/OpenRA.Game/Widgets/LabelWidget.cs b/OpenRA.Game/Widgets/LabelWidget.cs index fd38f8d948..1a2ce21342 100644 --- a/OpenRA.Game/Widgets/LabelWidget.cs +++ b/OpenRA.Game/Widgets/LabelWidget.cs @@ -1,132 +1,132 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public class LabelWidget : Widget - { - public enum TextAlign { Left, Center, Right } - public enum TextVAlign { Top, Middle, Bottom } - - public string Text = null; - public string Background = null; - public TextAlign Align = TextAlign.Left; - public TextVAlign VAlign = TextVAlign.Middle; - public bool Bold = false; - public bool WordWrap = false; - public Func GetText; - public Func GetBackground; - - public LabelWidget() - : base() - { - GetText = () => Text; - GetBackground = () => Background; - } - - protected LabelWidget(LabelWidget other) - : base(other) - { - Text = other.Text; - Align = other.Align; - Bold = other.Bold; - GetText = other.GetText; - GetBackground = other.GetBackground; - } - - public override void DrawInner() - { - var bg = GetBackground(); - - if (bg != null) - WidgetUtils.DrawPanel(bg, RenderBounds ); - - var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; - var text = GetText(); - if (text == null) - return; - - int2 textSize = font.Measure(text); - int2 position = RenderOrigin; - - if (VAlign == TextVAlign.Middle) - position += new int2(0, (Bounds.Height - textSize.Y)/2); - - if (VAlign == TextVAlign.Bottom) - position += new int2(0, Bounds.Height - textSize.Y); - - if (Align == TextAlign.Center) - position += new int2((Bounds.Width - textSize.X)/2, 0); - - if (Align == TextAlign.Right) - position += new int2(Bounds.Width - textSize.X,0); - - if (WordWrap) - { - if (textSize.X > Bounds.Width) - { - string[] lines = text.Split('\n'); - List newLines = new List(); - int i = 0; - string line = lines[i++]; - while (true) - { - newLines.Add(line); - int2 m = font.Measure(line); - int spaceIndex = 0, start = line.Length - 1; - - if (m.X <= Bounds.Width) - { - if (i < lines.Length - 1) - { - line = lines[i++]; - continue; - } - else - break; - } - - while (m.X > Bounds.Width) - { - if (-1 == (spaceIndex = line.LastIndexOf(' ', start))) - break; - start = spaceIndex - 1; - m = font.Measure(line.Substring(0, spaceIndex)); - } - - if (spaceIndex != -1) - { - newLines.RemoveAt(newLines.Count - 1); - newLines.Add(line.Substring(0, spaceIndex)); - line = line.Substring(spaceIndex + 1); - } - else if (i < lines.Length - 1) - { - line = lines[i++]; - continue; - } - else - break; - } - text = string.Join("\n", newLines.ToArray()); - } - } - - font.DrawText(text, position, Color.White); - } - - public override Widget Clone() { return new LabelWidget(this); } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public class LabelWidget : Widget + { + public enum TextAlign { Left, Center, Right } + public enum TextVAlign { Top, Middle, Bottom } + + public string Text = null; + public string Background = null; + public TextAlign Align = TextAlign.Left; + public TextVAlign VAlign = TextVAlign.Middle; + public bool Bold = false; + public bool WordWrap = false; + public Func GetText; + public Func GetBackground; + + public LabelWidget() + : base() + { + GetText = () => Text; + GetBackground = () => Background; + } + + protected LabelWidget(LabelWidget other) + : base(other) + { + Text = other.Text; + Align = other.Align; + Bold = other.Bold; + GetText = other.GetText; + GetBackground = other.GetBackground; + } + + public override void DrawInner() + { + var bg = GetBackground(); + + if (bg != null) + WidgetUtils.DrawPanel(bg, RenderBounds ); + + var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; + var text = GetText(); + if (text == null) + return; + + int2 textSize = font.Measure(text); + int2 position = RenderOrigin; + + if (VAlign == TextVAlign.Middle) + position += new int2(0, (Bounds.Height - textSize.Y)/2); + + if (VAlign == TextVAlign.Bottom) + position += new int2(0, Bounds.Height - textSize.Y); + + if (Align == TextAlign.Center) + position += new int2((Bounds.Width - textSize.X)/2, 0); + + if (Align == TextAlign.Right) + position += new int2(Bounds.Width - textSize.X,0); + + if (WordWrap) + { + if (textSize.X > Bounds.Width) + { + string[] lines = text.Split('\n'); + List newLines = new List(); + int i = 0; + string line = lines[i++]; + while (true) + { + newLines.Add(line); + int2 m = font.Measure(line); + int spaceIndex = 0, start = line.Length - 1; + + if (m.X <= Bounds.Width) + { + if (i < lines.Length - 1) + { + line = lines[i++]; + continue; + } + else + break; + } + + while (m.X > Bounds.Width) + { + if (-1 == (spaceIndex = line.LastIndexOf(' ', start))) + break; + start = spaceIndex - 1; + m = font.Measure(line.Substring(0, spaceIndex)); + } + + if (spaceIndex != -1) + { + newLines.RemoveAt(newLines.Count - 1); + newLines.Add(line.Substring(0, spaceIndex)); + line = line.Substring(spaceIndex + 1); + } + else if (i < lines.Length - 1) + { + line = lines[i++]; + continue; + } + else + break; + } + text = string.Join("\n", newLines.ToArray()); + } + } + + font.DrawText(text, position, Color.White); + } + + public override Widget Clone() { return new LabelWidget(this); } + } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/MapPreviewWidget.cs b/OpenRA.Game/Widgets/MapPreviewWidget.cs index 2afd6ef9ad..422cf3d8f1 100644 --- a/OpenRA.Game/Widgets/MapPreviewWidget.cs +++ b/OpenRA.Game/Widgets/MapPreviewWidget.cs @@ -1,101 +1,101 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public class MapPreviewWidget : Widget - { - public Func Map = () => null; - public Func> SpawnColors = () => new Dictionary(); - static Cache PreviewCache = new Cache(stub => Minimap.RenderMapPreview( new Map( stub.Path ))); - - public MapPreviewWidget() : base() { } - protected MapPreviewWidget(MapPreviewWidget other) - : base(other) - { - lastMap = other.lastMap; - Map = other.Map; - SpawnColors = other.SpawnColors; - } - public override Widget Clone() { return new MapPreviewWidget(this); } - - public int2 ConvertToPreview(Map map, int2 point) - { - return new int2(MapRect.X + (int)(PreviewScale*(point.X - map.Bounds.Left)) , MapRect.Y + (int)(PreviewScale*(point.Y - map.Bounds.Top))); - } - - Sheet mapChooserSheet; - Sprite mapChooserSprite; - Map lastMap; - Rectangle MapRect; - float PreviewScale = 0; - static Sprite UnownedSpawn = null; - static Sprite OwnedSpawn = null; - - public override void DrawInner() - { - if (UnownedSpawn == null) - UnownedSpawn = ChromeProvider.GetImage("spawnpoints", "unowned"); - if (OwnedSpawn == null) - OwnedSpawn = ChromeProvider.GetImage("spawnpoints", "owned"); - - var map = Map(); - if( map == null ) return; - - if (lastMap != map) - { - lastMap = map; - - // Update image data - var preview = PreviewCache[map]; - if( mapChooserSheet == null || mapChooserSheet.Size.Width != preview.Width || mapChooserSheet.Size.Height != preview.Height ) - mapChooserSheet = new Sheet(new Size( preview.Width, preview.Height ) ); - - mapChooserSheet.Texture.SetData( preview ); - mapChooserSprite = new Sprite( mapChooserSheet, new Rectangle( 0, 0, map.Bounds.Width, map.Bounds.Height ), TextureChannel.Alpha ); - - // Update map rect - PreviewScale = Math.Min(RenderBounds.Width * 1.0f / map.Bounds.Width, RenderBounds.Height * 1.0f / map.Bounds.Height); - var size = Math.Max(map.Bounds.Width, map.Bounds.Height); - var dw = (int)(PreviewScale * (size - map.Bounds.Width)) / 2; - var dh = (int)(PreviewScale * (size - map.Bounds.Height)) / 2; - MapRect = new Rectangle(RenderBounds.X + dw, RenderBounds.Y + dh, (int)(map.Bounds.Width * PreviewScale), (int)(map.Bounds.Height * PreviewScale)); - } - - Game.Renderer.RgbaSpriteRenderer.DrawSprite( mapChooserSprite, - new float2(MapRect.Location), - new float2( MapRect.Size ) ); - - // Overlay spawnpoints - var colors = SpawnColors(); - foreach (var p in map.SpawnPoints) - { - var pos = ConvertToPreview(map, p); - var sprite = UnownedSpawn; - var offset = new int2(-UnownedSpawn.bounds.Width/2, -UnownedSpawn.bounds.Height/2); - - if (colors.ContainsKey(p)) - { - sprite = OwnedSpawn; - offset = new int2(-OwnedSpawn.bounds.Width/2, -OwnedSpawn.bounds.Height/2); - WidgetUtils.FillRectWithColor(new Rectangle(pos.X + offset.X + 2, pos.Y + offset.Y + 2, 12, 12), colors[p]); - } - Game.Renderer.RgbaSpriteRenderer.DrawSprite(sprite, pos + offset); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public class MapPreviewWidget : Widget + { + public Func Map = () => null; + public Func> SpawnColors = () => new Dictionary(); + static Cache PreviewCache = new Cache(stub => Minimap.RenderMapPreview( new Map( stub.Path ))); + + public MapPreviewWidget() : base() { } + protected MapPreviewWidget(MapPreviewWidget other) + : base(other) + { + lastMap = other.lastMap; + Map = other.Map; + SpawnColors = other.SpawnColors; + } + public override Widget Clone() { return new MapPreviewWidget(this); } + + public int2 ConvertToPreview(Map map, int2 point) + { + return new int2(MapRect.X + (int)(PreviewScale*(point.X - map.Bounds.Left)) , MapRect.Y + (int)(PreviewScale*(point.Y - map.Bounds.Top))); + } + + Sheet mapChooserSheet; + Sprite mapChooserSprite; + Map lastMap; + Rectangle MapRect; + float PreviewScale = 0; + static Sprite UnownedSpawn = null; + static Sprite OwnedSpawn = null; + + public override void DrawInner() + { + if (UnownedSpawn == null) + UnownedSpawn = ChromeProvider.GetImage("spawnpoints", "unowned"); + if (OwnedSpawn == null) + OwnedSpawn = ChromeProvider.GetImage("spawnpoints", "owned"); + + var map = Map(); + if( map == null ) return; + + if (lastMap != map) + { + lastMap = map; + + // Update image data + var preview = PreviewCache[map]; + if( mapChooserSheet == null || mapChooserSheet.Size.Width != preview.Width || mapChooserSheet.Size.Height != preview.Height ) + mapChooserSheet = new Sheet(new Size( preview.Width, preview.Height ) ); + + mapChooserSheet.Texture.SetData( preview ); + mapChooserSprite = new Sprite( mapChooserSheet, new Rectangle( 0, 0, map.Bounds.Width, map.Bounds.Height ), TextureChannel.Alpha ); + + // Update map rect + PreviewScale = Math.Min(RenderBounds.Width * 1.0f / map.Bounds.Width, RenderBounds.Height * 1.0f / map.Bounds.Height); + var size = Math.Max(map.Bounds.Width, map.Bounds.Height); + var dw = (int)(PreviewScale * (size - map.Bounds.Width)) / 2; + var dh = (int)(PreviewScale * (size - map.Bounds.Height)) / 2; + MapRect = new Rectangle(RenderBounds.X + dw, RenderBounds.Y + dh, (int)(map.Bounds.Width * PreviewScale), (int)(map.Bounds.Height * PreviewScale)); + } + + Game.Renderer.RgbaSpriteRenderer.DrawSprite( mapChooserSprite, + new float2(MapRect.Location), + new float2( MapRect.Size ) ); + + // Overlay spawnpoints + var colors = SpawnColors(); + foreach (var p in map.SpawnPoints) + { + var pos = ConvertToPreview(map, p); + var sprite = UnownedSpawn; + var offset = new int2(-UnownedSpawn.bounds.Width/2, -UnownedSpawn.bounds.Height/2); + + if (colors.ContainsKey(p)) + { + sprite = OwnedSpawn; + offset = new int2(-OwnedSpawn.bounds.Width/2, -OwnedSpawn.bounds.Height/2); + WidgetUtils.FillRectWithColor(new Rectangle(pos.X + offset.X + 2, pos.Y + offset.Y + 2, 12, 12), colors[p]); + } + Game.Renderer.RgbaSpriteRenderer.DrawSprite(sprite, pos + offset); + } + } + } +} diff --git a/OpenRA.Game/Widgets/PasswordFieldWidget.cs b/OpenRA.Game/Widgets/PasswordFieldWidget.cs index 000fdcbfb7..6c2620c98b 100644 --- a/OpenRA.Game/Widgets/PasswordFieldWidget.cs +++ b/OpenRA.Game/Widgets/PasswordFieldWidget.cs @@ -1,28 +1,28 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public class PasswordFieldWidget : TextFieldWidget - { - public PasswordFieldWidget() : base() {} - protected PasswordFieldWidget(PasswordFieldWidget widget) : base(widget) {} - - public override void DrawInner() - { - DrawWithString(new string('*', Text.Length)); - } - public override Widget Clone() { return new PasswordFieldWidget(this); } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public class PasswordFieldWidget : TextFieldWidget + { + public PasswordFieldWidget() : base() {} + protected PasswordFieldWidget(PasswordFieldWidget widget) : base(widget) {} + + public override void DrawInner() + { + DrawWithString(new string('*', Text.Length)); + } + public override Widget Clone() { return new PasswordFieldWidget(this); } + } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/PerfGraphWidget.cs b/OpenRA.Game/Widgets/PerfGraphWidget.cs index 0560b37e0d..4e9643dbab 100644 --- a/OpenRA.Game/Widgets/PerfGraphWidget.cs +++ b/OpenRA.Game/Widgets/PerfGraphWidget.cs @@ -1,63 +1,63 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Support; - -namespace OpenRA.Widgets -{ - public class PerfGraphWidget : Widget - { - public PerfGraphWidget() : base() { } - - public override void DrawInner() - { - var rect = RenderBounds; - float2 origin = Game.viewport.Location + new float2(rect.Right, rect.Bottom); - float2 basis = new float2(-rect.Width / 100, -rect.Height / 100); - - Game.Renderer.LineRenderer.DrawLine(origin, origin + new float2(100, 0) * basis, Color.White, Color.White); - Game.Renderer.LineRenderer.DrawLine(origin + new float2(100, 0) * basis, origin + new float2(100, 100) * basis, Color.White, Color.White); - - int k = 0; - foreach (var item in PerfHistory.items.Values) - { - int n = 0; - item.Samples().Aggregate((a, b) => - { - Game.Renderer.LineRenderer.DrawLine( - origin + new float2(n, (float)a) * basis, - origin + new float2(n + 1, (float)b) * basis, - item.c, item.c); - ++n; - return b; - }); - - var u = Game.viewport.Location + new float2(rect.Left, rect.Top); - - Game.Renderer.LineRenderer.DrawLine( - u + new float2(10, 10 * k + 5), - u + new float2(12, 10 * k + 5), - item.c, item.c); - - Game.Renderer.LineRenderer.DrawLine( - u + new float2(10, 10 * k + 4), - u + new float2(12, 10 * k + 4), - item.c, item.c); - - Game.Renderer.TinyFont.DrawText(item.Name, new float2(rect.Left, rect.Top) + new float2(18, 10 * k - 3), Color.White); - Game.Renderer.Flush(); - ++k; - } - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Support; + +namespace OpenRA.Widgets +{ + public class PerfGraphWidget : Widget + { + public PerfGraphWidget() : base() { } + + public override void DrawInner() + { + var rect = RenderBounds; + float2 origin = Game.viewport.Location + new float2(rect.Right, rect.Bottom); + float2 basis = new float2(-rect.Width / 100, -rect.Height / 100); + + Game.Renderer.LineRenderer.DrawLine(origin, origin + new float2(100, 0) * basis, Color.White, Color.White); + Game.Renderer.LineRenderer.DrawLine(origin + new float2(100, 0) * basis, origin + new float2(100, 100) * basis, Color.White, Color.White); + + int k = 0; + foreach (var item in PerfHistory.items.Values) + { + int n = 0; + item.Samples().Aggregate((a, b) => + { + Game.Renderer.LineRenderer.DrawLine( + origin + new float2(n, (float)a) * basis, + origin + new float2(n + 1, (float)b) * basis, + item.c, item.c); + ++n; + return b; + }); + + var u = Game.viewport.Location + new float2(rect.Left, rect.Top); + + Game.Renderer.LineRenderer.DrawLine( + u + new float2(10, 10 * k + 5), + u + new float2(12, 10 * k + 5), + item.c, item.c); + + Game.Renderer.LineRenderer.DrawLine( + u + new float2(10, 10 * k + 4), + u + new float2(12, 10 * k + 4), + item.c, item.c); + + Game.Renderer.TinyFont.DrawText(item.Name, new float2(rect.Left, rect.Top) + new float2(18, 10 * k - 3), Color.White); + Game.Renderer.Flush(); + ++k; + } + } + } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/ProgressBarWidget.cs b/OpenRA.Game/Widgets/ProgressBarWidget.cs index ed462c5ef6..9ee01850d6 100644 --- a/OpenRA.Game/Widgets/ProgressBarWidget.cs +++ b/OpenRA.Game/Widgets/ProgressBarWidget.cs @@ -1,50 +1,50 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.Graphics; -using System.Collections.Generic; - -namespace OpenRA.Widgets -{ - public class ProgressBarWidget : Widget - { - public int Percentage = 0; - public bool Indeterminate = false; - int indeterminateTick = 0; - - public ProgressBarWidget() : base() {} - protected ProgressBarWidget(ProgressBarWidget widget) - : base(widget) - { - Percentage = widget.Percentage; - } - - public override void DrawInner() - { - WidgetUtils.DrawPanel("dialog3", RenderBounds); - Rectangle barRect = Indeterminate ? - new Rectangle(RenderBounds.X + 2 + (int)((RenderBounds.Width - 4)*(-Math.Cos(Math.PI*2*indeterminateTick/100) + 1)*3/8), RenderBounds.Y + 2, (RenderBounds.Width - 4) / 4, RenderBounds.Height - 4) : - new Rectangle(RenderBounds.X + 2, RenderBounds.Y + 2, Percentage * (RenderBounds.Width - 4) / 100, RenderBounds.Height - 4); - - if (barRect.Width > 0) - WidgetUtils.DrawPanel("dialog2", barRect); - } - - public override void Tick() - { - if (Indeterminate && indeterminateTick++ >= 100) - indeterminateTick = 0; - } - - public override Widget Clone() { return new ProgressBarWidget(this); } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.Graphics; +using System.Collections.Generic; + +namespace OpenRA.Widgets +{ + public class ProgressBarWidget : Widget + { + public int Percentage = 0; + public bool Indeterminate = false; + int indeterminateTick = 0; + + public ProgressBarWidget() : base() {} + protected ProgressBarWidget(ProgressBarWidget widget) + : base(widget) + { + Percentage = widget.Percentage; + } + + public override void DrawInner() + { + WidgetUtils.DrawPanel("dialog3", RenderBounds); + Rectangle barRect = Indeterminate ? + new Rectangle(RenderBounds.X + 2 + (int)((RenderBounds.Width - 4)*(-Math.Cos(Math.PI*2*indeterminateTick/100) + 1)*3/8), RenderBounds.Y + 2, (RenderBounds.Width - 4) / 4, RenderBounds.Height - 4) : + new Rectangle(RenderBounds.X + 2, RenderBounds.Y + 2, Percentage * (RenderBounds.Width - 4) / 100, RenderBounds.Height - 4); + + if (barRect.Width > 0) + WidgetUtils.DrawPanel("dialog2", barRect); + } + + public override void Tick() + { + if (Indeterminate && indeterminateTick++ >= 100) + indeterminateTick = 0; + } + + public override Widget Clone() { return new ProgressBarWidget(this); } + } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/ScrollPanelWidget.cs b/OpenRA.Game/Widgets/ScrollPanelWidget.cs index 16b1a0295e..6961aa91a5 100644 --- a/OpenRA.Game/Widgets/ScrollPanelWidget.cs +++ b/OpenRA.Game/Widgets/ScrollPanelWidget.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Game/Widgets/ScrollingTextWidget.cs b/OpenRA.Game/Widgets/ScrollingTextWidget.cs index 79212efa08..35234fb03f 100755 --- a/OpenRA.Game/Widgets/ScrollingTextWidget.cs +++ b/OpenRA.Game/Widgets/ScrollingTextWidget.cs @@ -1,126 +1,126 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public class ScrollingTextWidget : Widget - { - public string Text = ""; - private string ScrollingText = ""; - - public string Background = null; - - public bool Bold = false; - - public int ScrollLength = 200; - - // ticks per single letter scroll - public int ScrollRate = 4; - - private string ScrollBuffer = ""; - - private int ScrollLocation = 0; - private int ScrollTick = 0; - - public Func GetText; - public Func GetBackground; - - public ScrollingTextWidget() - : base() - { - GetText = () => Text; - GetBackground = () => Background; - } - - protected ScrollingTextWidget(ScrollingTextWidget other) - : base(other) - { - Text = other.Text; - GetText = other.GetText; - Bold = other.Bold; - GetBackground = other.GetBackground; - } - - public override void Tick() - { - if (Text != "") - { - ScrollingText = Text; - Text = ""; - } - UpdateScrollBuffer(); - } - - public void ResetScroll() - { - ScrollLocation = 0; - ScrollTick = 0; - } - - private void UpdateScrollBuffer() - { - ScrollTick++; - - if (ScrollTick < ScrollRate) - { - return; - } - - ScrollTick = 0; - ScrollBuffer = ""; - - if (ScrollingText.Substring(ScrollingText.Length - 4, 3) != " ") - { - ScrollingText += " "; - } - - int tempScrollLocation = ScrollLocation; - for (int i = 0; i < ScrollLength; ++i) - { - ScrollBuffer += ScrollingText.Substring(tempScrollLocation, 1); - tempScrollLocation = (tempScrollLocation + 1) % ScrollingText.Length; - } - - ScrollLocation = (ScrollLocation + 1) % ScrollingText.Length; - } - - public void SetText(string newText) - { - Text = newText.Replace("\n", " "); - Text = Text.Replace("\r", ""); - } - - public override void DrawInner() - { - var bg = GetBackground(); - - if (bg != null) - WidgetUtils.DrawPanel(bg, RenderBounds); - - var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; - var text = GetText(); - if (text == null) - return; - - int2 textSize = font.Measure(text); - int2 position = RenderOrigin + new int2(0, (Bounds.Height - textSize.Y) / 2); - - Game.Renderer.EnableScissor(position.X, position.Y, Bounds.Width, Bounds.Height); - font.DrawText(ScrollBuffer, position, Color.White); - Game.Renderer.DisableScissor(); - } - - public override Widget Clone() { return new ScrollingTextWidget(this); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public class ScrollingTextWidget : Widget + { + public string Text = ""; + private string ScrollingText = ""; + + public string Background = null; + + public bool Bold = false; + + public int ScrollLength = 200; + + // ticks per single letter scroll + public int ScrollRate = 4; + + private string ScrollBuffer = ""; + + private int ScrollLocation = 0; + private int ScrollTick = 0; + + public Func GetText; + public Func GetBackground; + + public ScrollingTextWidget() + : base() + { + GetText = () => Text; + GetBackground = () => Background; + } + + protected ScrollingTextWidget(ScrollingTextWidget other) + : base(other) + { + Text = other.Text; + GetText = other.GetText; + Bold = other.Bold; + GetBackground = other.GetBackground; + } + + public override void Tick() + { + if (Text != "") + { + ScrollingText = Text; + Text = ""; + } + UpdateScrollBuffer(); + } + + public void ResetScroll() + { + ScrollLocation = 0; + ScrollTick = 0; + } + + private void UpdateScrollBuffer() + { + ScrollTick++; + + if (ScrollTick < ScrollRate) + { + return; + } + + ScrollTick = 0; + ScrollBuffer = ""; + + if (ScrollingText.Substring(ScrollingText.Length - 4, 3) != " ") + { + ScrollingText += " "; + } + + int tempScrollLocation = ScrollLocation; + for (int i = 0; i < ScrollLength; ++i) + { + ScrollBuffer += ScrollingText.Substring(tempScrollLocation, 1); + tempScrollLocation = (tempScrollLocation + 1) % ScrollingText.Length; + } + + ScrollLocation = (ScrollLocation + 1) % ScrollingText.Length; + } + + public void SetText(string newText) + { + Text = newText.Replace("\n", " "); + Text = Text.Replace("\r", ""); + } + + public override void DrawInner() + { + var bg = GetBackground(); + + if (bg != null) + WidgetUtils.DrawPanel(bg, RenderBounds); + + var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; + var text = GetText(); + if (text == null) + return; + + int2 textSize = font.Measure(text); + int2 position = RenderOrigin + new int2(0, (Bounds.Height - textSize.Y) / 2); + + Game.Renderer.EnableScissor(position.X, position.Y, Bounds.Width, Bounds.Height); + font.DrawText(ScrollBuffer, position, Color.White); + Game.Renderer.DisableScissor(); + } + + public override Widget Clone() { return new ScrollingTextWidget(this); } + } +} diff --git a/OpenRA.Game/Widgets/ShpImageWidget.cs b/OpenRA.Game/Widgets/ShpImageWidget.cs index ddd56c32c8..216aaf4217 100644 --- a/OpenRA.Game/Widgets/ShpImageWidget.cs +++ b/OpenRA.Game/Widgets/ShpImageWidget.cs @@ -1,11 +1,11 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ #endregion using System; @@ -22,15 +22,15 @@ namespace OpenRA.Widgets public Func GetImage; public Func GetFrame; public Func GetPalette; - - readonly WorldRenderer worldRenderer; - [ObjectCreator.UseCtor] + + readonly WorldRenderer worldRenderer; + [ObjectCreator.UseCtor] public ShpImageWidget([ObjectCreator.Param] WorldRenderer worldRenderer) : base() { GetImage = () => { return Image; }; GetFrame = () => { return Frame; }; - GetPalette = () => { return Palette; }; + GetPalette = () => { return Palette; }; this.worldRenderer = worldRenderer; } @@ -42,7 +42,7 @@ namespace OpenRA.Widgets Palette = other.Palette; GetImage = other.GetImage; GetFrame = other.GetFrame; - GetPalette = other.GetPalette; + GetPalette = other.GetPalette; worldRenderer = other.worldRenderer; } diff --git a/OpenRA.Game/Widgets/SliderWidget.cs b/OpenRA.Game/Widgets/SliderWidget.cs index 91e4aaf66d..9984083401 100755 --- a/OpenRA.Game/Widgets/SliderWidget.cs +++ b/OpenRA.Game/Widgets/SliderWidget.cs @@ -1,197 +1,197 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public class SliderWidget : Widget - { - public event Action OnChange; - public Func GetOffset; - public int Ticks = 0; - public int TrackHeight = 5; - public float2 Range = new float2(0f, 1f); - - private float Offset = 0; - - int2 lastMouseLocation; - bool isMoving = false; - - public SliderWidget() - : base() - { - GetOffset = () => - { - var Big = Math.Max(Range.X, Range.Y); - var Little = Math.Min(Range.X, Range.Y); - var Spread = Big - Little; - - return Spread * Offset + Little; - }; - OnChange = x => Offset = x.Clamp(0f, 1f); - } - - public SliderWidget(SliderWidget other) - : base(other) - { - OnChange = other.OnChange; - GetOffset = other.GetOffset; - Ticks = other.Ticks; - Range = other.Range; - Offset = GetOffset(); - TrackHeight = other.TrackHeight; - lastMouseLocation = other.lastMouseLocation; - isMoving = other.isMoving; - } - - public void SetOffset(float newOffset) - { - var Big = Math.Max(Range.X, Range.Y); - var Little = Math.Min(Range.X, Range.Y); - var Spread = Big - Little; - - Offset = ((newOffset - Little) / Spread).Clamp(0f, 1f); - } - - // TODO: SliderWidget doesn't support delegate methods for mouse input - public override bool HandleMouseInput(MouseInput mi) - { - if (mi.Button != MouseButton.Left) - return false; - - if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) - return false; - - if (!Focused) - return false; - - switch (mi.Event) - { - case MouseInputEvent.Up: - { - if (Focused) - { - isMoving = false; - base.LoseFocus(mi); - } - } - break; - - case MouseInputEvent.Down: - { - if (thumbRect.Contains(mi.Location)) - { - isMoving = true; - lastMouseLocation = mi.Location; - } - else if (Ticks != 0) - { - var pos = Offset; - - // Offset slightly the direction we want to move so we don't get stuck on a tick - var delta = 0.001; - var targetTick = (float)((mi.Location.X > thumbRect.Right) ? Math.Ceiling((pos + delta) * (Ticks - 1)) - : Math.Floor((pos - delta) * (Ticks - 1))); - OnChange(targetTick / (Ticks - 1)); - - if (thumbRect.Contains(mi.Location)) - { - isMoving = true; - lastMouseLocation = mi.Location; - } - return true; - } - else // No ticks; move to the mouse position - { - var thumb = thumbRect; - var center = thumb.X + thumb.Width / 2; - var newOffset = OffsetBy((mi.Location.X - center) * 1f / (RenderBounds.Width - thumb.Width)); - if (newOffset != Offset) - { - OnChange(newOffset); - - if (thumbRect.Contains(mi.Location)) - { - isMoving = true; - lastMouseLocation = mi.Location; - } - return true; - } - } - } - break; - - case MouseInputEvent.Move: - { - if ((mi.Location.X != lastMouseLocation.X) && isMoving) - { - var newOffset = OffsetBy((mi.Location.X - lastMouseLocation.X) * 1f / (RenderBounds.Width - thumbRect.Width)); - if (newOffset != Offset) - { - lastMouseLocation = mi.Location; - OnChange(newOffset); - } - } - } - break; - } - - return thumbRect.Contains(mi.Location.X, mi.Location.Y); - } - - float OffsetBy(float amount) - { - var centerPos = Offset + amount; - if (centerPos < 0) centerPos = 0; - if (centerPos > 1) centerPos = 1; - return centerPos; - } - - public override Widget Clone() { return new SliderWidget(this); } - - Rectangle thumbRect - { - get - { - var width = RenderBounds.Height; - var height = RenderBounds.Height; - var origin = (int)((RenderBounds.X + width / 2) + Offset * (RenderBounds.Width - width) - width / 2f); - return new Rectangle(origin, RenderBounds.Y, width, height); - } - } - - public override void DrawInner() - { - if (!IsVisible()) - return; - - var trackWidth = RenderBounds.Width - thumbRect.Width; - var trackOrigin = RenderBounds.X + thumbRect.Width / 2; - var trackRect = new Rectangle(trackOrigin - 1, RenderBounds.Y + (RenderBounds.Height - TrackHeight) / 2, trackWidth + 2, TrackHeight); - - // Tickmarks (hacked until we have real art) - for (int i = 0; i < Ticks; i++) - { - var tickRect = new Rectangle(trackOrigin - 1 + (int)(i * trackWidth * 1f / (Ticks - 1)), - RenderBounds.Y + RenderBounds.Height / 2, 2, RenderBounds.Height / 2); - WidgetUtils.DrawPanel("dialog2", tickRect); - } - // Track - WidgetUtils.DrawPanel("dialog3", trackRect); - - // Thumb - WidgetUtils.DrawPanel("dialog2", thumbRect); - } - } -} - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public class SliderWidget : Widget + { + public event Action OnChange; + public Func GetOffset; + public int Ticks = 0; + public int TrackHeight = 5; + public float2 Range = new float2(0f, 1f); + + private float Offset = 0; + + int2 lastMouseLocation; + bool isMoving = false; + + public SliderWidget() + : base() + { + GetOffset = () => + { + var Big = Math.Max(Range.X, Range.Y); + var Little = Math.Min(Range.X, Range.Y); + var Spread = Big - Little; + + return Spread * Offset + Little; + }; + OnChange = x => Offset = x.Clamp(0f, 1f); + } + + public SliderWidget(SliderWidget other) + : base(other) + { + OnChange = other.OnChange; + GetOffset = other.GetOffset; + Ticks = other.Ticks; + Range = other.Range; + Offset = GetOffset(); + TrackHeight = other.TrackHeight; + lastMouseLocation = other.lastMouseLocation; + isMoving = other.isMoving; + } + + public void SetOffset(float newOffset) + { + var Big = Math.Max(Range.X, Range.Y); + var Little = Math.Min(Range.X, Range.Y); + var Spread = Big - Little; + + Offset = ((newOffset - Little) / Spread).Clamp(0f, 1f); + } + + // TODO: SliderWidget doesn't support delegate methods for mouse input + public override bool HandleMouseInput(MouseInput mi) + { + if (mi.Button != MouseButton.Left) + return false; + + if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) + return false; + + if (!Focused) + return false; + + switch (mi.Event) + { + case MouseInputEvent.Up: + { + if (Focused) + { + isMoving = false; + base.LoseFocus(mi); + } + } + break; + + case MouseInputEvent.Down: + { + if (thumbRect.Contains(mi.Location)) + { + isMoving = true; + lastMouseLocation = mi.Location; + } + else if (Ticks != 0) + { + var pos = Offset; + + // Offset slightly the direction we want to move so we don't get stuck on a tick + var delta = 0.001; + var targetTick = (float)((mi.Location.X > thumbRect.Right) ? Math.Ceiling((pos + delta) * (Ticks - 1)) + : Math.Floor((pos - delta) * (Ticks - 1))); + OnChange(targetTick / (Ticks - 1)); + + if (thumbRect.Contains(mi.Location)) + { + isMoving = true; + lastMouseLocation = mi.Location; + } + return true; + } + else // No ticks; move to the mouse position + { + var thumb = thumbRect; + var center = thumb.X + thumb.Width / 2; + var newOffset = OffsetBy((mi.Location.X - center) * 1f / (RenderBounds.Width - thumb.Width)); + if (newOffset != Offset) + { + OnChange(newOffset); + + if (thumbRect.Contains(mi.Location)) + { + isMoving = true; + lastMouseLocation = mi.Location; + } + return true; + } + } + } + break; + + case MouseInputEvent.Move: + { + if ((mi.Location.X != lastMouseLocation.X) && isMoving) + { + var newOffset = OffsetBy((mi.Location.X - lastMouseLocation.X) * 1f / (RenderBounds.Width - thumbRect.Width)); + if (newOffset != Offset) + { + lastMouseLocation = mi.Location; + OnChange(newOffset); + } + } + } + break; + } + + return thumbRect.Contains(mi.Location.X, mi.Location.Y); + } + + float OffsetBy(float amount) + { + var centerPos = Offset + amount; + if (centerPos < 0) centerPos = 0; + if (centerPos > 1) centerPos = 1; + return centerPos; + } + + public override Widget Clone() { return new SliderWidget(this); } + + Rectangle thumbRect + { + get + { + var width = RenderBounds.Height; + var height = RenderBounds.Height; + var origin = (int)((RenderBounds.X + width / 2) + Offset * (RenderBounds.Width - width) - width / 2f); + return new Rectangle(origin, RenderBounds.Y, width, height); + } + } + + public override void DrawInner() + { + if (!IsVisible()) + return; + + var trackWidth = RenderBounds.Width - thumbRect.Width; + var trackOrigin = RenderBounds.X + thumbRect.Width / 2; + var trackRect = new Rectangle(trackOrigin - 1, RenderBounds.Y + (RenderBounds.Height - TrackHeight) / 2, trackWidth + 2, TrackHeight); + + // Tickmarks (hacked until we have real art) + for (int i = 0; i < Ticks; i++) + { + var tickRect = new Rectangle(trackOrigin - 1 + (int)(i * trackWidth * 1f / (Ticks - 1)), + RenderBounds.Y + RenderBounds.Height / 2, 2, RenderBounds.Height / 2); + WidgetUtils.DrawPanel("dialog2", tickRect); + } + // Track + WidgetUtils.DrawPanel("dialog3", trackRect); + + // Thumb + WidgetUtils.DrawPanel("dialog2", thumbRect); + } + } +} + diff --git a/OpenRA.Game/Widgets/TextFieldWidget.cs b/OpenRA.Game/Widgets/TextFieldWidget.cs index 7486f3c725..72a4eb1921 100644 --- a/OpenRA.Game/Widgets/TextFieldWidget.cs +++ b/OpenRA.Game/Widgets/TextFieldWidget.cs @@ -1,211 +1,211 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public class TextFieldWidget : Widget - { - public string Text = ""; - public int MaxLength = 0; - public bool Bold = false; - public int VisualHeight = 1; - public Func OnEnterKey = () => false; - public Func OnTabKey = () => false; - public Action OnLoseFocus = () => { }; - public int CursorPosition { get; protected set; } - - public TextFieldWidget() : base() {} - protected TextFieldWidget(TextFieldWidget widget) - : base(widget) - { - Text = widget.Text; - MaxLength = widget.MaxLength; - Bold = widget.Bold; - VisualHeight = widget.VisualHeight; - } - - public override bool LoseFocus(MouseInput mi) - { - OnLoseFocus(); - var lose = base.LoseFocus(mi); - return lose; - } - - // TODO: TextFieldWidgets don't support delegate methods for mouse input - public override bool HandleMouseInput(MouseInput mi) - { - if (mi.Event == MouseInputEvent.Move) - return false; - - // Lose focus if they click outside the box; return false so the next widget can grab this event - if (mi.Event == MouseInputEvent.Down && !RenderBounds.Contains(mi.Location) && LoseFocus(mi)) - return false; - - if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) - return false; - - blinkCycle = 10; - showCursor = true; - CursorPosition = ClosestCursorPosition(mi.Location.X); - return true; - } - - - public int ClosestCursorPosition(int x) - { - var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; - var textSize = font.Measure(Text); - - var start = RenderOrigin.X + margin; - if (textSize.X > Bounds.Width - 2 * margin && Focused) - start += Bounds.Width - 2 * margin - textSize.X; - - int minIndex = -1; - int minValue = int.MaxValue; - for (int i = 0; i <= Text.Length; i++) - { - var dist = Math.Abs(start + font.Measure(Text.Substring(0,i)).X - x); - if (dist > minValue) - break; - minValue = dist; - minIndex = i; - } - return minIndex; - } - - public override bool HandleKeyPressInner(KeyInput e) - { - if (e.Event == KeyInputEvent.Up) return false; - - // Only take input if we are focused - if (!Focused) - return false; - - if (e.KeyChar == '\r' && OnEnterKey()) - return true; - - if (e.KeyChar == '\t' && OnTabKey()) - return true; - - if (e.KeyName == "left") - { - if (CursorPosition > 0) - CursorPosition--; - - return true; - } - - if (e.KeyName == "right") - { - if (CursorPosition <= Text.Length-1) - CursorPosition++; - - return true; - } - - if (e.KeyName == "delete") - { - if (Text.Length > 0 && CursorPosition < Text.Length) - { - Text = Text.Remove(CursorPosition, 1); - } - return true; - } - - TypeChar(e.KeyChar); - return true; - } - - public void TypeChar(char c) - { - // backspace - if (c == '\b' || c == 0x7f) - { - if (Text.Length > 0 && CursorPosition > 0) - { - Text = Text.Remove(CursorPosition - 1, 1); - - CursorPosition--; - } - } - else if (!char.IsControl(c)) - { - if (MaxLength > 0 && Text.Length >= MaxLength) - return; - - Text = Text.Insert(CursorPosition, c.ToString()); - - CursorPosition++; - } - } - - protected int blinkCycle = 10; - protected bool showCursor = true; - public override void Tick() - { - if (--blinkCycle <= 0) - { - blinkCycle = 20; - showCursor ^= true; - } - - base.Tick(); - } - - int margin = 5; - public virtual void DrawWithString(string text) - { - if (text == null) text = ""; - - var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; - var pos = RenderOrigin; - - if (CursorPosition > text.Length) - CursorPosition = text.Length; - - var textSize = font.Measure(text); - var cursorPosition = font.Measure(text.Substring(0,CursorPosition)); - - WidgetUtils.DrawPanel("dialog3", - new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height)); - - // Inset text by the margin and center vertically - var textPos = pos + new int2(margin, (Bounds.Height - textSize.Y) / 2 - VisualHeight); - - // Right align when editing and scissor when the text overflows - if (textSize.X > Bounds.Width - 2 * margin) - { - if (Focused) - textPos += new int2(Bounds.Width - 2 * margin - textSize.X, 0); - - Game.Renderer.EnableScissor(pos.X + margin, pos.Y, Bounds.Width - 2 * margin, Bounds.Bottom); - } - - font.DrawText(text, textPos, Color.White); - - if (showCursor && Focused) - font.DrawText("|", new float2(textPos.X + cursorPosition.X - 2, textPos.Y), Color.White); - - if (textSize.X > Bounds.Width - 2 * margin) - Game.Renderer.DisableScissor(); - } - - public override void DrawInner() - { - DrawWithString(Text); - } - - public override Widget Clone() { return new TextFieldWidget(this); } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public class TextFieldWidget : Widget + { + public string Text = ""; + public int MaxLength = 0; + public bool Bold = false; + public int VisualHeight = 1; + public Func OnEnterKey = () => false; + public Func OnTabKey = () => false; + public Action OnLoseFocus = () => { }; + public int CursorPosition { get; protected set; } + + public TextFieldWidget() : base() {} + protected TextFieldWidget(TextFieldWidget widget) + : base(widget) + { + Text = widget.Text; + MaxLength = widget.MaxLength; + Bold = widget.Bold; + VisualHeight = widget.VisualHeight; + } + + public override bool LoseFocus(MouseInput mi) + { + OnLoseFocus(); + var lose = base.LoseFocus(mi); + return lose; + } + + // TODO: TextFieldWidgets don't support delegate methods for mouse input + public override bool HandleMouseInput(MouseInput mi) + { + if (mi.Event == MouseInputEvent.Move) + return false; + + // Lose focus if they click outside the box; return false so the next widget can grab this event + if (mi.Event == MouseInputEvent.Down && !RenderBounds.Contains(mi.Location) && LoseFocus(mi)) + return false; + + if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) + return false; + + blinkCycle = 10; + showCursor = true; + CursorPosition = ClosestCursorPosition(mi.Location.X); + return true; + } + + + public int ClosestCursorPosition(int x) + { + var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; + var textSize = font.Measure(Text); + + var start = RenderOrigin.X + margin; + if (textSize.X > Bounds.Width - 2 * margin && Focused) + start += Bounds.Width - 2 * margin - textSize.X; + + int minIndex = -1; + int minValue = int.MaxValue; + for (int i = 0; i <= Text.Length; i++) + { + var dist = Math.Abs(start + font.Measure(Text.Substring(0,i)).X - x); + if (dist > minValue) + break; + minValue = dist; + minIndex = i; + } + return minIndex; + } + + public override bool HandleKeyPressInner(KeyInput e) + { + if (e.Event == KeyInputEvent.Up) return false; + + // Only take input if we are focused + if (!Focused) + return false; + + if (e.KeyChar == '\r' && OnEnterKey()) + return true; + + if (e.KeyChar == '\t' && OnTabKey()) + return true; + + if (e.KeyName == "left") + { + if (CursorPosition > 0) + CursorPosition--; + + return true; + } + + if (e.KeyName == "right") + { + if (CursorPosition <= Text.Length-1) + CursorPosition++; + + return true; + } + + if (e.KeyName == "delete") + { + if (Text.Length > 0 && CursorPosition < Text.Length) + { + Text = Text.Remove(CursorPosition, 1); + } + return true; + } + + TypeChar(e.KeyChar); + return true; + } + + public void TypeChar(char c) + { + // backspace + if (c == '\b' || c == 0x7f) + { + if (Text.Length > 0 && CursorPosition > 0) + { + Text = Text.Remove(CursorPosition - 1, 1); + + CursorPosition--; + } + } + else if (!char.IsControl(c)) + { + if (MaxLength > 0 && Text.Length >= MaxLength) + return; + + Text = Text.Insert(CursorPosition, c.ToString()); + + CursorPosition++; + } + } + + protected int blinkCycle = 10; + protected bool showCursor = true; + public override void Tick() + { + if (--blinkCycle <= 0) + { + blinkCycle = 20; + showCursor ^= true; + } + + base.Tick(); + } + + int margin = 5; + public virtual void DrawWithString(string text) + { + if (text == null) text = ""; + + var font = (Bold) ? Game.Renderer.BoldFont : Game.Renderer.RegularFont; + var pos = RenderOrigin; + + if (CursorPosition > text.Length) + CursorPosition = text.Length; + + var textSize = font.Measure(text); + var cursorPosition = font.Measure(text.Substring(0,CursorPosition)); + + WidgetUtils.DrawPanel("dialog3", + new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height)); + + // Inset text by the margin and center vertically + var textPos = pos + new int2(margin, (Bounds.Height - textSize.Y) / 2 - VisualHeight); + + // Right align when editing and scissor when the text overflows + if (textSize.X > Bounds.Width - 2 * margin) + { + if (Focused) + textPos += new int2(Bounds.Width - 2 * margin - textSize.X, 0); + + Game.Renderer.EnableScissor(pos.X + margin, pos.Y, Bounds.Width - 2 * margin, Bounds.Bottom); + } + + font.DrawText(text, textPos, Color.White); + + if (showCursor && Focused) + font.DrawText("|", new float2(textPos.X + cursorPosition.X - 2, textPos.Y), Color.White); + + if (textSize.X > Bounds.Width - 2 * margin) + Game.Renderer.DisableScissor(); + } + + public override void DrawInner() + { + DrawWithString(Text); + } + + public override Widget Clone() { return new TextFieldWidget(this); } + } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/TimerWidget.cs b/OpenRA.Game/Widgets/TimerWidget.cs index e066107d28..e4d4cff0a9 100644 --- a/OpenRA.Game/Widgets/TimerWidget.cs +++ b/OpenRA.Game/Widgets/TimerWidget.cs @@ -1,15 +1,15 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Drawing; -using OpenRA.Graphics; +#endregion + +using System.Drawing; +using OpenRA.Graphics; using OpenRA.Support; namespace OpenRA.Widgets @@ -26,10 +26,10 @@ namespace OpenRA.Widgets public override void DrawInner() { var s = WidgetUtils.FormatTime(Game.LocalTick); - var size = Game.Renderer.TitleFont.Measure(s); - var pos = new float2(RenderBounds.Left - size.X / 2, RenderBounds.Top - 20); - - Game.Renderer.TitleFont.DrawTextWithContrast(s, pos, Color.White, Color.Black, 1); + var size = Game.Renderer.TitleFont.Measure(s); + var pos = new float2(RenderBounds.Left - size.X / 2, RenderBounds.Top - 20); + + Game.Renderer.TitleFont.DrawTextWithContrast(s, pos, Color.White, Color.Black, 1); } } } diff --git a/OpenRA.Game/Widgets/ViewportScrollControllerWidget.cs b/OpenRA.Game/Widgets/ViewportScrollControllerWidget.cs index 6bbb9486ef..3e3f5af8f4 100755 --- a/OpenRA.Game/Widgets/ViewportScrollControllerWidget.cs +++ b/OpenRA.Game/Widgets/ViewportScrollControllerWidget.cs @@ -1,179 +1,179 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - [Flags] - public enum ScrollDirection - { - None = 0, - Up = 1, - Left = 2, - Down = 4, - Right = 8 - } - - public class ViewportScrollControllerWidget : Widget - { - public int EdgeScrollThreshold = 15; - - ScrollDirection Keyboard; - ScrollDirection Edge; - - public ViewportScrollControllerWidget() : base() { } - protected ViewportScrollControllerWidget(ViewportScrollControllerWidget widget) : base(widget) {} - public override void DrawInner() {} - - // TODO: ViewportScrollController doesn't support delegate methods for mouse input - public override bool HandleMouseInput(MouseInput mi) - { - if (mi.Event == MouseInputEvent.Move && - (mi.Button == MouseButton.Middle || mi.Button == (MouseButton.Left | MouseButton.Right))) - { - int InverseScroll = Game.Settings.Game.InverseDragScroll ? -1 : 1; - Game.viewport.Scroll((Viewport.LastMousePos - mi.Location) * InverseScroll); - return true; - } - return false; - } - - public override string GetCursor(int2 pos) - { - if (!Game.Settings.Game.ViewportEdgeScroll) - return null; - - if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Left)){ - ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections(); - if(BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Left)) - return "scroll-tl-blocked"; - else - return "scroll-tl"; - } - if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Right)){ - ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections(); - if (BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Right)) - return "scroll-tr-blocked"; - else - return "scroll-tr"; - } - if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Left)){ - ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections(); - if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Left)) - return "scroll-bl-blocked"; - else - return "scroll-bl"; - } - if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Right)){ - ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections(); - if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Right)) - return "scroll-br-blocked"; - else - return "scroll-br"; - } - - if (Edge.Includes(ScrollDirection.Up)) - if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Up)) - return "scroll-t-blocked"; - else - return "scroll-t"; - if (Edge.Includes(ScrollDirection.Down)) - if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Down)) - return "scroll-b-blocked"; - else - return "scroll-b"; - if (Edge.Includes(ScrollDirection.Left)) - if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Left)) - return "scroll-l-blocked"; - else - return "scroll-l"; - if (Edge.Includes(ScrollDirection.Right)) - if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Right)) - return "scroll-r-blocked"; - else - return "scroll-r"; - - return null; - } - - public override bool LoseFocus (MouseInput mi) - { - Keyboard = ScrollDirection.None; - return base.LoseFocus(mi); - } - - public override bool HandleKeyPressInner(KeyInput e) - { - switch (e.KeyName) - { - case "up": Keyboard = Keyboard.Set(ScrollDirection.Up, (e.Event == KeyInputEvent.Down)); return true; - case "down": Keyboard = Keyboard.Set(ScrollDirection.Down, (e.Event == KeyInputEvent.Down)); return true; - case "left": Keyboard = Keyboard.Set(ScrollDirection.Left, (e.Event == KeyInputEvent.Down)); return true; - case "right": Keyboard = Keyboard.Set(ScrollDirection.Right, (e.Event == KeyInputEvent.Down)); return true; - } - return false; - } - - public override void Tick() - { - Edge = ScrollDirection.None; - if (Game.Settings.Game.ViewportEdgeScroll && Game.HasInputFocus) - { - // Check for edge-scroll - if (Viewport.LastMousePos.X < EdgeScrollThreshold) - Edge = Edge.Set(ScrollDirection.Left, true); - if (Viewport.LastMousePos.Y < EdgeScrollThreshold) - Edge = Edge.Set(ScrollDirection.Up, true); - if (Viewport.LastMousePos.X >= Game.viewport.Width - EdgeScrollThreshold) - Edge = Edge.Set(ScrollDirection.Right, true); - if (Viewport.LastMousePos.Y >= Game.viewport.Height - EdgeScrollThreshold) - Edge = Edge.Set(ScrollDirection.Down, true); - } - - if(Keyboard != ScrollDirection.None || Edge != ScrollDirection.None) - { - var scroll = new float2(0, 0); - - // Modified to use the ViewportEdgeScrollStep setting - Gecko - if (Keyboard.Includes(ScrollDirection.Up) || Edge.Includes(ScrollDirection.Up)) - scroll += new float2(0, -1); - if (Keyboard.Includes(ScrollDirection.Right) || Edge.Includes(ScrollDirection.Right)) - scroll += new float2(1, 0); - if (Keyboard.Includes(ScrollDirection.Down) || Edge.Includes(ScrollDirection.Down)) - scroll += new float2(0, 1); - if (Keyboard.Includes(ScrollDirection.Left) || Edge.Includes(ScrollDirection.Left)) - scroll += new float2(-1, 0); - - float length = Math.Max(1, scroll.Length); - scroll.X = (scroll.X / length) * Game.Settings.Game.ViewportEdgeScrollStep; - scroll.Y = (scroll.Y / length) * Game.Settings.Game.ViewportEdgeScrollStep; - - Game.viewport.Scroll(scroll); - } - } - - public override Widget Clone() { return new ViewportScrollControllerWidget(this); } - } - - public static class ViewportExts - { - public static bool Includes(this ScrollDirection d, ScrollDirection s) - { - return (d & s) == s; - } - - public static ScrollDirection Set(this ScrollDirection d, ScrollDirection s, bool val) - { - return (d.Includes(s) != val) ? d ^ s : d; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + [Flags] + public enum ScrollDirection + { + None = 0, + Up = 1, + Left = 2, + Down = 4, + Right = 8 + } + + public class ViewportScrollControllerWidget : Widget + { + public int EdgeScrollThreshold = 15; + + ScrollDirection Keyboard; + ScrollDirection Edge; + + public ViewportScrollControllerWidget() : base() { } + protected ViewportScrollControllerWidget(ViewportScrollControllerWidget widget) : base(widget) {} + public override void DrawInner() {} + + // TODO: ViewportScrollController doesn't support delegate methods for mouse input + public override bool HandleMouseInput(MouseInput mi) + { + if (mi.Event == MouseInputEvent.Move && + (mi.Button == MouseButton.Middle || mi.Button == (MouseButton.Left | MouseButton.Right))) + { + int InverseScroll = Game.Settings.Game.InverseDragScroll ? -1 : 1; + Game.viewport.Scroll((Viewport.LastMousePos - mi.Location) * InverseScroll); + return true; + } + return false; + } + + public override string GetCursor(int2 pos) + { + if (!Game.Settings.Game.ViewportEdgeScroll) + return null; + + if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Left)){ + ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections(); + if(BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Left)) + return "scroll-tl-blocked"; + else + return "scroll-tl"; + } + if (Edge.Includes(ScrollDirection.Up) && Edge.Includes(ScrollDirection.Right)){ + ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections(); + if (BlockedDirections.Includes(ScrollDirection.Up) && BlockedDirections.Includes(ScrollDirection.Right)) + return "scroll-tr-blocked"; + else + return "scroll-tr"; + } + if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Left)){ + ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections(); + if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Left)) + return "scroll-bl-blocked"; + else + return "scroll-bl"; + } + if (Edge.Includes(ScrollDirection.Down) && Edge.Includes(ScrollDirection.Right)){ + ScrollDirection BlockedDirections = Game.viewport.GetBlockedDirections(); + if (BlockedDirections.Includes(ScrollDirection.Down) && BlockedDirections.Includes(ScrollDirection.Right)) + return "scroll-br-blocked"; + else + return "scroll-br"; + } + + if (Edge.Includes(ScrollDirection.Up)) + if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Up)) + return "scroll-t-blocked"; + else + return "scroll-t"; + if (Edge.Includes(ScrollDirection.Down)) + if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Down)) + return "scroll-b-blocked"; + else + return "scroll-b"; + if (Edge.Includes(ScrollDirection.Left)) + if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Left)) + return "scroll-l-blocked"; + else + return "scroll-l"; + if (Edge.Includes(ScrollDirection.Right)) + if (Game.viewport.GetBlockedDirections().Includes(ScrollDirection.Right)) + return "scroll-r-blocked"; + else + return "scroll-r"; + + return null; + } + + public override bool LoseFocus (MouseInput mi) + { + Keyboard = ScrollDirection.None; + return base.LoseFocus(mi); + } + + public override bool HandleKeyPressInner(KeyInput e) + { + switch (e.KeyName) + { + case "up": Keyboard = Keyboard.Set(ScrollDirection.Up, (e.Event == KeyInputEvent.Down)); return true; + case "down": Keyboard = Keyboard.Set(ScrollDirection.Down, (e.Event == KeyInputEvent.Down)); return true; + case "left": Keyboard = Keyboard.Set(ScrollDirection.Left, (e.Event == KeyInputEvent.Down)); return true; + case "right": Keyboard = Keyboard.Set(ScrollDirection.Right, (e.Event == KeyInputEvent.Down)); return true; + } + return false; + } + + public override void Tick() + { + Edge = ScrollDirection.None; + if (Game.Settings.Game.ViewportEdgeScroll && Game.HasInputFocus) + { + // Check for edge-scroll + if (Viewport.LastMousePos.X < EdgeScrollThreshold) + Edge = Edge.Set(ScrollDirection.Left, true); + if (Viewport.LastMousePos.Y < EdgeScrollThreshold) + Edge = Edge.Set(ScrollDirection.Up, true); + if (Viewport.LastMousePos.X >= Game.viewport.Width - EdgeScrollThreshold) + Edge = Edge.Set(ScrollDirection.Right, true); + if (Viewport.LastMousePos.Y >= Game.viewport.Height - EdgeScrollThreshold) + Edge = Edge.Set(ScrollDirection.Down, true); + } + + if(Keyboard != ScrollDirection.None || Edge != ScrollDirection.None) + { + var scroll = new float2(0, 0); + + // Modified to use the ViewportEdgeScrollStep setting - Gecko + if (Keyboard.Includes(ScrollDirection.Up) || Edge.Includes(ScrollDirection.Up)) + scroll += new float2(0, -1); + if (Keyboard.Includes(ScrollDirection.Right) || Edge.Includes(ScrollDirection.Right)) + scroll += new float2(1, 0); + if (Keyboard.Includes(ScrollDirection.Down) || Edge.Includes(ScrollDirection.Down)) + scroll += new float2(0, 1); + if (Keyboard.Includes(ScrollDirection.Left) || Edge.Includes(ScrollDirection.Left)) + scroll += new float2(-1, 0); + + float length = Math.Max(1, scroll.Length); + scroll.X = (scroll.X / length) * Game.Settings.Game.ViewportEdgeScrollStep; + scroll.Y = (scroll.Y / length) * Game.Settings.Game.ViewportEdgeScrollStep; + + Game.viewport.Scroll(scroll); + } + } + + public override Widget Clone() { return new ViewportScrollControllerWidget(this); } + } + + public static class ViewportExts + { + public static bool Includes(this ScrollDirection d, ScrollDirection s) + { + return (d & s) == s; + } + + public static ScrollDirection Set(this ScrollDirection d, ScrollDirection s, bool val) + { + return (d.Includes(s) != val) ? d ^ s : d; + } + } +} diff --git a/OpenRA.Game/Widgets/VqaPlayerWidget.cs b/OpenRA.Game/Widgets/VqaPlayerWidget.cs index 430aa40bbb..981b5861ae 100644 --- a/OpenRA.Game/Widgets/VqaPlayerWidget.cs +++ b/OpenRA.Game/Widgets/VqaPlayerWidget.cs @@ -1,18 +1,18 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion using System; using System.Drawing; using OpenRA.FileFormats; -using OpenRA.Graphics; - +using OpenRA.Graphics; + namespace OpenRA.Widgets { public class VqaPlayerWidget : Widget diff --git a/OpenRA.Game/Widgets/Widget.cs b/OpenRA.Game/Widgets/Widget.cs index d283c1f2fa..0ae6616be3 100644 --- a/OpenRA.Game/Widgets/Widget.cs +++ b/OpenRA.Game/Widgets/Widget.cs @@ -1,368 +1,368 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public abstract class Widget - { - // Info defined in YAML - public string Id = null; - public string X = "0"; - public string Y = "0"; - public string Width = "0"; - public string Height = "0"; - public string Delegate = null; - public string EventHandler = null; - public bool Visible = true; - - public readonly List Children = new List(); - - // Calculated internally - public Rectangle Bounds; - public Widget Parent = null; - - public static Stack WindowList = new Stack(); - - // Common Funcs that most widgets will want - public Func OnMouseDown = mi => false; - public Func OnMouseUp = mi => false; - public Action OnMouseMove = mi => {}; - public Func OnKeyPress = e => false; - - public Func IsVisible; - - public Widget() { IsVisible = () => Visible; } - - public static Widget RootWidget - { - get { return rootWidget; } - set { rootWidget = value; } - } - private static Widget rootWidget = new ContainerWidget(); - - public Widget(Widget widget) - { - Id = widget.Id; - X = widget.X; - Y = widget.Y; - Width = widget.Width; - Height = widget.Height; - Delegate = widget.Delegate; - Visible = widget.Visible; - - Bounds = widget.Bounds; - Parent = widget.Parent; - - OnMouseDown = widget.OnMouseDown; - OnMouseUp = widget.OnMouseUp; - OnMouseMove = widget.OnMouseMove; - OnKeyPress = widget.OnKeyPress; - - IsVisible = widget.IsVisible; - - foreach(var child in widget.Children) - AddChild(child.Clone()); - } - - public virtual Widget Clone() - { - throw new InvalidOperationException("Widget type `{0}` is not cloneable.".F(GetType().Name)); - } - - public virtual int2 RenderOrigin - { - get - { - var offset = (Parent == null) ? int2.Zero : Parent.ChildOrigin; - return new int2(Bounds.X, Bounds.Y) + offset; - } - } - - public virtual int2 ChildOrigin { get { return RenderOrigin; } } - public virtual Rectangle RenderBounds { get { return new Rectangle(RenderOrigin.X, RenderOrigin.Y, Bounds.Width, Bounds.Height); } } - - public virtual void Initialize() - { - // Parse the YAML equations to find the widget bounds - var parentBounds = (Parent == null) - ? new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height) - : Parent.Bounds; - - var substitutions = new Dictionary(); - substitutions.Add("WINDOW_RIGHT", Game.viewport.Width); - substitutions.Add("WINDOW_BOTTOM", Game.viewport.Height); - substitutions.Add("PARENT_RIGHT", parentBounds.Width); - substitutions.Add("PARENT_LEFT", parentBounds.Left); - substitutions.Add("PARENT_TOP", parentBounds.Top); - substitutions.Add("PARENT_BOTTOM", parentBounds.Height); - int width = Evaluator.Evaluate(Width, substitutions); - int height = Evaluator.Evaluate(Height, substitutions); - - substitutions.Add("WIDTH", width); - substitutions.Add("HEIGHT", height); - - Bounds = new Rectangle(Evaluator.Evaluate(X, substitutions), - Evaluator.Evaluate(Y, substitutions), - width, - height); - } - - public void PostInit(Dictionary args) - { - if( Delegate != null ) - { - args["widget"] = this; - Game.modData.ObjectCreator.CreateObject(Delegate, args); - args.Remove("widget"); - } - } - - public virtual Rectangle EventBounds { get { return RenderBounds; } } - public virtual Rectangle GetEventBounds() - { - return Children - .Where(c => c.IsVisible()) - .Select(c => c.GetEventBounds()) - .Aggregate(EventBounds, Rectangle.Union); - } - - public static Widget SelectedWidget; - public bool Focused { get { return SelectedWidget == this; } } - public virtual bool TakeFocus(MouseInput mi) - { - if (Focused) - return true; - - if (SelectedWidget != null && !SelectedWidget.LoseFocus(mi)) - return false; - SelectedWidget = this; - return true; - } - - // Remove focus from this widget; return false if you don't want to give it up - public virtual bool LoseFocus(MouseInput mi) - { - // Some widgets may need to override focus depending on mouse click - return LoseFocus(); - } - - public virtual bool LoseFocus() - { - if (SelectedWidget == this) - SelectedWidget = null; - - return true; - } - - public virtual string GetCursor(int2 pos) { return "default"; } - public string GetCursorOuter(int2 pos) - { - // Is the cursor on top of us? - if (!(IsVisible() && GetEventBounds().Contains(pos))) - return null; - - // Do any of our children specify a cursor? - foreach (var child in Children.OfType().Reverse()) - { - var cc = child.GetCursorOuter(pos); - if (cc != null) - return cc; - } - - return EventBounds.Contains(pos) ? GetCursor(pos) : null; - } - - public static bool HandleInput(MouseInput mi) - { - bool handled = false; - if (SelectedWidget != null && SelectedWidget.HandleMouseInputOuter(mi)) - handled = true; - - if (!handled && RootWidget.HandleMouseInputOuter(mi)) - handled = true; - - if (mi.Event == MouseInputEvent.Move) - { - Viewport.LastMousePos = mi.Location; - Viewport.TicksSinceLastMove = 0; - } - return handled; - } - - public bool HandleMouseInputOuter(MouseInput mi) - { - // Are we able to handle this event? - if (!(Focused || (IsVisible() && GetEventBounds().Contains(mi.Location.X,mi.Location.Y)))) - return false; - - // Send the event to the deepest children first and bubble up if unhandled - foreach (var child in Children.OfType().Reverse()) - if (child.HandleMouseInputOuter(mi)) - return true; - - return HandleMouseInput(mi); - } - - // Hack: Don't eat mouse input that others want - // TODO: Solve this properly - public virtual bool HandleMouseInput(MouseInput mi) - { - // Apply any special logic added by delegates; they return true if they caught the input - if (mi.Event == MouseInputEvent.Down && OnMouseDown(mi)) return true; - if (mi.Event == MouseInputEvent.Up && OnMouseUp(mi)) return true; - if (mi.Event == MouseInputEvent.Move) - OnMouseMove(mi); - - return false; - } - - public virtual bool HandleKeyPressInner(KeyInput e) { return false; } - public virtual bool HandleKeyPressOuter(KeyInput e) - { - if (!IsVisible()) - return false; - - // Can any of our children handle this? - foreach (var child in Children) - if (child.HandleKeyPressOuter(e)) - return true; - - // Do any widgety behavior (enter text etc) - var handled = HandleKeyPressInner(e); - - // Apply any special logic added by delegates; they return true if they caught the input - if (OnKeyPress(e)) return true; - - return handled; - } - - public static bool HandleKeyPress(KeyInput e) - { - if (SelectedWidget != null) - return SelectedWidget.HandleKeyPressOuter(e); - - if (RootWidget.HandleKeyPressOuter(e)) - return true; - return false; - } - - public abstract void DrawInner(); - - public virtual void Draw() - { - if (IsVisible()) - { - DrawInner(); - foreach (var child in Children) - child.Draw(); - } - } - - public virtual void Tick() - { - if (IsVisible()) - foreach (var child in Children) - child.Tick(); - } - - public virtual void AddChild(Widget child) - { - child.Parent = this; - Children.Add( child ); - } - public virtual void RemoveChild(Widget child) { Children.Remove(child); } - public virtual void RemoveChildren() { Children.Clear(); } - - public Widget GetWidget(string id) - { - if (this.Id == id) - return this; - - foreach (var child in Children) - { - var w = child.GetWidget(id); - if (w != null) - return w; - } - return null; - } - - public T GetWidget(string id) where T : Widget - { - var widget = GetWidget(id); - return (widget != null)? (T) widget : null; - } - - public static void CloseWindow() - { - RootWidget.Children.Remove( WindowList.Pop() ); - if( WindowList.Count > 0 ) - rootWidget.Children.Add( WindowList.Peek() ); - } - - public static Widget OpenWindow( string id ) - { - return OpenWindow( id, new Dictionary() ); - } - - public static Widget OpenWindow(string id, Dictionary args ) - { - var window = Game.modData.WidgetLoader.LoadWidget( args, rootWidget, id ); - if( WindowList.Count > 0 ) - rootWidget.Children.Remove( WindowList.Peek() ); - WindowList.Push( window ); - return window; - } - - public static void DoTick() - { - RootWidget.Tick(); - } - - public static void DoDraw() - { - RootWidget.Draw(); - } - } - - public class ContainerWidget : Widget { - public Func GetBackground; - public string Background = null; - - public ContainerWidget() : base() - { - GetBackground = () => Background; - } - - public ContainerWidget(ContainerWidget other) : base(other) - { - Background = other.Background; - GetBackground = other.GetBackground; - } - - public override void DrawInner() - { - var bg = GetBackground(); - if (bg != null) - WidgetUtils.DrawPanel(bg, RenderBounds ); - } - - public override string GetCursor(int2 pos) { return null; } - public override Widget Clone() { return new ContainerWidget(this); } - } - public interface IWidgetDelegate { } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public abstract class Widget + { + // Info defined in YAML + public string Id = null; + public string X = "0"; + public string Y = "0"; + public string Width = "0"; + public string Height = "0"; + public string Delegate = null; + public string EventHandler = null; + public bool Visible = true; + + public readonly List Children = new List(); + + // Calculated internally + public Rectangle Bounds; + public Widget Parent = null; + + public static Stack WindowList = new Stack(); + + // Common Funcs that most widgets will want + public Func OnMouseDown = mi => false; + public Func OnMouseUp = mi => false; + public Action OnMouseMove = mi => {}; + public Func OnKeyPress = e => false; + + public Func IsVisible; + + public Widget() { IsVisible = () => Visible; } + + public static Widget RootWidget + { + get { return rootWidget; } + set { rootWidget = value; } + } + private static Widget rootWidget = new ContainerWidget(); + + public Widget(Widget widget) + { + Id = widget.Id; + X = widget.X; + Y = widget.Y; + Width = widget.Width; + Height = widget.Height; + Delegate = widget.Delegate; + Visible = widget.Visible; + + Bounds = widget.Bounds; + Parent = widget.Parent; + + OnMouseDown = widget.OnMouseDown; + OnMouseUp = widget.OnMouseUp; + OnMouseMove = widget.OnMouseMove; + OnKeyPress = widget.OnKeyPress; + + IsVisible = widget.IsVisible; + + foreach(var child in widget.Children) + AddChild(child.Clone()); + } + + public virtual Widget Clone() + { + throw new InvalidOperationException("Widget type `{0}` is not cloneable.".F(GetType().Name)); + } + + public virtual int2 RenderOrigin + { + get + { + var offset = (Parent == null) ? int2.Zero : Parent.ChildOrigin; + return new int2(Bounds.X, Bounds.Y) + offset; + } + } + + public virtual int2 ChildOrigin { get { return RenderOrigin; } } + public virtual Rectangle RenderBounds { get { return new Rectangle(RenderOrigin.X, RenderOrigin.Y, Bounds.Width, Bounds.Height); } } + + public virtual void Initialize() + { + // Parse the YAML equations to find the widget bounds + var parentBounds = (Parent == null) + ? new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height) + : Parent.Bounds; + + var substitutions = new Dictionary(); + substitutions.Add("WINDOW_RIGHT", Game.viewport.Width); + substitutions.Add("WINDOW_BOTTOM", Game.viewport.Height); + substitutions.Add("PARENT_RIGHT", parentBounds.Width); + substitutions.Add("PARENT_LEFT", parentBounds.Left); + substitutions.Add("PARENT_TOP", parentBounds.Top); + substitutions.Add("PARENT_BOTTOM", parentBounds.Height); + int width = Evaluator.Evaluate(Width, substitutions); + int height = Evaluator.Evaluate(Height, substitutions); + + substitutions.Add("WIDTH", width); + substitutions.Add("HEIGHT", height); + + Bounds = new Rectangle(Evaluator.Evaluate(X, substitutions), + Evaluator.Evaluate(Y, substitutions), + width, + height); + } + + public void PostInit(Dictionary args) + { + if( Delegate != null ) + { + args["widget"] = this; + Game.modData.ObjectCreator.CreateObject(Delegate, args); + args.Remove("widget"); + } + } + + public virtual Rectangle EventBounds { get { return RenderBounds; } } + public virtual Rectangle GetEventBounds() + { + return Children + .Where(c => c.IsVisible()) + .Select(c => c.GetEventBounds()) + .Aggregate(EventBounds, Rectangle.Union); + } + + public static Widget SelectedWidget; + public bool Focused { get { return SelectedWidget == this; } } + public virtual bool TakeFocus(MouseInput mi) + { + if (Focused) + return true; + + if (SelectedWidget != null && !SelectedWidget.LoseFocus(mi)) + return false; + SelectedWidget = this; + return true; + } + + // Remove focus from this widget; return false if you don't want to give it up + public virtual bool LoseFocus(MouseInput mi) + { + // Some widgets may need to override focus depending on mouse click + return LoseFocus(); + } + + public virtual bool LoseFocus() + { + if (SelectedWidget == this) + SelectedWidget = null; + + return true; + } + + public virtual string GetCursor(int2 pos) { return "default"; } + public string GetCursorOuter(int2 pos) + { + // Is the cursor on top of us? + if (!(IsVisible() && GetEventBounds().Contains(pos))) + return null; + + // Do any of our children specify a cursor? + foreach (var child in Children.OfType().Reverse()) + { + var cc = child.GetCursorOuter(pos); + if (cc != null) + return cc; + } + + return EventBounds.Contains(pos) ? GetCursor(pos) : null; + } + + public static bool HandleInput(MouseInput mi) + { + bool handled = false; + if (SelectedWidget != null && SelectedWidget.HandleMouseInputOuter(mi)) + handled = true; + + if (!handled && RootWidget.HandleMouseInputOuter(mi)) + handled = true; + + if (mi.Event == MouseInputEvent.Move) + { + Viewport.LastMousePos = mi.Location; + Viewport.TicksSinceLastMove = 0; + } + return handled; + } + + public bool HandleMouseInputOuter(MouseInput mi) + { + // Are we able to handle this event? + if (!(Focused || (IsVisible() && GetEventBounds().Contains(mi.Location.X,mi.Location.Y)))) + return false; + + // Send the event to the deepest children first and bubble up if unhandled + foreach (var child in Children.OfType().Reverse()) + if (child.HandleMouseInputOuter(mi)) + return true; + + return HandleMouseInput(mi); + } + + // Hack: Don't eat mouse input that others want + // TODO: Solve this properly + public virtual bool HandleMouseInput(MouseInput mi) + { + // Apply any special logic added by delegates; they return true if they caught the input + if (mi.Event == MouseInputEvent.Down && OnMouseDown(mi)) return true; + if (mi.Event == MouseInputEvent.Up && OnMouseUp(mi)) return true; + if (mi.Event == MouseInputEvent.Move) + OnMouseMove(mi); + + return false; + } + + public virtual bool HandleKeyPressInner(KeyInput e) { return false; } + public virtual bool HandleKeyPressOuter(KeyInput e) + { + if (!IsVisible()) + return false; + + // Can any of our children handle this? + foreach (var child in Children) + if (child.HandleKeyPressOuter(e)) + return true; + + // Do any widgety behavior (enter text etc) + var handled = HandleKeyPressInner(e); + + // Apply any special logic added by delegates; they return true if they caught the input + if (OnKeyPress(e)) return true; + + return handled; + } + + public static bool HandleKeyPress(KeyInput e) + { + if (SelectedWidget != null) + return SelectedWidget.HandleKeyPressOuter(e); + + if (RootWidget.HandleKeyPressOuter(e)) + return true; + return false; + } + + public abstract void DrawInner(); + + public virtual void Draw() + { + if (IsVisible()) + { + DrawInner(); + foreach (var child in Children) + child.Draw(); + } + } + + public virtual void Tick() + { + if (IsVisible()) + foreach (var child in Children) + child.Tick(); + } + + public virtual void AddChild(Widget child) + { + child.Parent = this; + Children.Add( child ); + } + public virtual void RemoveChild(Widget child) { Children.Remove(child); } + public virtual void RemoveChildren() { Children.Clear(); } + + public Widget GetWidget(string id) + { + if (this.Id == id) + return this; + + foreach (var child in Children) + { + var w = child.GetWidget(id); + if (w != null) + return w; + } + return null; + } + + public T GetWidget(string id) where T : Widget + { + var widget = GetWidget(id); + return (widget != null)? (T) widget : null; + } + + public static void CloseWindow() + { + RootWidget.Children.Remove( WindowList.Pop() ); + if( WindowList.Count > 0 ) + rootWidget.Children.Add( WindowList.Peek() ); + } + + public static Widget OpenWindow( string id ) + { + return OpenWindow( id, new Dictionary() ); + } + + public static Widget OpenWindow(string id, Dictionary args ) + { + var window = Game.modData.WidgetLoader.LoadWidget( args, rootWidget, id ); + if( WindowList.Count > 0 ) + rootWidget.Children.Remove( WindowList.Peek() ); + WindowList.Push( window ); + return window; + } + + public static void DoTick() + { + RootWidget.Tick(); + } + + public static void DoDraw() + { + RootWidget.Draw(); + } + } + + public class ContainerWidget : Widget { + public Func GetBackground; + public string Background = null; + + public ContainerWidget() : base() + { + GetBackground = () => Background; + } + + public ContainerWidget(ContainerWidget other) : base(other) + { + Background = other.Background; + GetBackground = other.GetBackground; + } + + public override void DrawInner() + { + var bg = GetBackground(); + if (bg != null) + WidgetUtils.DrawPanel(bg, RenderBounds ); + } + + public override string GetCursor(int2 pos) { return null; } + public override Widget Clone() { return new ContainerWidget(this); } + } + public interface IWidgetDelegate { } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/WidgetLoader.cs b/OpenRA.Game/Widgets/WidgetLoader.cs index db3e1d2cc2..8c43c78747 100644 --- a/OpenRA.Game/Widgets/WidgetLoader.cs +++ b/OpenRA.Game/Widgets/WidgetLoader.cs @@ -1,62 +1,62 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Widgets; - -namespace OpenRA -{ - public class WidgetLoader - { - Dictionary widgets = new Dictionary(); - - public WidgetLoader( ModData modData ) - { - foreach( var file in modData.Manifest.ChromeLayout.Select( a => MiniYaml.FromFile( a ) ) ) - foreach( var w in file ) - widgets.Add( w.Key.Substring( w.Key.IndexOf( '@' ) + 1 ), w ); - } - - public Widget LoadWidget( Dictionary args, Widget parent, string w ) - { - return LoadWidget( args, parent, widgets[ w ] ); - } - - public Widget LoadWidget( Dictionary args, Widget parent, MiniYamlNode node) - { - var widget = NewWidget(node.Key, args); - - if (parent != null) - parent.AddChild( widget ); - - foreach (var child in node.Value.Nodes) - if (child.Key != "Children") - FieldLoader.LoadField(widget, child.Key, child.Value.Value); - - widget.Initialize(); - - foreach (var child in node.Value.Nodes) - if (child.Key == "Children") - foreach (var c in child.Value.Nodes) - LoadWidget( args, widget, c); - - widget.PostInit( args ); - return widget; - } - - Widget NewWidget(string widgetType, Dictionary args) - { - widgetType = widgetType.Split('@')[0]; - return Game.modData.ObjectCreator.CreateObject(widgetType + "Widget", args); - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Widgets; + +namespace OpenRA +{ + public class WidgetLoader + { + Dictionary widgets = new Dictionary(); + + public WidgetLoader( ModData modData ) + { + foreach( var file in modData.Manifest.ChromeLayout.Select( a => MiniYaml.FromFile( a ) ) ) + foreach( var w in file ) + widgets.Add( w.Key.Substring( w.Key.IndexOf( '@' ) + 1 ), w ); + } + + public Widget LoadWidget( Dictionary args, Widget parent, string w ) + { + return LoadWidget( args, parent, widgets[ w ] ); + } + + public Widget LoadWidget( Dictionary args, Widget parent, MiniYamlNode node) + { + var widget = NewWidget(node.Key, args); + + if (parent != null) + parent.AddChild( widget ); + + foreach (var child in node.Value.Nodes) + if (child.Key != "Children") + FieldLoader.LoadField(widget, child.Key, child.Value.Value); + + widget.Initialize(); + + foreach (var child in node.Value.Nodes) + if (child.Key == "Children") + foreach (var c in child.Value.Nodes) + LoadWidget( args, widget, c); + + widget.PostInit( args ); + return widget; + } + + Widget NewWidget(string widgetType, Dictionary args) + { + widgetType = widgetType.Split('@')[0]; + return Game.modData.ObjectCreator.CreateObject(widgetType + "Widget", args); + } + } } \ No newline at end of file diff --git a/OpenRA.Game/Widgets/WidgetUtils.cs b/OpenRA.Game/Widgets/WidgetUtils.cs index cef812770e..56569578a0 100644 --- a/OpenRA.Game/Widgets/WidgetUtils.cs +++ b/OpenRA.Game/Widgets/WidgetUtils.cs @@ -1,155 +1,155 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; - -namespace OpenRA.Widgets -{ - public static class WidgetUtils - { - public static Sprite GetChromeImage(World world, string name) - { - return ChromeProvider.GetImage("chrome-" + world.LocalPlayer.Country.Race, name); - } - - public static void DrawRGBA(Sprite s, float2 pos) - { - Game.Renderer.RgbaSpriteRenderer.DrawSprite(s,pos); - } - - public static void DrawSHP(Sprite s, float2 pos, WorldRenderer wr) - { - Game.Renderer.WorldSpriteRenderer.DrawSprite(s,pos, wr, "chrome"); - } - - public static void DrawPanel(string collection, Rectangle Bounds) - { - DrawPanelPartial(collection, Bounds, PanelSides.All); - } - - public static void FillRectWithSprite(Rectangle r, Sprite s) - { - for (var x = r.Left; x < r.Right; x += (int)s.size.X) - for (var y = r.Top; y < r.Bottom; y += (int)s.size.Y) - { - var ss = s; - var left = new int2(r.Right - x, r.Bottom - y); - if (left.X < (int)s.size.X || left.Y < (int)s.size.Y) - { - Rectangle rr = new Rectangle(s.bounds.Left,s.bounds.Top,Math.Min(left.X,(int)s.size.X),Math.Min(left.Y,(int)s.size.Y)); - ss = new Sprite(s.sheet,rr,s.channel); - } - DrawRGBA(ss, new float2(x, y)); - } - } - - public static void FillRectWithColor(Rectangle r, Color c) - { - Game.Renderer.LineRenderer.FillRect(new RectangleF( - Game.viewport.Location.X + r.X, - Game.viewport.Location.Y + r.Y, - r.Width, r.Height), c); - } - - public static int[] GetBorderSizes(string collection) - { - var images = new[] { "border-t", "border-b", "border-l", "border-r" }; - var ss = images.Select(i => ChromeProvider.GetImage("dialog4", i)).ToArray(); - return new[] { (int)ss[0].size.Y, (int)ss[1].size.Y, (int)ss[2].size.X, (int)ss[3].size.X }; - } - - static bool HasFlags(this PanelSides a, PanelSides b) { return (a & b) == b; } - public static Rectangle InflateBy(this Rectangle rect, int l, int t, int r, int b) - { - return Rectangle.FromLTRB(rect.Left - l, rect.Top - t, - rect.Right + r, rect.Bottom + b); - } - - public static void DrawPanelPartial(string collection, Rectangle Bounds, PanelSides ps) - { - var images = new[] { "border-t", "border-b", "border-l", "border-r", "corner-tl", "corner-tr", "corner-bl", "corner-br", "background" }; - var ss = images.Select(i => ChromeProvider.GetImage(collection, i)).ToArray(); - - // Background - FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, - Bounds.Top + (int)ss[0].size.Y, - Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, - Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), - ss[8]); - - // Left border - if (ps.HasFlags(PanelSides.Left)) - FillRectWithSprite(new Rectangle(Bounds.Left, - Bounds.Top + (int)ss[0].size.Y, - (int)ss[2].size.X, - Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), - ss[2]); - - // Right border - if (ps.HasFlags(PanelSides.Right)) - FillRectWithSprite(new Rectangle(Bounds.Right - (int)ss[3].size.X, - Bounds.Top + (int)ss[0].size.Y, - (int)ss[2].size.X, - Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), - ss[3]); - - // Top border - if (ps.HasFlags(PanelSides.Top)) - FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, - Bounds.Top, - Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, - (int)ss[0].size.Y), - ss[0]); - - // Bottom border - if (ps.HasFlags(PanelSides.Bottom)) - FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, - Bounds.Bottom - (int)ss[1].size.Y, - Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, - (int)ss[0].size.Y), - ss[1]); - - if (ps.HasFlags(PanelSides.Left | PanelSides.Top)) - DrawRGBA(ss[4], new float2(Bounds.Left, Bounds.Top)); - if (ps.HasFlags(PanelSides.Right | PanelSides.Top)) - DrawRGBA(ss[5], new float2(Bounds.Right - ss[5].size.X, Bounds.Top)); - if (ps.HasFlags(PanelSides.Left | PanelSides.Bottom)) - DrawRGBA(ss[6], new float2(Bounds.Left, Bounds.Bottom - ss[6].size.Y)); - if (ps.HasFlags(PanelSides.Right | PanelSides.Bottom)) - DrawRGBA(ss[7], new float2(Bounds.Right - ss[7].size.X, Bounds.Bottom - ss[7].size.Y)); - } - - - public static string FormatTime(int ticks) - { - var seconds = (int)Math.Ceiling(ticks / 25f); - var minutes = seconds / 60; - - if (minutes >= 60) - return "{0:D}:{1:D2}:{2:D2}".F(minutes / 60, minutes % 60, seconds % 60); - else - return "{0:D2}:{1:D2}".F(minutes, seconds % 60); - } - } - - [Flags] - public enum PanelSides - { - Left = 1, - Top = 2, - Right = 4, - Bottom = 8, - - All = Left | Top | Right | Bottom - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; + +namespace OpenRA.Widgets +{ + public static class WidgetUtils + { + public static Sprite GetChromeImage(World world, string name) + { + return ChromeProvider.GetImage("chrome-" + world.LocalPlayer.Country.Race, name); + } + + public static void DrawRGBA(Sprite s, float2 pos) + { + Game.Renderer.RgbaSpriteRenderer.DrawSprite(s,pos); + } + + public static void DrawSHP(Sprite s, float2 pos, WorldRenderer wr) + { + Game.Renderer.WorldSpriteRenderer.DrawSprite(s,pos, wr, "chrome"); + } + + public static void DrawPanel(string collection, Rectangle Bounds) + { + DrawPanelPartial(collection, Bounds, PanelSides.All); + } + + public static void FillRectWithSprite(Rectangle r, Sprite s) + { + for (var x = r.Left; x < r.Right; x += (int)s.size.X) + for (var y = r.Top; y < r.Bottom; y += (int)s.size.Y) + { + var ss = s; + var left = new int2(r.Right - x, r.Bottom - y); + if (left.X < (int)s.size.X || left.Y < (int)s.size.Y) + { + Rectangle rr = new Rectangle(s.bounds.Left,s.bounds.Top,Math.Min(left.X,(int)s.size.X),Math.Min(left.Y,(int)s.size.Y)); + ss = new Sprite(s.sheet,rr,s.channel); + } + DrawRGBA(ss, new float2(x, y)); + } + } + + public static void FillRectWithColor(Rectangle r, Color c) + { + Game.Renderer.LineRenderer.FillRect(new RectangleF( + Game.viewport.Location.X + r.X, + Game.viewport.Location.Y + r.Y, + r.Width, r.Height), c); + } + + public static int[] GetBorderSizes(string collection) + { + var images = new[] { "border-t", "border-b", "border-l", "border-r" }; + var ss = images.Select(i => ChromeProvider.GetImage("dialog4", i)).ToArray(); + return new[] { (int)ss[0].size.Y, (int)ss[1].size.Y, (int)ss[2].size.X, (int)ss[3].size.X }; + } + + static bool HasFlags(this PanelSides a, PanelSides b) { return (a & b) == b; } + public static Rectangle InflateBy(this Rectangle rect, int l, int t, int r, int b) + { + return Rectangle.FromLTRB(rect.Left - l, rect.Top - t, + rect.Right + r, rect.Bottom + b); + } + + public static void DrawPanelPartial(string collection, Rectangle Bounds, PanelSides ps) + { + var images = new[] { "border-t", "border-b", "border-l", "border-r", "corner-tl", "corner-tr", "corner-bl", "corner-br", "background" }; + var ss = images.Select(i => ChromeProvider.GetImage(collection, i)).ToArray(); + + // Background + FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, + Bounds.Top + (int)ss[0].size.Y, + Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), + ss[8]); + + // Left border + if (ps.HasFlags(PanelSides.Left)) + FillRectWithSprite(new Rectangle(Bounds.Left, + Bounds.Top + (int)ss[0].size.Y, + (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), + ss[2]); + + // Right border + if (ps.HasFlags(PanelSides.Right)) + FillRectWithSprite(new Rectangle(Bounds.Right - (int)ss[3].size.X, + Bounds.Top + (int)ss[0].size.Y, + (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), + ss[3]); + + // Top border + if (ps.HasFlags(PanelSides.Top)) + FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, + Bounds.Top, + Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, + (int)ss[0].size.Y), + ss[0]); + + // Bottom border + if (ps.HasFlags(PanelSides.Bottom)) + FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y, + Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, + (int)ss[0].size.Y), + ss[1]); + + if (ps.HasFlags(PanelSides.Left | PanelSides.Top)) + DrawRGBA(ss[4], new float2(Bounds.Left, Bounds.Top)); + if (ps.HasFlags(PanelSides.Right | PanelSides.Top)) + DrawRGBA(ss[5], new float2(Bounds.Right - ss[5].size.X, Bounds.Top)); + if (ps.HasFlags(PanelSides.Left | PanelSides.Bottom)) + DrawRGBA(ss[6], new float2(Bounds.Left, Bounds.Bottom - ss[6].size.Y)); + if (ps.HasFlags(PanelSides.Right | PanelSides.Bottom)) + DrawRGBA(ss[7], new float2(Bounds.Right - ss[7].size.X, Bounds.Bottom - ss[7].size.Y)); + } + + + public static string FormatTime(int ticks) + { + var seconds = (int)Math.Ceiling(ticks / 25f); + var minutes = seconds / 60; + + if (minutes >= 60) + return "{0:D}:{1:D2}:{2:D2}".F(minutes / 60, minutes % 60, seconds % 60); + else + return "{0:D2}:{1:D2}".F(minutes, seconds % 60); + } + } + + [Flags] + public enum PanelSides + { + Left = 1, + Top = 2, + Right = 4, + Bottom = 8, + + All = Left | Top | Right | Bottom + } +} diff --git a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs index 1ea1c57c52..76dc6cc834 100644 --- a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs +++ b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs @@ -1,19 +1,19 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Graphics; -using OpenRA.Orders; +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Orders; using OpenRA.Traits; namespace OpenRA.Widgets @@ -21,12 +21,12 @@ namespace OpenRA.Widgets public class WorldInteractionControllerWidget : Widget { readonly World world; - readonly WorldRenderer worldRenderer; - [ObjectCreator.UseCtor] - public WorldInteractionControllerWidget([ObjectCreator.Param] World world, [ObjectCreator.Param] WorldRenderer worldRenderer) - { + readonly WorldRenderer worldRenderer; + [ObjectCreator.UseCtor] + public WorldInteractionControllerWidget([ObjectCreator.Param] World world, [ObjectCreator.Param] WorldRenderer worldRenderer) + { this.world = world; - this.worldRenderer = worldRenderer; + this.worldRenderer = worldRenderer; } public override void DrawInner() @@ -95,7 +95,7 @@ namespace OpenRA.Widgets { if (world.OrderGenerator == null) return; - var orders = world.OrderGenerator.Order(world, xy.ToInt2(), mi).ToArray(); + var orders = world.OrderGenerator.Order(world, xy.ToInt2(), mi).ToArray(); orders.Do( o => world.IssueOrder( o ) ); // Find an actor with a phrase to say @@ -117,8 +117,8 @@ namespace OpenRA.Widgets public override string GetCursor(int2 pos) { - return Sync.CheckSyncUnchanged( world, () => - { + return Sync.CheckSyncUnchanged( world, () => + { var mi = new MouseInput { Location = pos, @@ -138,13 +138,13 @@ namespace OpenRA.Widgets { world.Selection.DoControlGroup(world, e.KeyName[0] - '0', e.Modifiers); return true; - } - - bool handled = false; - - foreach (var t in world.WorldActor.TraitsImplementing()) - handled = (t.KeyPressed(world.WorldActor, e)) ? true : handled; - + } + + bool handled = false; + + foreach (var t in world.WorldActor.TraitsImplementing()) + handled = (t.KeyPressed(world.WorldActor, e)) ? true : handled; + if (handled) return true; } return false; diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 21688210a0..f44fbad5cb 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -1,267 +1,267 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.Collections; -using OpenRA.Effects; -using OpenRA.FileFormats; -using OpenRA.Network; -using OpenRA.Orders; -using OpenRA.Traits; -using OpenRA.Widgets; -using XRandom = OpenRA.Thirdparty.Random; - -namespace OpenRA -{ - public class World - { - internal TraitDictionary traitDict = new TraitDictionary(); - Set actors = new Set(); - List effects = new List(); - Queue> frameEndActions = new Queue>(); - - public int FrameNumber { get { return orderManager.LocalFrameNumber; } } - - internal readonly OrderManager orderManager; - public Session LobbyInfo { get { return orderManager.LobbyInfo; } } - - public XRandom SharedRandom; - - public readonly Dictionary players = new Dictionary(); - - public void AddPlayer(Player p) { players[p.Index] = p; } - - int localPlayerIndex = -999; - public Player LocalPlayer - { - get { return players.ContainsKey(localPlayerIndex) ? players[localPlayerIndex] : null; } - } - public readonly Shroud LocalShroud; - - public void SetLocalPlayer(int index) - { - if (!(orderManager.Connection is ReplayConnection)) - localPlayerIndex = index; - } - - public readonly Actor WorldActor; - public readonly Map Map; - public readonly TileSet TileSet; - - public void IssueOrder( Order o ) { orderManager.IssueOrder( o ); } /* avoid exposing the OM to mod code */ - - IOrderGenerator orderGenerator_; - public IOrderGenerator OrderGenerator - { - get { return orderGenerator_; } - set - { - Sync.AssertUnsynced( "The current order generator may not be changed from synced code" ); - orderGenerator_ = value; - } - } - - public Selection Selection = new Selection(); - - public void CancelInputMode() { OrderGenerator = new UnitOrderGenerator(); } - - public bool ToggleInputMode() where T : IOrderGenerator, new() - { - if (OrderGenerator is T) - { - CancelInputMode(); - return false; - } - else - { - OrderGenerator = new T(); - return true; - } - } - - internal World(Manifest manifest, Map map, OrderManager orderManager) - { - this.orderManager = orderManager; - orderGenerator_ = new UnitOrderGenerator(); - Map = map; - - TileSet = Rules.TileSets[Map.Tileset]; - TileSet.LoadTiles(); - - SharedRandom = new XRandom(orderManager.LobbyInfo.GlobalSettings.RandomSeed); - - WorldActor = CreateActor( "World", new TypeDictionary() ); - LocalShroud = WorldActor.Trait(); - - Queries = new AllQueries(this); - - // Add players - foreach (var cmp in WorldActor.TraitsImplementing()) - cmp.CreatePlayers(this); - - // Set defaults for any unset stances - foreach (var p in players.Values) - foreach (var q in players.Values) - if (!p.Stances.ContainsKey(q)) - p.Stances[q] = Stance.Neutral; - - Sound.SoundVolumeModifier = 1.0f; - foreach (var wlh in WorldActor.TraitsImplementing()) - wlh.WorldLoaded(this); - } - - public Actor CreateActor( string name, TypeDictionary initDict ) - { - return CreateActor( true, name, initDict ); - } - - public Actor CreateActor( bool addToWorld, string name, TypeDictionary initDict ) - { - var a = new Actor( this, name, initDict ); - if( addToWorld ) - Add( a ); - return a; - } - - public void Add(Actor a) - { - a.IsInWorld = true; - actors.Add(a); - ActorAdded(a); - } - - public void Remove(Actor a) - { - a.IsInWorld = false; - actors.Remove(a); - ActorRemoved(a); - } - - public void Add(IEffect b) { effects.Add(b); } - public void Remove(IEffect b) { effects.Remove(b); } - - public void AddFrameEndTask( Action a ) { frameEndActions.Enqueue( a ); } - - public event Action ActorAdded = _ => { }; - public event Action ActorRemoved = _ => { }; - - // Will do bad things in multiplayer games - public bool DisableTick = false; - public void Tick() - { - // Todo: Expose this as an order so it can be synced - if (!DisableTick) - { - actors.Do( x => x.Tick() ); - Queries.WithTrait().DoTimed( x => - { - x.Trait.Tick( x.Actor ); - }, "[{2}] Trait: {0} ({1:0.000} ms)", Game.Settings.Debug.LongTickThreshold ); - - effects.DoTimed( e => e.Tick( this ), "[{2}] Effect: {0} ({1:0.000} ms)", Game.Settings.Debug.LongTickThreshold ); - } - - while (frameEndActions.Count != 0) - frameEndActions.Dequeue()(this); - Game.viewport.Tick(); - } - - public IEnumerable Actors { get { return actors; } } - public IEnumerable Effects { get { return effects; } } - - uint nextAID = 0; - internal uint NextAID() - { - return nextAID++; - } - - public int SyncHash() - { - //using (new PerfSample("synchash")) - { - int n = 0; - int ret = 0; - - // hash all the actors - foreach (var a in Actors) - ret += n++ * (int)(1+a.ActorID) * Sync.CalculateSyncHash(a); - - // hash all the traits that tick - foreach (var x in traitDict.ActorsWithTraitMultiple(this)) - ret += n++*(int) (1+x.Actor.ActorID)*Sync.CalculateSyncHash(x.Trait); - - // Hash the shared rng - ret += SharedRandom.Last; - - return ret; - } - } - - public class AllQueries - { - readonly World world; - - public readonly Cache OwnedBy; - - public AllQueries( World world ) - { - this.world = world; - OwnedBy = new Cache(p => new OwnedByCachedView(world, world.actors, x => x.Owner == p)); - } - - public IEnumerable> WithTrait() - { - return world.traitDict.ActorsWithTraitMultiple( world ); - } - - static CachedView> WithTraitInner( Set set, TypeDictionary hasTrait ) - { - var ret = hasTrait.GetOrDefault>>(); - if( ret != null ) - return ret; - ret = new CachedView>( - set, - x => x.HasTrait(), - x => new TraitPair { Actor = x, Trait = x.Trait() } ); - hasTrait.Add( ret ); - return ret; - } - - public class OwnedByCachedView : CachedView - { - readonly TypeDictionary hasTrait = new TypeDictionary(); - - public OwnedByCachedView( World world, Set set, Func include ) - : base( set, include, a => a ) - { - } - - public CachedView> WithTrait() - { - return WithTraitInner( this, hasTrait ); - } - } - } - - public AllQueries Queries; - } - - public struct TraitPair - { - public Actor Actor; - public T Trait; - - public override string ToString() - { - return "{0}->{1}".F( Actor.Info.Name, Trait.GetType().Name ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Collections; +using OpenRA.Effects; +using OpenRA.FileFormats; +using OpenRA.Network; +using OpenRA.Orders; +using OpenRA.Traits; +using OpenRA.Widgets; +using XRandom = OpenRA.Thirdparty.Random; + +namespace OpenRA +{ + public class World + { + internal TraitDictionary traitDict = new TraitDictionary(); + Set actors = new Set(); + List effects = new List(); + Queue> frameEndActions = new Queue>(); + + public int FrameNumber { get { return orderManager.LocalFrameNumber; } } + + internal readonly OrderManager orderManager; + public Session LobbyInfo { get { return orderManager.LobbyInfo; } } + + public XRandom SharedRandom; + + public readonly Dictionary players = new Dictionary(); + + public void AddPlayer(Player p) { players[p.Index] = p; } + + int localPlayerIndex = -999; + public Player LocalPlayer + { + get { return players.ContainsKey(localPlayerIndex) ? players[localPlayerIndex] : null; } + } + public readonly Shroud LocalShroud; + + public void SetLocalPlayer(int index) + { + if (!(orderManager.Connection is ReplayConnection)) + localPlayerIndex = index; + } + + public readonly Actor WorldActor; + public readonly Map Map; + public readonly TileSet TileSet; + + public void IssueOrder( Order o ) { orderManager.IssueOrder( o ); } /* avoid exposing the OM to mod code */ + + IOrderGenerator orderGenerator_; + public IOrderGenerator OrderGenerator + { + get { return orderGenerator_; } + set + { + Sync.AssertUnsynced( "The current order generator may not be changed from synced code" ); + orderGenerator_ = value; + } + } + + public Selection Selection = new Selection(); + + public void CancelInputMode() { OrderGenerator = new UnitOrderGenerator(); } + + public bool ToggleInputMode() where T : IOrderGenerator, new() + { + if (OrderGenerator is T) + { + CancelInputMode(); + return false; + } + else + { + OrderGenerator = new T(); + return true; + } + } + + internal World(Manifest manifest, Map map, OrderManager orderManager) + { + this.orderManager = orderManager; + orderGenerator_ = new UnitOrderGenerator(); + Map = map; + + TileSet = Rules.TileSets[Map.Tileset]; + TileSet.LoadTiles(); + + SharedRandom = new XRandom(orderManager.LobbyInfo.GlobalSettings.RandomSeed); + + WorldActor = CreateActor( "World", new TypeDictionary() ); + LocalShroud = WorldActor.Trait(); + + Queries = new AllQueries(this); + + // Add players + foreach (var cmp in WorldActor.TraitsImplementing()) + cmp.CreatePlayers(this); + + // Set defaults for any unset stances + foreach (var p in players.Values) + foreach (var q in players.Values) + if (!p.Stances.ContainsKey(q)) + p.Stances[q] = Stance.Neutral; + + Sound.SoundVolumeModifier = 1.0f; + foreach (var wlh in WorldActor.TraitsImplementing()) + wlh.WorldLoaded(this); + } + + public Actor CreateActor( string name, TypeDictionary initDict ) + { + return CreateActor( true, name, initDict ); + } + + public Actor CreateActor( bool addToWorld, string name, TypeDictionary initDict ) + { + var a = new Actor( this, name, initDict ); + if( addToWorld ) + Add( a ); + return a; + } + + public void Add(Actor a) + { + a.IsInWorld = true; + actors.Add(a); + ActorAdded(a); + } + + public void Remove(Actor a) + { + a.IsInWorld = false; + actors.Remove(a); + ActorRemoved(a); + } + + public void Add(IEffect b) { effects.Add(b); } + public void Remove(IEffect b) { effects.Remove(b); } + + public void AddFrameEndTask( Action a ) { frameEndActions.Enqueue( a ); } + + public event Action ActorAdded = _ => { }; + public event Action ActorRemoved = _ => { }; + + // Will do bad things in multiplayer games + public bool DisableTick = false; + public void Tick() + { + // Todo: Expose this as an order so it can be synced + if (!DisableTick) + { + actors.Do( x => x.Tick() ); + Queries.WithTrait().DoTimed( x => + { + x.Trait.Tick( x.Actor ); + }, "[{2}] Trait: {0} ({1:0.000} ms)", Game.Settings.Debug.LongTickThreshold ); + + effects.DoTimed( e => e.Tick( this ), "[{2}] Effect: {0} ({1:0.000} ms)", Game.Settings.Debug.LongTickThreshold ); + } + + while (frameEndActions.Count != 0) + frameEndActions.Dequeue()(this); + Game.viewport.Tick(); + } + + public IEnumerable Actors { get { return actors; } } + public IEnumerable Effects { get { return effects; } } + + uint nextAID = 0; + internal uint NextAID() + { + return nextAID++; + } + + public int SyncHash() + { + //using (new PerfSample("synchash")) + { + int n = 0; + int ret = 0; + + // hash all the actors + foreach (var a in Actors) + ret += n++ * (int)(1+a.ActorID) * Sync.CalculateSyncHash(a); + + // hash all the traits that tick + foreach (var x in traitDict.ActorsWithTraitMultiple(this)) + ret += n++*(int) (1+x.Actor.ActorID)*Sync.CalculateSyncHash(x.Trait); + + // Hash the shared rng + ret += SharedRandom.Last; + + return ret; + } + } + + public class AllQueries + { + readonly World world; + + public readonly Cache OwnedBy; + + public AllQueries( World world ) + { + this.world = world; + OwnedBy = new Cache(p => new OwnedByCachedView(world, world.actors, x => x.Owner == p)); + } + + public IEnumerable> WithTrait() + { + return world.traitDict.ActorsWithTraitMultiple( world ); + } + + static CachedView> WithTraitInner( Set set, TypeDictionary hasTrait ) + { + var ret = hasTrait.GetOrDefault>>(); + if( ret != null ) + return ret; + ret = new CachedView>( + set, + x => x.HasTrait(), + x => new TraitPair { Actor = x, Trait = x.Trait() } ); + hasTrait.Add( ret ); + return ret; + } + + public class OwnedByCachedView : CachedView + { + readonly TypeDictionary hasTrait = new TypeDictionary(); + + public OwnedByCachedView( World world, Set set, Func include ) + : base( set, include, a => a ) + { + } + + public CachedView> WithTrait() + { + return WithTraitInner( this, hasTrait ); + } + } + } + + public AllQueries Queries; + } + + public struct TraitPair + { + public Actor Actor; + public T Trait; + + public override string ToString() + { + return "{0}->{1}".F( Actor.Info.Name, Trait.GetType().Name ); + } + } +} diff --git a/OpenRA.Game/WorldUtils.cs b/OpenRA.Game/WorldUtils.cs index afee12b3ca..6efaedd616 100755 --- a/OpenRA.Game/WorldUtils.cs +++ b/OpenRA.Game/WorldUtils.cs @@ -1,129 +1,129 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.GameRules; -using OpenRA.Support; -using OpenRA.Traits; -using System; - -namespace OpenRA -{ - public static class WorldUtils - { - public static IEnumerable FindUnitsAtMouse(this World world, int2 mouseLocation) - { - var loc = mouseLocation + Game.viewport.Location; - return FindUnits(world, loc, loc).Where(a => world.LocalShroud.IsVisible(a)); - } - - public static IEnumerable FindUnits(this World world, float2 a, float2 b) - { - var u = float2.Min(a, b).ToInt2(); - var v = float2.Max(a, b).ToInt2(); - return world.WorldActor.Trait().ActorsInBox(u,v); - } - - public static IEnumerable FindUnitsInCircle(this World world, float2 a, float r) - { - using (new PerfSample("FindUnitsInCircle")) - { - var min = a - new float2(r, r); - var max = a + new float2(r, r); - - var actors = world.FindUnits(min, max); - - var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y); - - var inBox = actors.Where(x => x.GetBounds(true).IntersectsWith(rect)); - - return inBox.Where(x => (x.CenterLocation - a).LengthSquared < r * r); - } - } - - public static IEnumerable FindTilesInCircle(this World world, int2 a, int r) - { - var min = world.ClampToWorld(a - new int2(r, r)); - var max = world.ClampToWorld(a + new int2(r, r)); - for (var j = min.Y; j <= max.Y; j++) - for (var i = min.X; i <= max.X; i++) - if (r * r >= (new int2(i, j) - a).LengthSquared) - yield return new int2(i, j); - } - - public static string GetTerrainType(this World world, int2 cell) - { - var custom = world.Map.CustomTerrain[cell.X, cell.Y]; - return custom != null ? custom : world.TileSet.GetTerrainType(world.Map.MapTiles.Value[cell.X, cell.Y]); - } - - public static TerrainTypeInfo GetTerrainInfo(this World world, int2 cell) - { - return world.TileSet.Terrain[world.GetTerrainType(cell)]; - } - - public static int2 ClampToWorld( this World world, int2 xy ) - { - return xy.Clamp(world.Map.Bounds); - } - - public static int2 ChooseRandomEdgeCell(this World w) - { - var isX = w.SharedRandom.Next(2) == 0; - var edge = w.SharedRandom.Next(2) == 0; - - return new int2( - isX ? w.SharedRandom.Next(w.Map.Bounds.Left, w.Map.Bounds.Right) - : (edge ? w.Map.Bounds.Left : w.Map.Bounds.Right), - !isX ? w.SharedRandom.Next(w.Map.Bounds.Top, w.Map.Bounds.Bottom) - : (edge ? w.Map.Bounds.Top : w.Map.Bounds.Bottom)); - } - - public static int2 ChooseRandomCell(this World w, Thirdparty.Random r) - { - return new int2( - r.Next(w.Map.Bounds.Left, w.Map.Bounds.Right), - r.Next(w.Map.Bounds.Top, w.Map.Bounds.Bottom)); - } - - public static IEnumerable GetCountries(this World w) - { - return w.WorldActor.Info.Traits.WithInterface(); - } - - public static float Gauss1D(this Thirdparty.Random r, int samples) - { - return Graphics.Util.MakeArray(samples, _ => (float)r.NextDouble() * 2 - 1f) - .Sum() / samples; - } - - // Returns a random offset in the range [-1..1,-1..1] with a separable - // Gauss distribution with 'samples' values taken for each axis - public static float2 Gauss2D(this Thirdparty.Random r, int samples) - { - return new float2(Gauss1D(r, samples), Gauss1D(r, samples)); - } - - public static bool HasVoice(this Actor a) - { - return a.Info.Traits.Contains() && a.Info.Traits.Get().Voice != null; - } - - public static VoiceInfo GetVoice(this Actor a) - { - if (!a.Info.Traits.Contains()) return null; - var v = a.Info.Traits.Get().Voice; - return (v == null) ? null : Rules.Voices[v]; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.GameRules; +using OpenRA.Support; +using OpenRA.Traits; +using System; + +namespace OpenRA +{ + public static class WorldUtils + { + public static IEnumerable FindUnitsAtMouse(this World world, int2 mouseLocation) + { + var loc = mouseLocation + Game.viewport.Location; + return FindUnits(world, loc, loc).Where(a => world.LocalShroud.IsVisible(a)); + } + + public static IEnumerable FindUnits(this World world, float2 a, float2 b) + { + var u = float2.Min(a, b).ToInt2(); + var v = float2.Max(a, b).ToInt2(); + return world.WorldActor.Trait().ActorsInBox(u,v); + } + + public static IEnumerable FindUnitsInCircle(this World world, float2 a, float r) + { + using (new PerfSample("FindUnitsInCircle")) + { + var min = a - new float2(r, r); + var max = a + new float2(r, r); + + var actors = world.FindUnits(min, max); + + var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y); + + var inBox = actors.Where(x => x.GetBounds(true).IntersectsWith(rect)); + + return inBox.Where(x => (x.CenterLocation - a).LengthSquared < r * r); + } + } + + public static IEnumerable FindTilesInCircle(this World world, int2 a, int r) + { + var min = world.ClampToWorld(a - new int2(r, r)); + var max = world.ClampToWorld(a + new int2(r, r)); + for (var j = min.Y; j <= max.Y; j++) + for (var i = min.X; i <= max.X; i++) + if (r * r >= (new int2(i, j) - a).LengthSquared) + yield return new int2(i, j); + } + + public static string GetTerrainType(this World world, int2 cell) + { + var custom = world.Map.CustomTerrain[cell.X, cell.Y]; + return custom != null ? custom : world.TileSet.GetTerrainType(world.Map.MapTiles.Value[cell.X, cell.Y]); + } + + public static TerrainTypeInfo GetTerrainInfo(this World world, int2 cell) + { + return world.TileSet.Terrain[world.GetTerrainType(cell)]; + } + + public static int2 ClampToWorld( this World world, int2 xy ) + { + return xy.Clamp(world.Map.Bounds); + } + + public static int2 ChooseRandomEdgeCell(this World w) + { + var isX = w.SharedRandom.Next(2) == 0; + var edge = w.SharedRandom.Next(2) == 0; + + return new int2( + isX ? w.SharedRandom.Next(w.Map.Bounds.Left, w.Map.Bounds.Right) + : (edge ? w.Map.Bounds.Left : w.Map.Bounds.Right), + !isX ? w.SharedRandom.Next(w.Map.Bounds.Top, w.Map.Bounds.Bottom) + : (edge ? w.Map.Bounds.Top : w.Map.Bounds.Bottom)); + } + + public static int2 ChooseRandomCell(this World w, Thirdparty.Random r) + { + return new int2( + r.Next(w.Map.Bounds.Left, w.Map.Bounds.Right), + r.Next(w.Map.Bounds.Top, w.Map.Bounds.Bottom)); + } + + public static IEnumerable GetCountries(this World w) + { + return w.WorldActor.Info.Traits.WithInterface(); + } + + public static float Gauss1D(this Thirdparty.Random r, int samples) + { + return Graphics.Util.MakeArray(samples, _ => (float)r.NextDouble() * 2 - 1f) + .Sum() / samples; + } + + // Returns a random offset in the range [-1..1,-1..1] with a separable + // Gauss distribution with 'samples' values taken for each axis + public static float2 Gauss2D(this Thirdparty.Random r, int samples) + { + return new float2(Gauss1D(r, samples), Gauss1D(r, samples)); + } + + public static bool HasVoice(this Actor a) + { + return a.Info.Traits.Contains() && a.Info.Traits.Get().Voice != null; + } + + public static VoiceInfo GetVoice(this Actor a) + { + if (!a.Info.Traits.Contains()) return null; + var v = a.Info.Traits.Get().Voice; + return (v == null) ? null : Rules.Voices[v]; + } + } +} diff --git a/OpenRA.Launcher.Mac/Controller.h b/OpenRA.Launcher.Mac/Controller.h index 7804a520aa..fa8415f821 100644 --- a/OpenRA.Launcher.Mac/Controller.h +++ b/OpenRA.Launcher.Mac/Controller.h @@ -1,9 +1,9 @@ /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #import diff --git a/OpenRA.Launcher.Mac/Controller.m b/OpenRA.Launcher.Mac/Controller.m index b368c5cb6d..8e2f88fb3f 100644 --- a/OpenRA.Launcher.Mac/Controller.m +++ b/OpenRA.Launcher.Mac/Controller.m @@ -1,9 +1,9 @@ /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #import "Controller.h" diff --git a/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs b/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs index 84f28cb9d9..2fbce34044 100644 --- a/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs +++ b/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.Cnc/AttackPopupTurreted.cs b/OpenRA.Mods.Cnc/AttackPopupTurreted.cs index 2651cdfdcb..001d4cf247 100644 --- a/OpenRA.Mods.Cnc/AttackPopupTurreted.cs +++ b/OpenRA.Mods.Cnc/AttackPopupTurreted.cs @@ -1,160 +1,160 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Move; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Render; -using OpenRA.Mods.RA; -using OpenRA.GameRules; - -namespace OpenRA.Mods.Cnc -{ - class AttackPopupTurretedInfo : AttackBaseInfo - { - public int CloseDelay = 125; - public int DefaultFacing = 0; - public float ClosedDamageMultiplier = 0.5f; - public override object Create(ActorInitializer init) { return new AttackPopupTurreted( init.self, this ); } - } - - class AttackPopupTurreted : AttackBase, INotifyBuildComplete, INotifyIdle, IDamageModifier - { - enum PopupState - { - Open, - Rotating, - Transitioning, - Closed - }; - - protected Target target; - AttackPopupTurretedInfo Info; - Turreted Turret; - int IdleTicks = 0; - PopupState State = PopupState.Open; - - public AttackPopupTurreted(Actor self, AttackPopupTurretedInfo info) : base(self) - { - Info = info; - Turret = self.Trait(); - } - - protected override bool CanAttack( Actor self, Target target ) - { - if (State == PopupState.Transitioning) - return false; - - if( self.HasTrait() && !buildComplete ) - return false; - - if (!base.CanAttack( self, target )) - return false; - - IdleTicks = 0; - if (State == PopupState.Closed) - { - State = PopupState.Transitioning; - var rb = self.Trait(); - rb.PlayCustomAnimThen(self, "opening", () => - { - State = PopupState.Open; - rb.PlayCustomAnimRepeating(self, "idle"); - }); - return false; - } - - Turret.desiredFacing = Util.GetFacing( target.CenterLocation - self.CenterLocation, Turret.turretFacing ); - if( Turret.desiredFacing != Turret.turretFacing ) - return false; - - return true; - } - - public override void Tick(Actor self) - { - base.Tick(self); - DoAttack( self, target ); - } - - public void TickIdle(Actor self) - { - if (State == PopupState.Open && IdleTicks++ > Info.CloseDelay) - { - Turret.desiredFacing = Info.DefaultFacing; - State = PopupState.Rotating; - } - else if (State == PopupState.Rotating && Turret.turretFacing == Info.DefaultFacing) - { - State = PopupState.Transitioning; - var rb = self.Trait(); - rb.PlayCustomAnimThen(self, "closing", () => - { - State = PopupState.Closed; - rb.PlayCustomAnimRepeating(self, "closed-idle"); - Turret.desiredFacing = null; - }); - } - } - - public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) - { - return new AttackActivity( newTarget ); - } - - public override void ResolveOrder(Actor self, Order order) - { - base.ResolveOrder(self, order); - - if (order.OrderString == "Stop") - target = Target.None; - } - - bool buildComplete = false; - public void BuildingComplete(Actor self) { buildComplete = true; } - - public float GetDamageModifier(Actor attacker, WarheadInfo warhead) - { - return State == PopupState.Closed ? Info.ClosedDamageMultiplier : 1f; - } - - class AttackActivity : CancelableActivity - { - readonly Target target; - public AttackActivity( Target newTarget ) { this.target = newTarget; } - - public override IActivity Tick( Actor self ) - { - if( IsCanceled || !target.IsValid ) return NextActivity; - - if (self.TraitsImplementing().Any(d => d.Disabled)) - return this; - - var attack = self.Trait(); - const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ - var weapon = attack.ChooseWeaponForTarget(target); - if (weapon != null) - { - attack.target = target; - - if (self.HasTrait() && !self.Info.Traits.Get().OnRails) - return Util.SequenceActivities( - new Follow( target, Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ), - this ); - } - return NextActivity; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Move; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Render; +using OpenRA.Mods.RA; +using OpenRA.GameRules; + +namespace OpenRA.Mods.Cnc +{ + class AttackPopupTurretedInfo : AttackBaseInfo + { + public int CloseDelay = 125; + public int DefaultFacing = 0; + public float ClosedDamageMultiplier = 0.5f; + public override object Create(ActorInitializer init) { return new AttackPopupTurreted( init.self, this ); } + } + + class AttackPopupTurreted : AttackBase, INotifyBuildComplete, INotifyIdle, IDamageModifier + { + enum PopupState + { + Open, + Rotating, + Transitioning, + Closed + }; + + protected Target target; + AttackPopupTurretedInfo Info; + Turreted Turret; + int IdleTicks = 0; + PopupState State = PopupState.Open; + + public AttackPopupTurreted(Actor self, AttackPopupTurretedInfo info) : base(self) + { + Info = info; + Turret = self.Trait(); + } + + protected override bool CanAttack( Actor self, Target target ) + { + if (State == PopupState.Transitioning) + return false; + + if( self.HasTrait() && !buildComplete ) + return false; + + if (!base.CanAttack( self, target )) + return false; + + IdleTicks = 0; + if (State == PopupState.Closed) + { + State = PopupState.Transitioning; + var rb = self.Trait(); + rb.PlayCustomAnimThen(self, "opening", () => + { + State = PopupState.Open; + rb.PlayCustomAnimRepeating(self, "idle"); + }); + return false; + } + + Turret.desiredFacing = Util.GetFacing( target.CenterLocation - self.CenterLocation, Turret.turretFacing ); + if( Turret.desiredFacing != Turret.turretFacing ) + return false; + + return true; + } + + public override void Tick(Actor self) + { + base.Tick(self); + DoAttack( self, target ); + } + + public void TickIdle(Actor self) + { + if (State == PopupState.Open && IdleTicks++ > Info.CloseDelay) + { + Turret.desiredFacing = Info.DefaultFacing; + State = PopupState.Rotating; + } + else if (State == PopupState.Rotating && Turret.turretFacing == Info.DefaultFacing) + { + State = PopupState.Transitioning; + var rb = self.Trait(); + rb.PlayCustomAnimThen(self, "closing", () => + { + State = PopupState.Closed; + rb.PlayCustomAnimRepeating(self, "closed-idle"); + Turret.desiredFacing = null; + }); + } + } + + public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) + { + return new AttackActivity( newTarget ); + } + + public override void ResolveOrder(Actor self, Order order) + { + base.ResolveOrder(self, order); + + if (order.OrderString == "Stop") + target = Target.None; + } + + bool buildComplete = false; + public void BuildingComplete(Actor self) { buildComplete = true; } + + public float GetDamageModifier(Actor attacker, WarheadInfo warhead) + { + return State == PopupState.Closed ? Info.ClosedDamageMultiplier : 1f; + } + + class AttackActivity : CancelableActivity + { + readonly Target target; + public AttackActivity( Target newTarget ) { this.target = newTarget; } + + public override IActivity Tick( Actor self ) + { + if( IsCanceled || !target.IsValid ) return NextActivity; + + if (self.TraitsImplementing().Any(d => d.Disabled)) + return this; + + var attack = self.Trait(); + const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ + var weapon = attack.ChooseWeaponForTarget(target); + if (weapon != null) + { + attack.target = target; + + if (self.HasTrait() && !self.Info.Traits.Get().OnRails) + return Util.SequenceActivities( + new Follow( target, Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ), + this ); + } + return NextActivity; + } + } + } +} diff --git a/OpenRA.Mods.Cnc/CncLoadScreen.cs b/OpenRA.Mods.Cnc/CncLoadScreen.cs index 135479a6dd..6e41b3f84d 100644 --- a/OpenRA.Mods.Cnc/CncLoadScreen.cs +++ b/OpenRA.Mods.Cnc/CncLoadScreen.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion @@ -67,7 +67,7 @@ namespace OpenRA.Mods.Cnc WidgetUtils.FillRectWithSprite(BgRect, Bg); WidgetUtils.FillRectWithSprite(StripeRect, Stripe); r.RgbaSpriteRenderer.DrawSprite(Logo, LogoPos); - Font.DrawText(text, new float2(Renderer.Resolution.Width - textSize.X - 20, Renderer.Resolution.Height - textSize.Y - 20), Color.Black); + Font.DrawText(text, new float2(Renderer.Resolution.Width - textSize.X - 20, Renderer.Resolution.Height - textSize.Y - 20), Color.Black); r.EndFrame( new NullInputHandler() ); } } diff --git a/OpenRA.Mods.Cnc/CncWaterPaletteRotation.cs b/OpenRA.Mods.Cnc/CncWaterPaletteRotation.cs index 27df3de5aa..276894c4bf 100644 --- a/OpenRA.Mods.Cnc/CncWaterPaletteRotation.cs +++ b/OpenRA.Mods.Cnc/CncWaterPaletteRotation.cs @@ -1,40 +1,40 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.Traits; -using System.Collections.Generic; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.Cnc -{ - class CncWaterPaletteRotationInfo : TraitInfo {} - - class CncWaterPaletteRotation : ITick, IPaletteModifier - { - - float t = 0; - public void Tick(Actor self) - { - t += .25f; - } - - public void AdjustPalette(Dictionary palettes) - { - // Only modify the terrain palette - var pal = palettes["terrain"]; - - var copy = (uint[])pal.Values.Clone(); - var rotate = (int)t % 7; - for (int i = 0; i < 7; i++) - pal.SetColor(0x20 + (rotate + i) % 7, copy[0x20 + i]); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.Traits; +using System.Collections.Generic; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.Cnc +{ + class CncWaterPaletteRotationInfo : TraitInfo {} + + class CncWaterPaletteRotation : ITick, IPaletteModifier + { + + float t = 0; + public void Tick(Actor self) + { + t += .25f; + } + + public void AdjustPalette(Dictionary palettes) + { + // Only modify the terrain palette + var pal = palettes["terrain"]; + + var copy = (uint[])pal.Values.Clone(); + var rotate = (int)t % 7; + for (int i = 0; i < 7; i++) + pal.SetColor(0x20 + (rotate + i) % 7, copy[0x20 + i]); + } + } +} diff --git a/OpenRA.Mods.Cnc/DeadBuildingState.cs b/OpenRA.Mods.Cnc/DeadBuildingState.cs index 344a002fd0..74521d6942 100644 --- a/OpenRA.Mods.Cnc/DeadBuildingState.cs +++ b/OpenRA.Mods.Cnc/DeadBuildingState.cs @@ -1,48 +1,48 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Effects; -using OpenRA.Traits; - -namespace OpenRA.Mods.Cnc -{ - class DeadBuildingStateInfo : ITraitInfo, ITraitPrerequisite, ITraitPrerequisite - { - public readonly int LingerTime = 20; - public readonly bool Zombie = false; // Civilian structures stick around after death - public object Create(ActorInitializer init) { return new DeadBuildingState(init.self, this); } - } - - class DeadBuildingState : INotifyDamage - { - DeadBuildingStateInfo info; - RenderSimple rs; - public DeadBuildingState(Actor self, DeadBuildingStateInfo info) - { - this.info = info; - rs = self.Trait(); - self.Trait().RemoveOnDeath = !rs.anim.HasSequence("dead"); - } - - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageStateChanged && e.DamageState == DamageState.Dead) - { - if (!rs.anim.HasSequence("dead")) return; - rs.anim.PlayRepeating("dead"); - if (!info.Zombie) - self.World.AddFrameEndTask( - w => w.Add( - new DelayedAction(info.LingerTime, - () => self.Destroy()))); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Effects; +using OpenRA.Traits; + +namespace OpenRA.Mods.Cnc +{ + class DeadBuildingStateInfo : ITraitInfo, ITraitPrerequisite, ITraitPrerequisite + { + public readonly int LingerTime = 20; + public readonly bool Zombie = false; // Civilian structures stick around after death + public object Create(ActorInitializer init) { return new DeadBuildingState(init.self, this); } + } + + class DeadBuildingState : INotifyDamage + { + DeadBuildingStateInfo info; + RenderSimple rs; + public DeadBuildingState(Actor self, DeadBuildingStateInfo info) + { + this.info = info; + rs = self.Trait(); + self.Trait().RemoveOnDeath = !rs.anim.HasSequence("dead"); + } + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageStateChanged && e.DamageState == DamageState.Dead) + { + if (!rs.anim.HasSequence("dead")) return; + rs.anim.PlayRepeating("dead"); + if (!info.Zombie) + self.World.AddFrameEndTask( + w => w.Add( + new DelayedAction(info.LingerTime, + () => self.Destroy()))); + } + } + } +} diff --git a/OpenRA.Mods.Cnc/Effects/IonCannon.cs b/OpenRA.Mods.Cnc/Effects/IonCannon.cs index e9f9320e40..f9ea628ddc 100644 --- a/OpenRA.Mods.Cnc/Effects/IonCannon.cs +++ b/OpenRA.Mods.Cnc/Effects/IonCannon.cs @@ -1,48 +1,48 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Mods.RA; -using OpenRA.Traits; - -namespace OpenRA.Mods.Cnc.Effects -{ - public class IonCannon : IEffect - { - Target target; - Animation anim; - Actor firedBy; - - public IonCannon(Actor firedBy, World world, int2 location) - { - this.firedBy = firedBy; - target = Target.FromCell(location); - anim = new Animation("ionsfx"); - anim.PlayThen("idle", () => Finish(world)); - } - - public void Tick(World world) { anim.Tick(); } - - public IEnumerable Render() - { - yield return new Renderable(anim.Image, - target.CenterLocation - new float2(.5f * anim.Image.size.X, anim.Image.size.Y - Game.CellSize), - "effect", (int)target.CenterLocation.Y); - } - - void Finish( World world ) - { - world.AddFrameEndTask(w => w.Remove(this)); - Combat.DoExplosion(firedBy, "IonCannon", target.CenterLocation, 0); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Mods.RA; +using OpenRA.Traits; + +namespace OpenRA.Mods.Cnc.Effects +{ + public class IonCannon : IEffect + { + Target target; + Animation anim; + Actor firedBy; + + public IonCannon(Actor firedBy, World world, int2 location) + { + this.firedBy = firedBy; + target = Target.FromCell(location); + anim = new Animation("ionsfx"); + anim.PlayThen("idle", () => Finish(world)); + } + + public void Tick(World world) { anim.Tick(); } + + public IEnumerable Render() + { + yield return new Renderable(anim.Image, + target.CenterLocation - new float2(.5f * anim.Image.size.X, anim.Image.size.Y - Game.CellSize), + "effect", (int)target.CenterLocation.Y); + } + + void Finish( World world ) + { + world.AddFrameEndTask(w => w.Remove(this)); + Combat.DoExplosion(firedBy, "IonCannon", target.CenterLocation, 0); + } + } +} diff --git a/OpenRA.Mods.Cnc/IonCannonPower.cs b/OpenRA.Mods.Cnc/IonCannonPower.cs index df9f702c0c..6a23442e9e 100644 --- a/OpenRA.Mods.Cnc/IonCannonPower.cs +++ b/OpenRA.Mods.Cnc/IonCannonPower.cs @@ -1,35 +1,35 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.Cnc.Effects; -using OpenRA.Mods.RA; -using OpenRA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.Cnc -{ - class IonCannonPowerInfo : SupportPowerInfo - { - public override object Create(ActorInitializer init) { return new IonCannonPower(init.self, this); } - } - - class IonCannonPower : SupportPower - { - public IonCannonPower(Actor self, IonCannonPowerInfo info) : base(self, info) { } - public override void Activate(Actor self, Order order) - { - self.World.AddFrameEndTask(w => - { - Sound.Play(Info.LaunchSound, Game.CellSize * order.TargetLocation.ToFloat2()); - w.Add(new IonCannon(self, w, order.TargetLocation)); - }); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.Cnc.Effects; +using OpenRA.Mods.RA; +using OpenRA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.Cnc +{ + class IonCannonPowerInfo : SupportPowerInfo + { + public override object Create(ActorInitializer init) { return new IonCannonPower(init.self, this); } + } + + class IonCannonPower : SupportPower + { + public IonCannonPower(Actor self, IonCannonPowerInfo info) : base(self, info) { } + public override void Activate(Actor self, Order order) + { + self.World.AddFrameEndTask(w => + { + Sound.Play(Info.LaunchSound, Game.CellSize * order.TargetLocation.ToFloat2()); + w.Add(new IonCannon(self, w, order.TargetLocation)); + }); + } + } +} diff --git a/OpenRA.Mods.Cnc/Missions/CncShellmapScript.cs b/OpenRA.Mods.Cnc/Missions/CncShellmapScript.cs index 5f262af212..fed34d5e53 100755 --- a/OpenRA.Mods.Cnc/Missions/CncShellmapScript.cs +++ b/OpenRA.Mods.Cnc/Missions/CncShellmapScript.cs @@ -1,16 +1,16 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.Mods.RA.Air; +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Mods.RA.Air; using OpenRA.Traits; using OpenRA.FileFormats; using OpenRA.Mods.RA.Activities; @@ -22,28 +22,28 @@ namespace OpenRA.Mods.RA class CncShellmapScript: IWorldLoaded, ITick { - Dictionary Actors; + Dictionary Actors; static int2 ViewportOrigin; Map Map; public void WorldLoaded(World w) - { + { Map = w.Map; var b = w.Map.Bounds; ViewportOrigin = new int2(b.Left + b.Width/2, b.Top + b.Height/2); - Game.MoveViewport(ViewportOrigin); + Game.MoveViewport(ViewportOrigin); Actors = w.WorldActor.Trait().Actors; Sound.SoundVolumeModifier = 0.25f; } - int ticks = 0; + int ticks = 0; float speed = 4f; - public void Tick(Actor self) - { - var loc = new float2( - (float)(-System.Math.Sin((ticks + 45) % (360f * speed) * (Math.PI / 180) * 1f / speed) * 15f + ViewportOrigin.X), - (float)(0.4f*System.Math.Cos((ticks + 45) % (360f * speed) * (Math.PI / 180) * 1f / speed) * 10f + ViewportOrigin.Y)); + public void Tick(Actor self) + { + var loc = new float2( + (float)(-System.Math.Sin((ticks + 45) % (360f * speed) * (Math.PI / 180) * 1f / speed) * 15f + ViewportOrigin.X), + (float)(0.4f*System.Math.Cos((ticks + 45) % (360f * speed) * (Math.PI / 180) * 1f / speed) * 10f + ViewportOrigin.Y)); Game.MoveViewport(loc); if (ticks == 0) diff --git a/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs b/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs index e2b785d0db..69b598f584 100644 --- a/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs +++ b/OpenRA.Mods.Cnc/Missions/Gdi01Script.cs @@ -1,23 +1,23 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA; -using OpenRA.FileFormats; -using OpenRA.Mods.RA; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Move; -using OpenRA.Traits; -using OpenRA.Traits.Activities; +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA; +using OpenRA.FileFormats; +using OpenRA.Mods.RA; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Move; +using OpenRA.Traits; +using OpenRA.Traits.Activities; using OpenRA.Widgets; namespace OpenRA.Mods.Cnc @@ -32,7 +32,7 @@ namespace OpenRA.Mods.Cnc public void WorldLoaded(World w) { - Map = w.Map; + Map = w.Map; Players = w.players.Values.ToDictionary(p => p.InternalName); Actors = w.WorldActor.Trait().Actors; var b = w.Map.Bounds; @@ -98,7 +98,7 @@ namespace OpenRA.Mods.Cnc new OwnerInit( Players["BadGuy"] ), new FacingInit( 0 ), new LocationInit ( Actors["nod0"].Location ), - }); + }); var mobile = a.Trait(); a.QueueActivity( mobile.MoveTo( Actors["nod1"].Location, 2 ) ); a.QueueActivity( mobile.MoveTo( Actors["nod2"].Location, 2 ) ); @@ -164,8 +164,8 @@ namespace OpenRA.Mods.Cnc } void SetGunboatPath() - { - var self = Actors[ "Gunboat" ]; + { + var self = Actors[ "Gunboat" ]; var mobile = self.Trait(); self.QueueActivity(mobile.ScriptedMove( Actors["gunboatLeft"].Location )); self.QueueActivity(mobile.ScriptedMove( Actors["gunboatRight"].Location )); @@ -183,8 +183,8 @@ namespace OpenRA.Mods.Cnc new LocationInit( startPos ), new OwnerInit( Players["GoodGuy"] ), new FacingInit( 0 ), - }); - + }); + var mobile = a.Trait(); var cargo = a.Trait(); foreach (var i in items) @@ -202,7 +202,7 @@ namespace OpenRA.Mods.Cnc { var b = cargo.Unload(a); world.AddFrameEndTask(w2 => - { + { if (b.Destroyed) return; w2.Add(b); b.TraitsImplementing().FirstOrDefault().SetPosition(b, a.Location); diff --git a/OpenRA.Mods.Cnc/PoisonedByTiberium.cs b/OpenRA.Mods.Cnc/PoisonedByTiberium.cs index 413845c2cd..5f4ec0e592 100644 --- a/OpenRA.Mods.Cnc/PoisonedByTiberium.cs +++ b/OpenRA.Mods.Cnc/PoisonedByTiberium.cs @@ -1,49 +1,49 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.GameRules; -using OpenRA.Mods.RA; -using OpenRA.Traits; - -namespace OpenRA.Mods.Cnc -{ - class PoisonedByTiberiumInfo : ITraitInfo - { - [WeaponReference] - public readonly string Weapon = "Tiberium"; - public readonly string[] Resources = { "Tiberium", "BlueTiberium" }; - - public object Create(ActorInitializer init) { return new PoisonedByTiberium(this); } - } - - class PoisonedByTiberium : ITick, ISync - { - PoisonedByTiberiumInfo info; - [Sync] int poisonTicks; - - public PoisonedByTiberium(PoisonedByTiberiumInfo info) { this.info = info; } - - public void Tick(Actor self) - { - if (--poisonTicks > 0) return; - - var rl = self.World.WorldActor.Trait(); - var r = rl.GetResource(self.Location); - if( r == null ) return; - if( !info.Resources.Contains(r.info.Name) ) return; - - var weapon = Rules.Weapons[info.Weapon.ToLowerInvariant()]; - - self.InflictDamage( self.World.WorldActor, weapon.Warheads[ 0 ].Damage, weapon.Warheads[ 0 ] ); - poisonTicks = weapon.ROF; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.GameRules; +using OpenRA.Mods.RA; +using OpenRA.Traits; + +namespace OpenRA.Mods.Cnc +{ + class PoisonedByTiberiumInfo : ITraitInfo + { + [WeaponReference] + public readonly string Weapon = "Tiberium"; + public readonly string[] Resources = { "Tiberium", "BlueTiberium" }; + + public object Create(ActorInitializer init) { return new PoisonedByTiberium(this); } + } + + class PoisonedByTiberium : ITick, ISync + { + PoisonedByTiberiumInfo info; + [Sync] int poisonTicks; + + public PoisonedByTiberium(PoisonedByTiberiumInfo info) { this.info = info; } + + public void Tick(Actor self) + { + if (--poisonTicks > 0) return; + + var rl = self.World.WorldActor.Trait(); + var r = rl.GetResource(self.Location); + if( r == null ) return; + if( !info.Resources.Contains(r.info.Name) ) return; + + var weapon = Rules.Weapons[info.Weapon.ToLowerInvariant()]; + + self.InflictDamage( self.World.WorldActor, weapon.Warheads[ 0 ].Damage, weapon.Warheads[ 0 ] ); + poisonTicks = weapon.ROF; + } + } +} diff --git a/OpenRA.Mods.Cnc/ProductionAirdrop.cs b/OpenRA.Mods.Cnc/ProductionAirdrop.cs index 9c501cca9a..5bc3685783 100644 --- a/OpenRA.Mods.Cnc/ProductionAirdrop.cs +++ b/OpenRA.Mods.Cnc/ProductionAirdrop.cs @@ -1,73 +1,73 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Mods.RA; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Air; - -namespace OpenRA.Mods.Cnc -{ - public class ProductionAirdropInfo : ProductionInfo - { - public readonly string ReadyAudio = "reinfor1.aud"; - public override object Create(ActorInitializer init) { return new ProductionAirdrop(this); } - } - - class ProductionAirdrop : Production - { - public ProductionAirdrop(ProductionAirdropInfo info) : base(info) {} - - public override bool Produce( Actor self, ActorInfo producee ) - { - var owner = self.Owner; - - // Start and end beyond the edge of the map, to give a finite delay, and ability to land when AFLD is on map edge - var startPos = new int2(owner.World.Map.Bounds.Right + 5, self.Location.Y); - var endPos = new int2(owner.World.Map.Bounds.Left - 5, self.Location.Y); - - // Assume a single exit point for simplicity - var exit = self.Info.Traits.WithInterface().First(); - - var rb = self.Trait(); - rb.PlayCustomAnimRepeating(self, "active"); - owner.World.AddFrameEndTask(w => - { - var a = w.CreateActor("C17", new TypeDictionary - { - new LocationInit( startPos ), - new OwnerInit( owner ), - new FacingInit( 64 ), - new AltitudeInit( Rules.Info["c17"].Traits.Get().CruiseAltitude ), - }); - - a.QueueActivity(Fly.ToCell(self.Location + new int2(6,0))); - a.QueueActivity(new Land(Target.FromActor(self))); - a.QueueActivity(new CallFunc(() => - { - if (!self.IsInWorld || self.IsDead()) - return; - - rb.PlayCustomAnimRepeating(self, "idle"); - self.World.AddFrameEndTask(ww => DoProduction(self, producee, exit)); - Sound.PlayToPlayer(self.Owner, (Info as ProductionAirdropInfo).ReadyAudio); - })); - a.QueueActivity(Fly.ToCell(endPos)); - a.QueueActivity(new RemoveSelf()); - }); - - return true; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Mods.RA; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Air; + +namespace OpenRA.Mods.Cnc +{ + public class ProductionAirdropInfo : ProductionInfo + { + public readonly string ReadyAudio = "reinfor1.aud"; + public override object Create(ActorInitializer init) { return new ProductionAirdrop(this); } + } + + class ProductionAirdrop : Production + { + public ProductionAirdrop(ProductionAirdropInfo info) : base(info) {} + + public override bool Produce( Actor self, ActorInfo producee ) + { + var owner = self.Owner; + + // Start and end beyond the edge of the map, to give a finite delay, and ability to land when AFLD is on map edge + var startPos = new int2(owner.World.Map.Bounds.Right + 5, self.Location.Y); + var endPos = new int2(owner.World.Map.Bounds.Left - 5, self.Location.Y); + + // Assume a single exit point for simplicity + var exit = self.Info.Traits.WithInterface().First(); + + var rb = self.Trait(); + rb.PlayCustomAnimRepeating(self, "active"); + owner.World.AddFrameEndTask(w => + { + var a = w.CreateActor("C17", new TypeDictionary + { + new LocationInit( startPos ), + new OwnerInit( owner ), + new FacingInit( 64 ), + new AltitudeInit( Rules.Info["c17"].Traits.Get().CruiseAltitude ), + }); + + a.QueueActivity(Fly.ToCell(self.Location + new int2(6,0))); + a.QueueActivity(new Land(Target.FromActor(self))); + a.QueueActivity(new CallFunc(() => + { + if (!self.IsInWorld || self.IsDead()) + return; + + rb.PlayCustomAnimRepeating(self, "idle"); + self.World.AddFrameEndTask(ww => DoProduction(self, producee, exit)); + Sound.PlayToPlayer(self.Owner, (Info as ProductionAirdropInfo).ReadyAudio); + })); + a.QueueActivity(Fly.ToCell(endPos)); + a.QueueActivity(new RemoveSelf()); + }); + + return true; + } + } +} diff --git a/OpenRA.Mods.Cnc/RenderCargo.cs b/OpenRA.Mods.Cnc/RenderCargo.cs index f85e3ce968..4d8f956f41 100644 --- a/OpenRA.Mods.Cnc/RenderCargo.cs +++ b/OpenRA.Mods.Cnc/RenderCargo.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.Cnc/RenderGunboat.cs b/OpenRA.Mods.Cnc/RenderGunboat.cs index bf24bf3b47..314166370e 100644 --- a/OpenRA.Mods.Cnc/RenderGunboat.cs +++ b/OpenRA.Mods.Cnc/RenderGunboat.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.Cnc/SpawnViceroid.cs b/OpenRA.Mods.Cnc/SpawnViceroid.cs index ce3f12c272..66e77e656a 100644 --- a/OpenRA.Mods.Cnc/SpawnViceroid.cs +++ b/OpenRA.Mods.Cnc/SpawnViceroid.cs @@ -1,55 +1,55 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.FileFormats; -using System.Linq; - -namespace OpenRA.Mods.Cnc -{ - class SpawnViceroidInfo : ITraitInfo - { - [ActorReference] - public readonly string ViceroidActor = "vice"; - public readonly int Probability = 10; - public readonly string Owner = "Creeps"; - public readonly int InfDeath = 5; - - public object Create(ActorInitializer init) { return new SpawnViceroid(this); } - } - - class SpawnViceroid : INotifyDamage - { - readonly SpawnViceroidInfo Info; - - public SpawnViceroid(SpawnViceroidInfo info) - { - Info = info; - } - - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageState == DamageState.Dead && e.Warhead.InfDeath == Info.InfDeath - && self.World.SharedRandom.Next(100) <= Info.Probability) - self.World.AddFrameEndTask(w => - { - var td = new TypeDictionary - { - new LocationInit( self.Location ), - new OwnerInit( self.World.players.Values.First(p => p.InternalName == Info.Owner) ) - }; - - if (self.HasTrait()) - td.Add(new FacingInit( self.Trait().Facing )); - w.CreateActor(Info.ViceroidActor, td); - }); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.FileFormats; +using System.Linq; + +namespace OpenRA.Mods.Cnc +{ + class SpawnViceroidInfo : ITraitInfo + { + [ActorReference] + public readonly string ViceroidActor = "vice"; + public readonly int Probability = 10; + public readonly string Owner = "Creeps"; + public readonly int InfDeath = 5; + + public object Create(ActorInitializer init) { return new SpawnViceroid(this); } + } + + class SpawnViceroid : INotifyDamage + { + readonly SpawnViceroidInfo Info; + + public SpawnViceroid(SpawnViceroidInfo info) + { + Info = info; + } + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageState == DamageState.Dead && e.Warhead.InfDeath == Info.InfDeath + && self.World.SharedRandom.Next(100) <= Info.Probability) + self.World.AddFrameEndTask(w => + { + var td = new TypeDictionary + { + new LocationInit( self.Location ), + new OwnerInit( self.World.players.Values.First(p => p.InternalName == Info.Owner) ) + }; + + if (self.HasTrait()) + td.Add(new FacingInit( self.Trait().Facing )); + w.CreateActor(Info.ViceroidActor, td); + }); + } + } +} diff --git a/OpenRA.Mods.Cnc/TiberiumRefinery.cs b/OpenRA.Mods.Cnc/TiberiumRefinery.cs index 5cd0e92e98..a78d44a3ba 100644 --- a/OpenRA.Mods.Cnc/TiberiumRefinery.cs +++ b/OpenRA.Mods.Cnc/TiberiumRefinery.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion @@ -13,7 +13,7 @@ using OpenRA.Mods.RA; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Render; using OpenRA.Traits; -using OpenRA.Traits.Activities; +using OpenRA.Traits.Activities; using OpenRA.Mods.RA.Move; namespace OpenRA.Mods.Cnc diff --git a/OpenRA.Mods.Cnc/WithFire.cs b/OpenRA.Mods.Cnc/WithFire.cs index d996f33662..6a182c8bcb 100644 --- a/OpenRA.Mods.Cnc/WithFire.cs +++ b/OpenRA.Mods.Cnc/WithFire.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.Cnc/WithRoof.cs b/OpenRA.Mods.Cnc/WithRoof.cs index 1928cfdac8..abe7d3bbb5 100644 --- a/OpenRA.Mods.Cnc/WithRoof.cs +++ b/OpenRA.Mods.Cnc/WithRoof.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.RA/Activities/Attack.cs b/OpenRA.Mods.RA/Activities/Attack.cs index 0937ec7017..241daf21de 100755 --- a/OpenRA.Mods.RA/Activities/Attack.cs +++ b/OpenRA.Mods.RA/Activities/Attack.cs @@ -1,81 +1,81 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Activities -{ - /* non-turreted attack */ - public class Attack : CancelableActivity - { - protected Target Target; - ITargetable targetable; - int Range; - bool AllowMovement; - - int nextPathTime; - - const int delayBetweenPathingAttempts = 20; - const int delaySpread = 5; - - public Attack(Target target, int range, bool allowMovement) - { - Target = target; - if (target.IsActor) - targetable = target.Actor.TraitOrDefault(); - - Range = range; - AllowMovement = allowMovement; - } - - public Attack(Target target, int range) : this(target, range, true) {} - - public override IActivity Tick( Actor self ) - { - var attack = self.Trait(); - - var ret = InnerTick( self, attack ); - attack.IsAttacking = ( ret == this ); - return ret; - } - - protected virtual IActivity InnerTick( Actor self, AttackBase attack ) - { - if (IsCanceled) return NextActivity; - var facing = self.Trait(); - if (!Target.IsValid) - return NextActivity; - - if (targetable != null && !targetable.TargetableBy(Target.Actor, self)) - return NextActivity; - - if (!Combat.IsInRange(self.CenterLocation, Range, Target)) - { - if (--nextPathTime > 0) - return this; - - nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread, - delayBetweenPathingAttempts + delaySpread); - - return (AllowMovement) ? Util.SequenceActivities(self.Trait().MoveWithinRange(Target, Range), this) : NextActivity; - } - - var desiredFacing = Util.GetFacing(Target.CenterLocation - self.CenterLocation, 0); - if (facing.Facing != desiredFacing) - return Util.SequenceActivities( new Turn( desiredFacing ), this ); - - attack.DoAttack(self, Target); - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Activities +{ + /* non-turreted attack */ + public class Attack : CancelableActivity + { + protected Target Target; + ITargetable targetable; + int Range; + bool AllowMovement; + + int nextPathTime; + + const int delayBetweenPathingAttempts = 20; + const int delaySpread = 5; + + public Attack(Target target, int range, bool allowMovement) + { + Target = target; + if (target.IsActor) + targetable = target.Actor.TraitOrDefault(); + + Range = range; + AllowMovement = allowMovement; + } + + public Attack(Target target, int range) : this(target, range, true) {} + + public override IActivity Tick( Actor self ) + { + var attack = self.Trait(); + + var ret = InnerTick( self, attack ); + attack.IsAttacking = ( ret == this ); + return ret; + } + + protected virtual IActivity InnerTick( Actor self, AttackBase attack ) + { + if (IsCanceled) return NextActivity; + var facing = self.Trait(); + if (!Target.IsValid) + return NextActivity; + + if (targetable != null && !targetable.TargetableBy(Target.Actor, self)) + return NextActivity; + + if (!Combat.IsInRange(self.CenterLocation, Range, Target)) + { + if (--nextPathTime > 0) + return this; + + nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread, + delayBetweenPathingAttempts + delaySpread); + + return (AllowMovement) ? Util.SequenceActivities(self.Trait().MoveWithinRange(Target, Range), this) : NextActivity; + } + + var desiredFacing = Util.GetFacing(Target.CenterLocation - self.CenterLocation, 0); + if (facing.Facing != desiredFacing) + return Util.SequenceActivities( new Turn( desiredFacing ), this ); + + attack.DoAttack(self, Target); + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/CallFunc.cs b/OpenRA.Mods.RA/Activities/CallFunc.cs index caea771b16..1227a1e52a 100644 --- a/OpenRA.Mods.RA/Activities/CallFunc.cs +++ b/OpenRA.Mods.RA/Activities/CallFunc.cs @@ -1,58 +1,58 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Activities -{ - public class CallFunc : IActivity - { - public CallFunc(Action a) { this.a = a; } - public CallFunc(Action a, bool interruptable) - { - this.a = a; - this.interruptable = interruptable; - } - - Action a; - bool interruptable; - IActivity NextActivity { get; set; } - - public IActivity Tick(Actor self) - { - if (a != null) a(); - return NextActivity; - } - - public void Cancel(Actor self) - { - if (!interruptable) - return; - - a = null; - NextActivity = null; - } - - public void Queue( IActivity activity ) - { - if( NextActivity != null ) - NextActivity.Queue( activity ); - else - NextActivity = activity; - } - - public IEnumerable GetCurrentPath() - { - yield break; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Activities +{ + public class CallFunc : IActivity + { + public CallFunc(Action a) { this.a = a; } + public CallFunc(Action a, bool interruptable) + { + this.a = a; + this.interruptable = interruptable; + } + + Action a; + bool interruptable; + IActivity NextActivity { get; set; } + + public IActivity Tick(Actor self) + { + if (a != null) a(); + return NextActivity; + } + + public void Cancel(Actor self) + { + if (!interruptable) + return; + + a = null; + NextActivity = null; + } + + public void Queue( IActivity activity ) + { + if( NextActivity != null ) + NextActivity.Queue( activity ); + else + NextActivity = activity; + } + + public IEnumerable GetCurrentPath() + { + yield break; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/CaptureBuilding.cs b/OpenRA.Mods.RA/Activities/CaptureBuilding.cs index ae719d5cbe..aa5b939f38 100644 --- a/OpenRA.Mods.RA/Activities/CaptureBuilding.cs +++ b/OpenRA.Mods.RA/Activities/CaptureBuilding.cs @@ -1,52 +1,52 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - class CaptureBuilding : CancelableActivity - { - Actor target; - - public CaptureBuilding(Actor target) { this.target = target; } - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity; - if (target.Owner == self.Owner) return NextActivity; - - if( !target.Trait().OccupiedCells().Any( x => x.First == self.Location ) ) - return NextActivity; - - // todo: clean this up - self.World.AddFrameEndTask(w => - { - // momentarily remove from world so the ownership queries don't get confused - var oldOwner = target.Owner; - w.Remove(target); - target.Owner = self.Owner; - w.Add(target); - - foreach (var t in target.TraitsImplementing()) - t.OnCapture(target, self, oldOwner, self.Owner); - - foreach (var t in self.World.Queries.WithTrait()) - t.Trait.OnActorCaptured(t.Actor, target, self, oldOwner, self.Owner); - - self.Destroy(); - }); - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + class CaptureBuilding : CancelableActivity + { + Actor target; + + public CaptureBuilding(Actor target) { this.target = target; } + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity; + if (target.Owner == self.Owner) return NextActivity; + + if( !target.Trait().OccupiedCells().Any( x => x.First == self.Location ) ) + return NextActivity; + + // todo: clean this up + self.World.AddFrameEndTask(w => + { + // momentarily remove from world so the ownership queries don't get confused + var oldOwner = target.Owner; + w.Remove(target); + target.Owner = self.Owner; + w.Add(target); + + foreach (var t in target.TraitsImplementing()) + t.OnCapture(target, self, oldOwner, self.Owner); + + foreach (var t in self.World.Queries.WithTrait()) + t.Trait.OnActorCaptured(t.Actor, target, self, oldOwner, self.Owner); + + self.Destroy(); + }); + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/DeliverOre.cs b/OpenRA.Mods.RA/Activities/DeliverOre.cs index fe3f3933c8..face6240e2 100755 --- a/OpenRA.Mods.RA/Activities/DeliverOre.cs +++ b/OpenRA.Mods.RA/Activities/DeliverOre.cs @@ -1,72 +1,72 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Activities -{ - public class DeliverResources : IActivity - { - IActivity NextActivity { get; set; } - - bool isDocking; - - public DeliverResources() { } - - public IActivity Tick( Actor self ) - { - if( NextActivity != null ) - return NextActivity; - - var mobile = self.Trait(); - var harv = self.Trait(); - - if (harv.LinkedProc == null || !harv.LinkedProc.IsInWorld) - harv.ChooseNewProc(self, null); - - if (harv.LinkedProc == null) // no procs exist; check again in 1s. - return Util.SequenceActivities( new Wait(25), this ); - - var proc = harv.LinkedProc; - - if( self.Location != proc.Location + proc.Trait().DeliverOffset ) - { - return Util.SequenceActivities( mobile.MoveTo(proc.Location + proc.Trait().DeliverOffset, 0), this ); - } - else if (!isDocking) - { - isDocking = true; - proc.Trait().OnDock(self, this); - } - return Util.SequenceActivities( new Wait(10), this ); - } - - public void Cancel(Actor self) - { - // TODO: allow canceling of deliver orders? - } - - public void Queue( IActivity activity ) - { - if( NextActivity != null ) - NextActivity.Queue( activity ); - else - NextActivity = activity; - } - - public IEnumerable GetCurrentPath() - { - yield break; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Activities +{ + public class DeliverResources : IActivity + { + IActivity NextActivity { get; set; } + + bool isDocking; + + public DeliverResources() { } + + public IActivity Tick( Actor self ) + { + if( NextActivity != null ) + return NextActivity; + + var mobile = self.Trait(); + var harv = self.Trait(); + + if (harv.LinkedProc == null || !harv.LinkedProc.IsInWorld) + harv.ChooseNewProc(self, null); + + if (harv.LinkedProc == null) // no procs exist; check again in 1s. + return Util.SequenceActivities( new Wait(25), this ); + + var proc = harv.LinkedProc; + + if( self.Location != proc.Location + proc.Trait().DeliverOffset ) + { + return Util.SequenceActivities( mobile.MoveTo(proc.Location + proc.Trait().DeliverOffset, 0), this ); + } + else if (!isDocking) + { + isDocking = true; + proc.Trait().OnDock(self, this); + } + return Util.SequenceActivities( new Wait(10), this ); + } + + public void Cancel(Actor self) + { + // TODO: allow canceling of deliver orders? + } + + public void Queue( IActivity activity ) + { + if( NextActivity != null ) + NextActivity.Queue( activity ); + else + NextActivity = activity; + } + + public IEnumerable GetCurrentPath() + { + yield break; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Demolish.cs b/OpenRA.Mods.RA/Activities/Demolish.cs index 506be2da10..7ca4e69aac 100644 --- a/OpenRA.Mods.RA/Activities/Demolish.cs +++ b/OpenRA.Mods.RA/Activities/Demolish.cs @@ -1,37 +1,37 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Effects; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - class Demolish : CancelableActivity - { - Actor target; - - public Demolish( Actor target ) { this.target = target; } - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity; - - if( !target.Trait().OccupiedCells().Any( x => x.First == self.Location ) ) - return NextActivity; - - self.World.AddFrameEndTask(w => w.Add(new DelayedAction(25 * 2, - () => { if (target.IsInWorld) target.Kill(self); }))); - return NextActivity; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Effects; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + class Demolish : CancelableActivity + { + Actor target; + + public Demolish( Actor target ) { this.target = target; } + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity; + + if( !target.Trait().OccupiedCells().Any( x => x.First == self.Location ) ) + return NextActivity; + + self.World.AddFrameEndTask(w => w.Add(new DelayedAction(25 * 2, + () => { if (target.IsInWorld) target.Kill(self); }))); + return NextActivity; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Enter.cs b/OpenRA.Mods.RA/Activities/Enter.cs index 50e8786257..2ec80185fb 100755 --- a/OpenRA.Mods.RA/Activities/Enter.cs +++ b/OpenRA.Mods.RA/Activities/Enter.cs @@ -1,38 +1,38 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Activities -{ - public class Enter : CancelableActivity - { - readonly Actor target; - public Enter( Actor target ) { this.target = target; } - - public override IActivity Tick( Actor self ) - { - if( IsCanceled || target.Destroyed || !target.IsInWorld ) - return NextActivity; - - var mobile = self.Trait(); - var nearest = target.Trait().NearestCellTo( mobile.toCell ); - if( ( nearest - mobile.toCell ).LengthSquared > 2 ) - return Util.SequenceActivities( new MoveAdjacentTo( target ), this ); - - return Util.SequenceActivities( mobile.MoveTo( nearest, target ), NextActivity ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Activities +{ + public class Enter : CancelableActivity + { + readonly Actor target; + public Enter( Actor target ) { this.target = target; } + + public override IActivity Tick( Actor self ) + { + if( IsCanceled || target.Destroyed || !target.IsInWorld ) + return NextActivity; + + var mobile = self.Trait(); + var nearest = target.Trait().NearestCellTo( mobile.toCell ); + if( ( nearest - mobile.toCell ).LengthSquared > 2 ) + return Util.SequenceActivities( new MoveAdjacentTo( target ), this ); + + return Util.SequenceActivities( mobile.MoveTo( nearest, target ), NextActivity ); + } + } +} diff --git a/OpenRA.Mods.RA/Activities/EnterTransport.cs b/OpenRA.Mods.RA/Activities/EnterTransport.cs index aa5093d58c..d63f74b440 100644 --- a/OpenRA.Mods.RA/Activities/EnterTransport.cs +++ b/OpenRA.Mods.RA/Activities/EnterTransport.cs @@ -1,46 +1,46 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - class EnterTransport : CancelableActivity - { - public Actor transport; - - public EnterTransport(Actor self, Actor transport) - { - this.transport = transport; - } - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - if (transport == null || !transport.IsInWorld) return NextActivity; - - var cargo = transport.Trait(); - if (cargo.IsFull(transport)) - return NextActivity; - - - // Todo: Queue a move order to the transport? need to be - // careful about units that can't path to the transport - if ((transport.Location - self.Location).Length > 1) - return NextActivity; - - cargo.Load(transport, self); - self.World.AddFrameEndTask(w => w.Remove(self)); - - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + class EnterTransport : CancelableActivity + { + public Actor transport; + + public EnterTransport(Actor self, Actor transport) + { + this.transport = transport; + } + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + if (transport == null || !transport.IsInWorld) return NextActivity; + + var cargo = transport.Trait(); + if (cargo.IsFull(transport)) + return NextActivity; + + + // Todo: Queue a move order to the transport? need to be + // careful about units that can't path to the transport + if ((transport.Location - self.Location).Length > 1) + return NextActivity; + + cargo.Load(transport, self); + self.World.AddFrameEndTask(w => w.Remove(self)); + + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Follow.cs b/OpenRA.Mods.RA/Activities/Follow.cs index 65d1e2310b..1bec2e7f02 100644 --- a/OpenRA.Mods.RA/Activities/Follow.cs +++ b/OpenRA.Mods.RA/Activities/Follow.cs @@ -1,49 +1,49 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Activities -{ - public class Follow : CancelableActivity - { - Target Target; - int Range; - int nextPathTime; - - const int delayBetweenPathingAttempts = 20; - const int delaySpread = 5; - - public Follow(Target target, int range) - { - Target = target; - Range = range; - } - - public override IActivity Tick( Actor self ) - { - if (IsCanceled) return NextActivity; - if (!Target.IsValid) return NextActivity; - - var inRange = ( Util.CellContaining( Target.CenterLocation ) - self.Location ).LengthSquared < Range * Range; - - if( inRange ) return this; - if (--nextPathTime > 0) return this; - - nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread, - delayBetweenPathingAttempts + delaySpread); - - var mobile = self.Trait(); - return Util.SequenceActivities( mobile.MoveWithinRange( Target, Range ), this ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Activities +{ + public class Follow : CancelableActivity + { + Target Target; + int Range; + int nextPathTime; + + const int delayBetweenPathingAttempts = 20; + const int delaySpread = 5; + + public Follow(Target target, int range) + { + Target = target; + Range = range; + } + + public override IActivity Tick( Actor self ) + { + if (IsCanceled) return NextActivity; + if (!Target.IsValid) return NextActivity; + + var inRange = ( Util.CellContaining( Target.CenterLocation ) - self.Location ).LengthSquared < Range * Range; + + if( inRange ) return this; + if (--nextPathTime > 0) return this; + + nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread, + delayBetweenPathingAttempts + delaySpread); + + var mobile = self.Trait(); + return Util.SequenceActivities( mobile.MoveWithinRange( Target, Range ), this ); + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Harvest.cs b/OpenRA.Mods.RA/Activities/Harvest.cs index 332e1cf4a6..86b5200b67 100755 --- a/OpenRA.Mods.RA/Activities/Harvest.cs +++ b/OpenRA.Mods.RA/Activities/Harvest.cs @@ -1,78 +1,78 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Activities -{ - public class Harvest : CancelableActivity - { - bool isHarvesting = false; - - public override IActivity Tick( Actor self ) - { - if( isHarvesting ) return this; - if( IsCanceled ) return NextActivity; - if( NextActivity != null ) return NextActivity; - - var harv = self.Trait(); - harv.LastHarvestedCell = self.Location; - - if( harv.IsFull ) - return Util.SequenceActivities( new DeliverResources(), NextActivity ); - - if (HarvestThisTile(self)) - return this; - else - { - FindMoreResource(self); - return NextActivity; - } - } - - bool HarvestThisTile(Actor self) - { - var harv = self.Trait(); - var renderUnit = self.Trait(); /* better have one of these! */ - - var resource = self.World.WorldActor.Trait().Harvest(self.Location); - if (resource == null) - return false; - - if (renderUnit.anim.CurrentSequence.Name != "harvest") - { - isHarvesting = true; - renderUnit.PlayCustomAnimation(self, "harvest", () => isHarvesting = false); - } - harv.AcceptResource(resource); - return true; - } - - void FindMoreResource(Actor self) - { - var mobile = self.Trait(); - var res = self.World.WorldActor.Trait(); - var harv = self.Info.Traits.Get(); - var mobileInfo = self.Info.Traits.Get(); - self.QueueActivity(mobile.MoveTo( - () => - { - return self.World.WorldActor.Trait().FindPath(PathSearch.Search(self.World, mobileInfo, true) - .WithHeuristic(loc => (res.GetResource(loc) != null && harv.Resources.Contains( res.GetResource(loc).info.Name )) ? 0 : 1) - .FromPoint(self.Location)); - })); - self.QueueActivity(new Harvest()); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Activities +{ + public class Harvest : CancelableActivity + { + bool isHarvesting = false; + + public override IActivity Tick( Actor self ) + { + if( isHarvesting ) return this; + if( IsCanceled ) return NextActivity; + if( NextActivity != null ) return NextActivity; + + var harv = self.Trait(); + harv.LastHarvestedCell = self.Location; + + if( harv.IsFull ) + return Util.SequenceActivities( new DeliverResources(), NextActivity ); + + if (HarvestThisTile(self)) + return this; + else + { + FindMoreResource(self); + return NextActivity; + } + } + + bool HarvestThisTile(Actor self) + { + var harv = self.Trait(); + var renderUnit = self.Trait(); /* better have one of these! */ + + var resource = self.World.WorldActor.Trait().Harvest(self.Location); + if (resource == null) + return false; + + if (renderUnit.anim.CurrentSequence.Name != "harvest") + { + isHarvesting = true; + renderUnit.PlayCustomAnimation(self, "harvest", () => isHarvesting = false); + } + harv.AcceptResource(resource); + return true; + } + + void FindMoreResource(Actor self) + { + var mobile = self.Trait(); + var res = self.World.WorldActor.Trait(); + var harv = self.Info.Traits.Get(); + var mobileInfo = self.Info.Traits.Get(); + self.QueueActivity(mobile.MoveTo( + () => + { + return self.World.WorldActor.Trait().FindPath(PathSearch.Search(self.World, mobileInfo, true) + .WithHeuristic(loc => (res.GetResource(loc) != null && harv.Resources.Contains( res.GetResource(loc).info.Name )) ? 0 : 1) + .FromPoint(self.Location)); + })); + self.QueueActivity(new Harvest()); + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Heal.cs b/OpenRA.Mods.RA/Activities/Heal.cs index 6775f8dd68..3b5e09907f 100755 --- a/OpenRA.Mods.RA/Activities/Heal.cs +++ b/OpenRA.Mods.RA/Activities/Heal.cs @@ -1,32 +1,32 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Activities -{ - /* non-turreted attack */ - public class Heal : Attack - { - public Heal(Target target, int range, bool allowMovement) - : base(target, range, allowMovement) {} - - protected override IActivity InnerTick( Actor self, AttackBase attack ) - { - if (Target.IsActor && Target.Actor.GetDamageState() == DamageState.Undamaged) - return NextActivity; - - return base.InnerTick(self, attack); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Activities +{ + /* non-turreted attack */ + public class Heal : Attack + { + public Heal(Target target, int range, bool allowMovement) + : base(target, range, allowMovement) {} + + protected override IActivity InnerTick( Actor self, AttackBase attack ) + { + if (Target.IsActor && Target.Actor.GetDamageState() == DamageState.Undamaged) + return NextActivity; + + return base.InnerTick(self, attack); + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Infiltrate.cs b/OpenRA.Mods.RA/Activities/Infiltrate.cs index ddc4490526..ff2e0c9bac 100644 --- a/OpenRA.Mods.RA/Activities/Infiltrate.cs +++ b/OpenRA.Mods.RA/Activities/Infiltrate.cs @@ -1,39 +1,39 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - class Infiltrate : CancelableActivity - { - Actor target; - public Infiltrate(Actor target) { this.target = target; } - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity; - if (target.Owner == self.Owner) return NextActivity; - - if( !target.Trait().OccupiedCells().Any( x => x.First == self.Location ) ) - return NextActivity; - - foreach (var t in target.TraitsImplementing()) - t.OnInfiltrate(target, self); - - self.Destroy(); - - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + class Infiltrate : CancelableActivity + { + Actor target; + public Infiltrate(Actor target) { this.target = target; } + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity; + if (target.Owner == self.Owner) return NextActivity; + + if( !target.Trait().OccupiedCells().Any( x => x.First == self.Location ) ) + return NextActivity; + + foreach (var t in target.TraitsImplementing()) + t.OnInfiltrate(target, self); + + self.Destroy(); + + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/LayMines.cs b/OpenRA.Mods.RA/Activities/LayMines.cs index 5a37a56c96..6f51445b85 100644 --- a/OpenRA.Mods.RA/Activities/LayMines.cs +++ b/OpenRA.Mods.RA/Activities/LayMines.cs @@ -1,87 +1,87 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Activities -{ - // assumes you have Minelayer on that unit - - class LayMines : CancelableActivity - { - public override IActivity Tick( Actor self ) - { - if (IsCanceled) return NextActivity; - - var mobile = self.Trait(); - var limitedAmmo = self.TraitOrDefault(); - if (!limitedAmmo.HasAmmo()) - { - // rearm & repair at fix, then back out here to refill the minefield some more - var buildings = self.Info.Traits.Get().RearmBuildings; - var rearmTarget = self.World.Actors.FirstOrDefault(a => a.Owner != null && self.Owner.Stances[a.Owner] == Stance.Ally - && buildings.Contains(a.Info.Name)); - - if (rearmTarget == null) - return new Wait(20); - - return Util.SequenceActivities( - new Enter(rearmTarget), - //new Move(Util.CellContaining(rearmTarget.CenterLocation), rearmTarget), - new Rearm(), - new Repair(rearmTarget), - this ); - } - - var ml = self.Trait(); - if (ml.minefield.Contains(self.Location) && - ShouldLayMine(self, self.Location)) - { - LayMine(self); - return Util.SequenceActivities( new Wait(20), this ); // a little wait after placing each mine, for show - } - - for (var n = 0; n < 20; n++) // dont get stuck forever here - { - var p = ml.minefield.Random(self.World.SharedRandom); - if (ShouldLayMine(self, p)) - return Util.SequenceActivities( mobile.MoveTo(p, 0), this ); - } - - // todo: return somewhere likely to be safe (near fix) so we're not sitting out in the minefield. - - return new Wait(20); // nothing to do here - } - - bool ShouldLayMine(Actor self, int2 p) - { - // if there is no unit (other than me) here, we want to place a mine here - return !self.World.WorldActor.Trait() - .GetUnitsAt(p).Any(a => a != self); - } - - void LayMine(Actor self) - { - var limitedAmmo = self.TraitOrDefault(); - if (limitedAmmo != null) limitedAmmo.Attacking(self, Target.FromCell(self.Location)); - - self.World.AddFrameEndTask( - w => w.CreateActor(self.Info.Traits.Get().Mine, new TypeDictionary - { - new LocationInit( self.Location ), - new OwnerInit( self.Owner ), - })); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Activities +{ + // assumes you have Minelayer on that unit + + class LayMines : CancelableActivity + { + public override IActivity Tick( Actor self ) + { + if (IsCanceled) return NextActivity; + + var mobile = self.Trait(); + var limitedAmmo = self.TraitOrDefault(); + if (!limitedAmmo.HasAmmo()) + { + // rearm & repair at fix, then back out here to refill the minefield some more + var buildings = self.Info.Traits.Get().RearmBuildings; + var rearmTarget = self.World.Actors.FirstOrDefault(a => a.Owner != null && self.Owner.Stances[a.Owner] == Stance.Ally + && buildings.Contains(a.Info.Name)); + + if (rearmTarget == null) + return new Wait(20); + + return Util.SequenceActivities( + new Enter(rearmTarget), + //new Move(Util.CellContaining(rearmTarget.CenterLocation), rearmTarget), + new Rearm(), + new Repair(rearmTarget), + this ); + } + + var ml = self.Trait(); + if (ml.minefield.Contains(self.Location) && + ShouldLayMine(self, self.Location)) + { + LayMine(self); + return Util.SequenceActivities( new Wait(20), this ); // a little wait after placing each mine, for show + } + + for (var n = 0; n < 20; n++) // dont get stuck forever here + { + var p = ml.minefield.Random(self.World.SharedRandom); + if (ShouldLayMine(self, p)) + return Util.SequenceActivities( mobile.MoveTo(p, 0), this ); + } + + // todo: return somewhere likely to be safe (near fix) so we're not sitting out in the minefield. + + return new Wait(20); // nothing to do here + } + + bool ShouldLayMine(Actor self, int2 p) + { + // if there is no unit (other than me) here, we want to place a mine here + return !self.World.WorldActor.Trait() + .GetUnitsAt(p).Any(a => a != self); + } + + void LayMine(Actor self) + { + var limitedAmmo = self.TraitOrDefault(); + if (limitedAmmo != null) limitedAmmo.Attacking(self, Target.FromCell(self.Location)); + + self.World.AddFrameEndTask( + w => w.CreateActor(self.Info.Traits.Get().Mine, new TypeDictionary + { + new LocationInit( self.Location ), + new OwnerInit( self.Owner ), + })); + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Leap.cs b/OpenRA.Mods.RA/Activities/Leap.cs index 0b485c5da1..8c87e5fc2d 100644 --- a/OpenRA.Mods.RA/Activities/Leap.cs +++ b/OpenRA.Mods.RA/Activities/Leap.cs @@ -1,61 +1,61 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Mods.RA.Render; -using OpenRA.Mods.RA.Move; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - class Leap : CancelableActivity - { - Target target; - int2 initialLocation; - - int moveFraction; - const int delay = 6; - - public Leap(Actor self, Target target) - { - this.target = target; - initialLocation = self.Trait().PxPosition; - - self.Trait().Attacking(self, target); - Sound.Play("dogg5p.aud", self.CenterLocation); - } - - public override IActivity Tick(Actor self) - { - if( moveFraction == 0 && IsCanceled ) return NextActivity; - if (!target.IsValid) return NextActivity; - - self.Trait().IsLeaping = true; - var mobile = self.Trait(); - ++moveFraction; - - mobile.PxPosition = int2.Lerp(initialLocation, target.PxPosition, moveFraction, delay); - - if (moveFraction >= delay) - { - self.TraitsImplementing().FirstOrDefault() - .SetPosition(self, Util.CellContaining(target.CenterLocation)); - - if (target.IsActor) - target.Actor.Kill(self); - self.Trait().IsLeaping = false; - return NextActivity; - } - - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.RA.Render; +using OpenRA.Mods.RA.Move; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + class Leap : CancelableActivity + { + Target target; + int2 initialLocation; + + int moveFraction; + const int delay = 6; + + public Leap(Actor self, Target target) + { + this.target = target; + initialLocation = self.Trait().PxPosition; + + self.Trait().Attacking(self, target); + Sound.Play("dogg5p.aud", self.CenterLocation); + } + + public override IActivity Tick(Actor self) + { + if( moveFraction == 0 && IsCanceled ) return NextActivity; + if (!target.IsValid) return NextActivity; + + self.Trait().IsLeaping = true; + var mobile = self.Trait(); + ++moveFraction; + + mobile.PxPosition = int2.Lerp(initialLocation, target.PxPosition, moveFraction, delay); + + if (moveFraction >= delay) + { + self.TraitsImplementing().FirstOrDefault() + .SetPosition(self, Util.CellContaining(target.CenterLocation)); + + if (target.IsActor) + target.Actor.Kill(self); + self.Trait().IsLeaping = false; + return NextActivity; + } + + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs b/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs index 3cf7266aea..6de31d0d34 100755 --- a/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs +++ b/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs @@ -1,55 +1,55 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Activities -{ - public class MoveAdjacentTo : CancelableActivity - { - readonly Actor target; - - public MoveAdjacentTo( Actor target ) - { - this.target = target; - } - - public override IActivity Tick( Actor self ) - { - if( IsCanceled || target.Destroyed || !target.IsInWorld) return NextActivity; - - var mobile = self.Trait(); - var ps1 = new PathSearch( self.World, mobile.Info ) - { - checkForBlocked = true, - heuristic = location => 0, - inReverse = true - }; - foreach( var cell in target.Trait().OccupiedCells() ) - { - ps1.AddInitialCell( cell.First ); - if( ( mobile.toCell - cell.First ).LengthSquared <= 2 ) - return NextActivity; - } - ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell ); - - var ps2 = PathSearch.FromPoint( self.World, mobile.Info, mobile.toCell, target.Location, true ); - var ret = self.World.WorldActor.Trait().FindBidiPath( ps1, ps2 ); - if( ret.Count > 0 ) - ret.RemoveAt( 0 ); - return Util.SequenceActivities( mobile.MoveTo( () => ret ), this ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Activities +{ + public class MoveAdjacentTo : CancelableActivity + { + readonly Actor target; + + public MoveAdjacentTo( Actor target ) + { + this.target = target; + } + + public override IActivity Tick( Actor self ) + { + if( IsCanceled || target.Destroyed || !target.IsInWorld) return NextActivity; + + var mobile = self.Trait(); + var ps1 = new PathSearch( self.World, mobile.Info ) + { + checkForBlocked = true, + heuristic = location => 0, + inReverse = true + }; + foreach( var cell in target.Trait().OccupiedCells() ) + { + ps1.AddInitialCell( cell.First ); + if( ( mobile.toCell - cell.First ).LengthSquared <= 2 ) + return NextActivity; + } + ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell ); + + var ps2 = PathSearch.FromPoint( self.World, mobile.Info, mobile.toCell, target.Location, true ); + var ret = self.World.WorldActor.Trait().FindBidiPath( ps1, ps2 ); + if( ret.Count > 0 ) + ret.RemoveAt( 0 ); + return Util.SequenceActivities( mobile.MoveTo( () => ret ), this ); + } + } +} diff --git a/OpenRA.Mods.RA/Activities/QueuedActivity.cs b/OpenRA.Mods.RA/Activities/QueuedActivity.cs index e67d58cf7a..f529f168af 100644 --- a/OpenRA.Mods.RA/Activities/QueuedActivity.cs +++ b/OpenRA.Mods.RA/Activities/QueuedActivity.cs @@ -1,77 +1,77 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Activities -{ - public class QueuedActivity : IActivity - { - public QueuedActivity(Action a) { this.a = a; } - - public QueuedActivity(Action a, bool interruptable) - { - this.a = a; - this.interruptable = interruptable; - } - - Action a; - private bool interruptable = true; - public IActivity NextActivity { get; set; } - - public IActivity Tick(Actor self) { return Run(self); } - - public IActivity Run(Actor self) - { - if (a != null) - a(this); - - return NextActivity; - } - - public void Insert(IActivity activity) - { - if (activity == null) - return; - activity.Queue(NextActivity); - NextActivity = activity; - } - - public void Cancel(Actor self) - { - if (!interruptable) - return; - - a = null; - NextActivity = null; - } - - public void Queue( IActivity activity ) - { - if( NextActivity != null ) - NextActivity.Queue( activity ); - else - NextActivity = activity; - } - - public IEnumerable GetCurrentPath() - { - if (NextActivity != null) - foreach (var path in NextActivity.GetCurrentPath()) - { - yield return path; - } - - yield break; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Activities +{ + public class QueuedActivity : IActivity + { + public QueuedActivity(Action a) { this.a = a; } + + public QueuedActivity(Action a, bool interruptable) + { + this.a = a; + this.interruptable = interruptable; + } + + Action a; + private bool interruptable = true; + public IActivity NextActivity { get; set; } + + public IActivity Tick(Actor self) { return Run(self); } + + public IActivity Run(Actor self) + { + if (a != null) + a(this); + + return NextActivity; + } + + public void Insert(IActivity activity) + { + if (activity == null) + return; + activity.Queue(NextActivity); + NextActivity = activity; + } + + public void Cancel(Actor self) + { + if (!interruptable) + return; + + a = null; + NextActivity = null; + } + + public void Queue( IActivity activity ) + { + if( NextActivity != null ) + NextActivity.Queue( activity ); + else + NextActivity = activity; + } + + public IEnumerable GetCurrentPath() + { + if (NextActivity != null) + foreach (var path in NextActivity.GetCurrentPath()) + { + yield return path; + } + + yield break; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/RAHarvesterDockSequence.cs b/OpenRA.Mods.RA/Activities/RAHarvesterDockSequence.cs index 930e480100..90981ae722 100644 --- a/OpenRA.Mods.RA/Activities/RAHarvesterDockSequence.cs +++ b/OpenRA.Mods.RA/Activities/RAHarvesterDockSequence.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.RA/Activities/Rearm.cs b/OpenRA.Mods.RA/Activities/Rearm.cs index a6ed3a3bb9..7a41f17b0d 100644 --- a/OpenRA.Mods.RA/Activities/Rearm.cs +++ b/OpenRA.Mods.RA/Activities/Rearm.cs @@ -1,46 +1,46 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - public class Rearm : CancelableActivity - { - int remainingTicks = ticksPerPip; - - const int ticksPerPip = 25 * 2; - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - var limitedAmmo = self.TraitOrDefault(); - if (limitedAmmo == null) return NextActivity; - - if (--remainingTicks == 0) - { - if (!limitedAmmo.GiveAmmo()) return NextActivity; - - var hostBuilding = self.World.FindUnits(self.CenterLocation, self.CenterLocation) - .FirstOrDefault(a => a.HasTrait()); - - if (hostBuilding != null) - hostBuilding.Trait().PlayCustomAnim(hostBuilding, "active"); - - remainingTicks = ticksPerPip; - } - - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + public class Rearm : CancelableActivity + { + int remainingTicks = ticksPerPip; + + const int ticksPerPip = 25 * 2; + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + var limitedAmmo = self.TraitOrDefault(); + if (limitedAmmo == null) return NextActivity; + + if (--remainingTicks == 0) + { + if (!limitedAmmo.GiveAmmo()) return NextActivity; + + var hostBuilding = self.World.FindUnits(self.CenterLocation, self.CenterLocation) + .FirstOrDefault(a => a.HasTrait()); + + if (hostBuilding != null) + hostBuilding.Trait().PlayCustomAnim(hostBuilding, "active"); + + remainingTicks = ticksPerPip; + } + + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/RemoveSelf.cs b/OpenRA.Mods.RA/Activities/RemoveSelf.cs index 3091ba2017..754af98b1b 100755 --- a/OpenRA.Mods.RA/Activities/RemoveSelf.cs +++ b/OpenRA.Mods.RA/Activities/RemoveSelf.cs @@ -1,25 +1,25 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - public class RemoveSelf : CancelableActivity - { - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - self.Destroy(); - return null; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + public class RemoveSelf : CancelableActivity + { + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + self.Destroy(); + return null; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Repair.cs b/OpenRA.Mods.RA/Activities/Repair.cs index f1157fb10e..2f5fe2054b 100644 --- a/OpenRA.Mods.RA/Activities/Repair.cs +++ b/OpenRA.Mods.RA/Activities/Repair.cs @@ -1,61 +1,61 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - public class Repair : CancelableActivity - { - int remainingTicks; - Actor host; - - public Repair(Actor host) { this.host = host; } - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - if (host != null && !host.IsInWorld) return NextActivity; - if (remainingTicks == 0) - { - var health = self.TraitOrDefault(); - if (health == null) return NextActivity; - - var repairsUnits = host.Info.Traits.Get(); - var unitCost = self.Info.Traits.Get().Cost; - var hpToRepair = Math.Min(repairsUnits.HpPerStep, health.MaxHP - health.HP); - var cost = (hpToRepair * unitCost * repairsUnits.ValuePercentage) / (health.MaxHP * 100); - - if (!self.Owner.PlayerActor.Trait().TakeCash(cost)) - { - remainingTicks = 1; - return this; - } - - self.InflictDamage(self, -hpToRepair, null); - if (health.DamageState == DamageState.Undamaged) - return NextActivity; - - if (host != null) - host.Trait() - .PlayCustomAnim(host, "active"); - - remainingTicks = repairsUnits.Interval; - } - else - --remainingTicks; - - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + public class Repair : CancelableActivity + { + int remainingTicks; + Actor host; + + public Repair(Actor host) { this.host = host; } + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + if (host != null && !host.IsInWorld) return NextActivity; + if (remainingTicks == 0) + { + var health = self.TraitOrDefault(); + if (health == null) return NextActivity; + + var repairsUnits = host.Info.Traits.Get(); + var unitCost = self.Info.Traits.Get().Cost; + var hpToRepair = Math.Min(repairsUnits.HpPerStep, health.MaxHP - health.HP); + var cost = (hpToRepair * unitCost * repairsUnits.ValuePercentage) / (health.MaxHP * 100); + + if (!self.Owner.PlayerActor.Trait().TakeCash(cost)) + { + remainingTicks = 1; + return this; + } + + self.InflictDamage(self, -hpToRepair, null); + if (health.DamageState == DamageState.Undamaged) + return NextActivity; + + if (host != null) + host.Trait() + .PlayCustomAnim(host, "active"); + + remainingTicks = repairsUnits.Interval; + } + else + --remainingTicks; + + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/RepairBuilding.cs b/OpenRA.Mods.RA/Activities/RepairBuilding.cs index b8f0a0f814..7395b173df 100644 --- a/OpenRA.Mods.RA/Activities/RepairBuilding.cs +++ b/OpenRA.Mods.RA/Activities/RepairBuilding.cs @@ -1,13 +1,13 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - +#endregion + using System.Linq; using OpenRA.Traits; using OpenRA.Traits.Activities; @@ -21,20 +21,20 @@ namespace OpenRA.Mods.RA.Activities public RepairBuilding(Actor target) { this.target = target; } public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity; - if( !target.Trait().OccupiedCells().Any( x => x.First == self.Location ) ) - return NextActivity; + { + if (IsCanceled) return NextActivity; + if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity; + if( !target.Trait().OccupiedCells().Any( x => x.First == self.Location ) ) + return NextActivity; var health = target.Trait(); if (health.DamageState == DamageState.Undamaged) return NextActivity; - target.InflictDamage(self, -health.MaxHP, null); + target.InflictDamage(self, -health.MaxHP, null); self.Destroy(); return this; - } + } } } diff --git a/OpenRA.Mods.RA/Activities/Teleport.cs b/OpenRA.Mods.RA/Activities/Teleport.cs index c029d82001..d5470bbb93 100755 --- a/OpenRA.Mods.RA/Activities/Teleport.cs +++ b/OpenRA.Mods.RA/Activities/Teleport.cs @@ -1,32 +1,32 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - public class Teleport : CancelableActivity - { - int2 destination; - - public Teleport(int2 destination) - { - this.destination = destination; - } - - public override IActivity Tick(Actor self) - { - self.TraitsImplementing().FirstOrDefault().SetPosition(self, destination); - return NextActivity; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + public class Teleport : CancelableActivity + { + int2 destination; + + public Teleport(int2 destination) + { + this.destination = destination; + } + + public override IActivity Tick(Actor self) + { + self.TraitsImplementing().FirstOrDefault().SetPosition(self, destination); + return NextActivity; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Transform.cs b/OpenRA.Mods.RA/Activities/Transform.cs index 5d4a15a458..e749648351 100644 --- a/OpenRA.Mods.RA/Activities/Transform.cs +++ b/OpenRA.Mods.RA/Activities/Transform.cs @@ -1,87 +1,87 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.FileFormats; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - class Transform : CancelableActivity - { - string actor = null; - int2 offset; - string[] sounds = null; - int facing; - - RenderBuilding rb; - public Transform(Actor self, string toActor, int2 offset, int facing, string[] sounds) - { - this.actor = toActor; - this.offset = offset; - this.sounds = sounds; - this.facing = facing; - rb = self.TraitOrDefault(); - } - - void DoTransform(Actor self) - { - // Hack: repeat the first frame of the make anim instead - // of flashing the full structure for a frame - if (rb != null) - rb.PlayCustomAnim(self, "make"); - - self.World.AddFrameEndTask(w => - { - var selected = w.Selection.Contains(self); - - self.Destroy(); - foreach (var s in sounds) - Sound.PlayToPlayer(self.Owner, s, self.CenterLocation); - - var init = new TypeDictionary - { - new LocationInit( self.Location + offset ), - new OwnerInit( self.Owner ), - new FacingInit( facing ), - }; - if (self.HasTrait()) - init.Add( new HealthInit( self.Trait().HPFraction )); - - var a = w.CreateActor( actor, init ); - - if (selected) - w.Selection.Add(w, a); - }); - } - - bool started = false; - public override IActivity Tick( Actor self ) - { - if (IsCanceled) return NextActivity; - if (started) return this; - - if (rb == null) - DoTransform(self); - else - { - rb.PlayCustomAnimBackwards(self, "make", () => DoTransform(self)); - - foreach (var s in self.Info.Traits.Get().SellSounds) - Sound.PlayToPlayer(self.Owner, s, self.CenterLocation); - - started = true; - } - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + class Transform : CancelableActivity + { + string actor = null; + int2 offset; + string[] sounds = null; + int facing; + + RenderBuilding rb; + public Transform(Actor self, string toActor, int2 offset, int facing, string[] sounds) + { + this.actor = toActor; + this.offset = offset; + this.sounds = sounds; + this.facing = facing; + rb = self.TraitOrDefault(); + } + + void DoTransform(Actor self) + { + // Hack: repeat the first frame of the make anim instead + // of flashing the full structure for a frame + if (rb != null) + rb.PlayCustomAnim(self, "make"); + + self.World.AddFrameEndTask(w => + { + var selected = w.Selection.Contains(self); + + self.Destroy(); + foreach (var s in sounds) + Sound.PlayToPlayer(self.Owner, s, self.CenterLocation); + + var init = new TypeDictionary + { + new LocationInit( self.Location + offset ), + new OwnerInit( self.Owner ), + new FacingInit( facing ), + }; + if (self.HasTrait()) + init.Add( new HealthInit( self.Trait().HPFraction )); + + var a = w.CreateActor( actor, init ); + + if (selected) + w.Selection.Add(w, a); + }); + } + + bool started = false; + public override IActivity Tick( Actor self ) + { + if (IsCanceled) return NextActivity; + if (started) return this; + + if (rb == null) + DoTransform(self); + else + { + rb.PlayCustomAnimBackwards(self, "make", () => DoTransform(self)); + + foreach (var s in self.Info.Traits.Get().SellSounds) + Sound.PlayToPlayer(self.Owner, s, self.CenterLocation); + + started = true; + } + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Turn.cs b/OpenRA.Mods.RA/Activities/Turn.cs index fecc089fcb..6b3fd817a2 100755 --- a/OpenRA.Mods.RA/Activities/Turn.cs +++ b/OpenRA.Mods.RA/Activities/Turn.cs @@ -1,38 +1,38 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - public class Turn : CancelableActivity - { - int desiredFacing; - - public Turn( int desiredFacing ) - { - this.desiredFacing = desiredFacing; - } - - public override IActivity Tick( Actor self ) - { - if (IsCanceled) return NextActivity; - var facing = self.Trait(); - - if( desiredFacing == facing.Facing ) - return NextActivity; - facing.Facing = Util.TickFacing(facing.Facing, desiredFacing, facing.ROT); - - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + public class Turn : CancelableActivity + { + int desiredFacing; + + public Turn( int desiredFacing ) + { + this.desiredFacing = desiredFacing; + } + + public override IActivity Tick( Actor self ) + { + if (IsCanceled) return NextActivity; + var facing = self.Trait(); + + if( desiredFacing == facing.Facing ) + return NextActivity; + facing.Facing = Util.TickFacing(facing.Facing, desiredFacing, facing.ROT); + + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/UnloadCargo.cs b/OpenRA.Mods.RA/Activities/UnloadCargo.cs index 4e5d928e7c..b541fa6a15 100644 --- a/OpenRA.Mods.RA/Activities/UnloadCargo.cs +++ b/OpenRA.Mods.RA/Activities/UnloadCargo.cs @@ -1,82 +1,82 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using System.Drawing; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Activities -{ - public class UnloadCargo : CancelableActivity - { - int2? ChooseExitTile(Actor self, Actor cargo) - { - // is anyone still hogging this tile? - if (self.World.WorldActor.Trait().GetUnitsAt(self.Location).Count() > 1) - return null; - - var mobile = cargo.Trait(); - - for (var i = -1; i < 2; i++) - for (var j = -1; j < 2; j++) - if ((i != 0 || j != 0) && - mobile.CanEnterCell(self.Location + new int2(i, j))) - return self.Location + new int2(i, j); - - return null; - } - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - - // if we're a thing that can turn, turn to the - // right facing for the unload animation - var facing = self.TraitOrDefault(); - var unloadFacing = self.Info.Traits.Get().UnloadFacing; - if (facing != null && facing.Facing != unloadFacing) - return Util.SequenceActivities( new Turn(unloadFacing), this ); - - // todo: handle the BS of open/close sequences, which are inconsistent, - // for reasons that probably make good sense to the westwood guys. - - var cargo = self.Trait(); - if (cargo.IsEmpty(self)) - return NextActivity; - - var ru = self.TraitOrDefault(); - if (ru != null) - ru.PlayCustomAnimation(self, "unload", null); - - var exitTile = ChooseExitTile(self, cargo.Peek(self)); - if (exitTile == null) - return this; - - var actor = cargo.Unload(self); - - self.World.AddFrameEndTask(w => - { - if (actor.Destroyed) return; - w.Add(actor); - - var mobile = actor.Trait(); - mobile.SetPosition(actor, self.Location); - actor.CancelActivity(); - actor.QueueActivity(mobile.MoveTo(exitTile.Value, 0)); - actor.SetTargetLine(Target.FromCell(exitTile.Value), Color.Green, false); - }); - - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using System.Drawing; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Activities +{ + public class UnloadCargo : CancelableActivity + { + int2? ChooseExitTile(Actor self, Actor cargo) + { + // is anyone still hogging this tile? + if (self.World.WorldActor.Trait().GetUnitsAt(self.Location).Count() > 1) + return null; + + var mobile = cargo.Trait(); + + for (var i = -1; i < 2; i++) + for (var j = -1; j < 2; j++) + if ((i != 0 || j != 0) && + mobile.CanEnterCell(self.Location + new int2(i, j))) + return self.Location + new int2(i, j); + + return null; + } + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + + // if we're a thing that can turn, turn to the + // right facing for the unload animation + var facing = self.TraitOrDefault(); + var unloadFacing = self.Info.Traits.Get().UnloadFacing; + if (facing != null && facing.Facing != unloadFacing) + return Util.SequenceActivities( new Turn(unloadFacing), this ); + + // todo: handle the BS of open/close sequences, which are inconsistent, + // for reasons that probably make good sense to the westwood guys. + + var cargo = self.Trait(); + if (cargo.IsEmpty(self)) + return NextActivity; + + var ru = self.TraitOrDefault(); + if (ru != null) + ru.PlayCustomAnimation(self, "unload", null); + + var exitTile = ChooseExitTile(self, cargo.Peek(self)); + if (exitTile == null) + return this; + + var actor = cargo.Unload(self); + + self.World.AddFrameEndTask(w => + { + if (actor.Destroyed) return; + w.Add(actor); + + var mobile = actor.Trait(); + mobile.SetPosition(actor, self.Location); + actor.CancelActivity(); + actor.QueueActivity(mobile.MoveTo(exitTile.Value, 0)); + actor.SetTargetLine(Target.FromCell(exitTile.Value), Color.Green, false); + }); + + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/Wait.cs b/OpenRA.Mods.RA/Activities/Wait.cs index b5e75c44b5..3edb64f184 100644 --- a/OpenRA.Mods.RA/Activities/Wait.cs +++ b/OpenRA.Mods.RA/Activities/Wait.cs @@ -1,41 +1,41 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Activities -{ - public class Wait : CancelableActivity - { - int remainingTicks; - bool interruptable = true; - - public Wait(int period) { remainingTicks = period; } - public Wait(int period, bool interruptable) - { - remainingTicks = period; - this.interruptable = interruptable; - } - - public override IActivity Tick(Actor self) - { - if (remainingTicks-- == 0) return NextActivity; - return this; - } - - protected override bool OnCancel( Actor self ) - { - if( !interruptable ) return false; - remainingTicks = 0; - return true; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Activities +{ + public class Wait : CancelableActivity + { + int remainingTicks; + bool interruptable = true; + + public Wait(int period) { remainingTicks = period; } + public Wait(int period, bool interruptable) + { + remainingTicks = period; + this.interruptable = interruptable; + } + + public override IActivity Tick(Actor self) + { + if (remainingTicks-- == 0) return NextActivity; + return this; + } + + protected override bool OnCancel( Actor self ) + { + if( !interruptable ) return false; + remainingTicks = 0; + return true; + } + } +} diff --git a/OpenRA.Mods.RA/ActorLostNotification.cs b/OpenRA.Mods.RA/ActorLostNotification.cs index 4f62c744dd..76ad520b39 100644 --- a/OpenRA.Mods.RA/ActorLostNotification.cs +++ b/OpenRA.Mods.RA/ActorLostNotification.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.RA/Air/Aircraft.cs b/OpenRA.Mods.RA/Air/Aircraft.cs index 97960610ba..87132dd7bc 100755 --- a/OpenRA.Mods.RA/Air/Aircraft.cs +++ b/OpenRA.Mods.RA/Air/Aircraft.cs @@ -1,160 +1,160 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.RA.Air -{ - public class DebugAircraftFacingInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new DebugAircraftFacing(init.self); } - } - public class DebugAircraftFacing : ISync - { - readonly Actor self; - public DebugAircraftFacing(Actor self){this.self = self;} - [Sync] public int foo { get { return self.Trait().Facing; } } - } - - public class DebugAircraftSubPxXInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new DebugAircraftSubPxX(init.self); } - } - public class DebugAircraftSubPxX : ISync - { - readonly Actor self; - public DebugAircraftSubPxX(Actor self){this.self = self;} - [Sync] public int foo { get { return self.Trait().SubPxPosition.X; } } - } - - public class DebugAircraftSubPxYInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new DebugAircraftSubPxY(init.self); } - } - public class DebugAircraftSubPxY : ISync - { - readonly Actor self; - public DebugAircraftSubPxY(Actor self){this.self = self;} - [Sync] public int foo { get { return self.Trait().SubPxPosition.Y; } } - } - - public class DebugAircraftAltitudeInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new DebugAircraftAltitude(init.self); } - } - public class DebugAircraftAltitude : ISync - { - readonly Actor self; - public DebugAircraftAltitude(Actor self){this.self = self;} - [Sync] public int Facing { get { return self.Trait().Altitude; } } - } - - public class AircraftInfo : ITraitInfo - { - public readonly int CruiseAltitude = 30; - [ActorReference] - public readonly string[] RepairBuildings = { "fix" }; - [ActorReference] - public readonly string[] RearmBuildings = { "hpad", "afld" }; - public readonly int InitialFacing = 128; - public readonly int ROT = 255; - public readonly int Speed = 1; - public readonly string[] LandableTerrainTypes = { }; - - public virtual object Create( ActorInitializer init ) { return new Aircraft( init , this ); } - } - - public class Aircraft : IMove, IFacing, IOccupySpace, ISync - { - protected readonly Actor self; - [Sync] - public int Facing { get; set; } - [Sync] - public int Altitude { get; set; } - [Sync] - public int2 SubPxPosition; - public int2 PxPosition { get { return new int2( SubPxPosition.X / 1024, SubPxPosition.Y / 1024 ); } } - public int2 TopLeft { get { return Util.CellContaining( PxPosition ); } } - - readonly AircraftInfo Info; - - public Aircraft( ActorInitializer init , AircraftInfo info) - { - this.self = init.self; - if( init.Contains() ) - this.SubPxPosition = 1024 * Util.CenterOfCell( init.Get() ); - - this.Facing = init.Contains() ? init.Get() : info.InitialFacing; - this.Altitude = init.Contains() ? init.Get() : 0; - Info = info; - } - - public int ROT { get { return Info.ROT; } } - - public int InitialFacing { get { return Info.InitialFacing; } } - - public void SetPosition(Actor self, int2 cell) - { - SetPxPosition( self, Util.CenterOfCell( cell ) ); - } - - public void SetPxPosition( Actor self, int2 px ) - { - SubPxPosition = px * 1024; - } - - public void AdjustPxPosition(Actor self, int2 px) { SetPxPosition(self, px); } - - public bool AircraftCanEnter(Actor a) - { - if( self.Owner != a.Owner ) return false; - return Info.RearmBuildings.Contains( a.Info.Name ) - || Info.RepairBuildings.Contains( a.Info.Name ); - } - - public bool CanEnterCell(int2 location) { return true; } - - public int MovementSpeed - { - get - { - decimal ret = Info.Speed; - foreach( var t in self.TraitsImplementing() ) - ret *= t.GetSpeedModifier(); - return (int)ret; - } - } - - Pair[] noCells = new Pair[] { }; - public IEnumerable> OccupiedCells() { return noCells; } - - public void TickMove( int speed, int facing ) - { - var rawspeed = speed * 7 / (32 * 1024); - SubPxPosition += rawspeed * -Util.SubPxVector[facing]; - } - - public bool CanLand(int2 cell) - { - if (!self.World.Map.IsInMap(cell)) - return false; - - if (self.World.WorldActor.Trait().AnyUnitsAt(cell)) - return false; - - var type = self.World.GetTerrainType(cell); - return Info.LandableTerrainTypes.Contains(type); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.RA.Air +{ + public class DebugAircraftFacingInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new DebugAircraftFacing(init.self); } + } + public class DebugAircraftFacing : ISync + { + readonly Actor self; + public DebugAircraftFacing(Actor self){this.self = self;} + [Sync] public int foo { get { return self.Trait().Facing; } } + } + + public class DebugAircraftSubPxXInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new DebugAircraftSubPxX(init.self); } + } + public class DebugAircraftSubPxX : ISync + { + readonly Actor self; + public DebugAircraftSubPxX(Actor self){this.self = self;} + [Sync] public int foo { get { return self.Trait().SubPxPosition.X; } } + } + + public class DebugAircraftSubPxYInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new DebugAircraftSubPxY(init.self); } + } + public class DebugAircraftSubPxY : ISync + { + readonly Actor self; + public DebugAircraftSubPxY(Actor self){this.self = self;} + [Sync] public int foo { get { return self.Trait().SubPxPosition.Y; } } + } + + public class DebugAircraftAltitudeInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new DebugAircraftAltitude(init.self); } + } + public class DebugAircraftAltitude : ISync + { + readonly Actor self; + public DebugAircraftAltitude(Actor self){this.self = self;} + [Sync] public int Facing { get { return self.Trait().Altitude; } } + } + + public class AircraftInfo : ITraitInfo + { + public readonly int CruiseAltitude = 30; + [ActorReference] + public readonly string[] RepairBuildings = { "fix" }; + [ActorReference] + public readonly string[] RearmBuildings = { "hpad", "afld" }; + public readonly int InitialFacing = 128; + public readonly int ROT = 255; + public readonly int Speed = 1; + public readonly string[] LandableTerrainTypes = { }; + + public virtual object Create( ActorInitializer init ) { return new Aircraft( init , this ); } + } + + public class Aircraft : IMove, IFacing, IOccupySpace, ISync + { + protected readonly Actor self; + [Sync] + public int Facing { get; set; } + [Sync] + public int Altitude { get; set; } + [Sync] + public int2 SubPxPosition; + public int2 PxPosition { get { return new int2( SubPxPosition.X / 1024, SubPxPosition.Y / 1024 ); } } + public int2 TopLeft { get { return Util.CellContaining( PxPosition ); } } + + readonly AircraftInfo Info; + + public Aircraft( ActorInitializer init , AircraftInfo info) + { + this.self = init.self; + if( init.Contains() ) + this.SubPxPosition = 1024 * Util.CenterOfCell( init.Get() ); + + this.Facing = init.Contains() ? init.Get() : info.InitialFacing; + this.Altitude = init.Contains() ? init.Get() : 0; + Info = info; + } + + public int ROT { get { return Info.ROT; } } + + public int InitialFacing { get { return Info.InitialFacing; } } + + public void SetPosition(Actor self, int2 cell) + { + SetPxPosition( self, Util.CenterOfCell( cell ) ); + } + + public void SetPxPosition( Actor self, int2 px ) + { + SubPxPosition = px * 1024; + } + + public void AdjustPxPosition(Actor self, int2 px) { SetPxPosition(self, px); } + + public bool AircraftCanEnter(Actor a) + { + if( self.Owner != a.Owner ) return false; + return Info.RearmBuildings.Contains( a.Info.Name ) + || Info.RepairBuildings.Contains( a.Info.Name ); + } + + public bool CanEnterCell(int2 location) { return true; } + + public int MovementSpeed + { + get + { + decimal ret = Info.Speed; + foreach( var t in self.TraitsImplementing() ) + ret *= t.GetSpeedModifier(); + return (int)ret; + } + } + + Pair[] noCells = new Pair[] { }; + public IEnumerable> OccupiedCells() { return noCells; } + + public void TickMove( int speed, int facing ) + { + var rawspeed = speed * 7 / (32 * 1024); + SubPxPosition += rawspeed * -Util.SubPxVector[facing]; + } + + public bool CanLand(int2 cell) + { + if (!self.World.Map.IsInMap(cell)) + return false; + + if (self.World.WorldActor.Trait().AnyUnitsAt(cell)) + return false; + + var type = self.World.GetTerrainType(cell); + return Info.LandableTerrainTypes.Contains(type); + } + } +} diff --git a/OpenRA.Mods.RA/Air/AttackHeli.cs b/OpenRA.Mods.RA/Air/AttackHeli.cs index 27a3b85915..4720a7dae7 100755 --- a/OpenRA.Mods.RA/Air/AttackHeli.cs +++ b/OpenRA.Mods.RA/Air/AttackHeli.cs @@ -1,30 +1,30 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Activities; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Air -{ - class AttackHeliInfo : AttackFrontalInfo - { - public override object Create(ActorInitializer init) { return new AttackHeli(init.self, this); } - } - - class AttackHeli : AttackFrontal - { - public AttackHeli(Actor self, AttackHeliInfo info) : base(self, info) { } - - public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) - { - return new HeliAttack( newTarget ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Air +{ + class AttackHeliInfo : AttackFrontalInfo + { + public override object Create(ActorInitializer init) { return new AttackHeli(init.self, this); } + } + + class AttackHeli : AttackFrontal + { + public AttackHeli(Actor self, AttackHeliInfo info) : base(self, info) { } + + public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) + { + return new HeliAttack( newTarget ); + } + } +} diff --git a/OpenRA.Mods.RA/Air/AttackPlane.cs b/OpenRA.Mods.RA/Air/AttackPlane.cs index 04933fb4ce..334fd857d9 100755 --- a/OpenRA.Mods.RA/Air/AttackPlane.cs +++ b/OpenRA.Mods.RA/Air/AttackPlane.cs @@ -1,37 +1,37 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Activities; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Air -{ - class AttackPlaneInfo : AttackFrontalInfo - { - public override object Create(ActorInitializer init) { return new AttackPlane(init.self, this); } - } - - class AttackPlane : AttackFrontal - { - public AttackPlane(Actor self, AttackPlaneInfo info) : base(self, info) { } - - public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) - { - return new FlyAttack( newTarget ); - } - - protected override bool CanAttack(Actor self, Target target) - { - // dont fire while landed - return base.CanAttack(self, target) - && self.Trait().Altitude > 0; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Air +{ + class AttackPlaneInfo : AttackFrontalInfo + { + public override object Create(ActorInitializer init) { return new AttackPlane(init.self, this); } + } + + class AttackPlane : AttackFrontal + { + public AttackPlane(Actor self, AttackPlaneInfo info) : base(self, info) { } + + public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) + { + return new FlyAttack( newTarget ); + } + + protected override bool CanAttack(Actor self, Target target) + { + // dont fire while landed + return base.CanAttack(self, target) + && self.Trait().Altitude > 0; + } + } +} diff --git a/OpenRA.Mods.RA/Air/FallsToEarth.cs b/OpenRA.Mods.RA/Air/FallsToEarth.cs index 2c63683502..a92029a418 100755 --- a/OpenRA.Mods.RA/Air/FallsToEarth.cs +++ b/OpenRA.Mods.RA/Air/FallsToEarth.cs @@ -1,81 +1,81 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Activities; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Air -{ - class FallsToEarthInfo : TraitInfo - { - [WeaponReference] - public readonly string Explosion = null; - - public readonly bool Spins = true; - public readonly bool Moves = false; - } - - class FallsToEarth : INotifyDamage - { - public void Damaged(Actor self, AttackInfo e) - { - if (self.IsDead()) - { - self.Trait().RemoveOnDeath = false; - - self.CancelActivity(); - self.QueueActivity(new FallToEarth(self, self.Info.Traits.Get())); - } - } - } - - class FallToEarth : CancelableActivity - { - int acceleration = 0; - int spin = 0; - FallsToEarthInfo info; - - public FallToEarth(Actor self, FallsToEarthInfo info) - { - this.info = info; - if (info.Spins) - acceleration = self.World.SharedRandom.Next(2) * 2 - 1; - } - - public override IActivity Tick(Actor self) - { - var aircraft = self.Trait(); - if (aircraft.Altitude <= 0) - { - if (info.Explosion != null) - Combat.DoExplosion(self, info.Explosion, self.CenterLocation, 0); - - self.Destroy(); - return null; - } - - if (info.Spins) - { - spin += acceleration; - aircraft.Facing = (aircraft.Facing + spin) % 256; - } - - if (info.Moves) - FlyUtil.Fly(self, aircraft.Altitude); - - aircraft.Altitude--; - - return this; - } - - protected override bool OnCancel(Actor self) { return false; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Air +{ + class FallsToEarthInfo : TraitInfo + { + [WeaponReference] + public readonly string Explosion = null; + + public readonly bool Spins = true; + public readonly bool Moves = false; + } + + class FallsToEarth : INotifyDamage + { + public void Damaged(Actor self, AttackInfo e) + { + if (self.IsDead()) + { + self.Trait().RemoveOnDeath = false; + + self.CancelActivity(); + self.QueueActivity(new FallToEarth(self, self.Info.Traits.Get())); + } + } + } + + class FallToEarth : CancelableActivity + { + int acceleration = 0; + int spin = 0; + FallsToEarthInfo info; + + public FallToEarth(Actor self, FallsToEarthInfo info) + { + this.info = info; + if (info.Spins) + acceleration = self.World.SharedRandom.Next(2) * 2 - 1; + } + + public override IActivity Tick(Actor self) + { + var aircraft = self.Trait(); + if (aircraft.Altitude <= 0) + { + if (info.Explosion != null) + Combat.DoExplosion(self, info.Explosion, self.CenterLocation, 0); + + self.Destroy(); + return null; + } + + if (info.Spins) + { + spin += acceleration; + aircraft.Facing = (aircraft.Facing + spin) % 256; + } + + if (info.Moves) + FlyUtil.Fly(self, aircraft.Altitude); + + aircraft.Altitude--; + + return this; + } + + protected override bool OnCancel(Actor self) { return false; } + } +} diff --git a/OpenRA.Mods.RA/Air/Fly.cs b/OpenRA.Mods.RA/Air/Fly.cs index e3a81de969..194988b3d9 100755 --- a/OpenRA.Mods.RA/Air/Fly.cs +++ b/OpenRA.Mods.RA/Air/Fly.cs @@ -1,65 +1,65 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Air -{ - public class Fly : CancelableActivity - { - public readonly int2 Pos; - - private Fly( int2 px ) { Pos = px; } - - public static Fly ToPx( int2 px ) { return new Fly( px ); } - public static Fly ToCell( int2 pos ) { return new Fly( Util.CenterOfCell( pos ) ); } - - public override IActivity Tick(Actor self) - { - var cruiseAltitude = self.Info.Traits.Get().CruiseAltitude; - - if (IsCanceled) return NextActivity; - - var d = Pos - self.CenterLocation; - if (d.LengthSquared < 50) /* close enough */ - return NextActivity; - - var aircraft = self.Trait(); - - var desiredFacing = Util.GetFacing(d, aircraft.Facing); - if (aircraft.Altitude == cruiseAltitude) - aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); - - if (aircraft.Altitude < cruiseAltitude) - ++aircraft.Altitude; - - FlyUtil.Fly(self, cruiseAltitude); - return this; - } - - public override IEnumerable GetCurrentPath() - { - yield return Pos; - } - } - - public static class FlyUtil - { - public static void Fly(Actor self, int desiredAltitude ) - { - var aircraft = self.Trait(); - aircraft.TickMove( 1024 * aircraft.MovementSpeed, aircraft.Facing ); - aircraft.Altitude += Math.Sign(desiredAltitude - aircraft.Altitude); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Air +{ + public class Fly : CancelableActivity + { + public readonly int2 Pos; + + private Fly( int2 px ) { Pos = px; } + + public static Fly ToPx( int2 px ) { return new Fly( px ); } + public static Fly ToCell( int2 pos ) { return new Fly( Util.CenterOfCell( pos ) ); } + + public override IActivity Tick(Actor self) + { + var cruiseAltitude = self.Info.Traits.Get().CruiseAltitude; + + if (IsCanceled) return NextActivity; + + var d = Pos - self.CenterLocation; + if (d.LengthSquared < 50) /* close enough */ + return NextActivity; + + var aircraft = self.Trait(); + + var desiredFacing = Util.GetFacing(d, aircraft.Facing); + if (aircraft.Altitude == cruiseAltitude) + aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); + + if (aircraft.Altitude < cruiseAltitude) + ++aircraft.Altitude; + + FlyUtil.Fly(self, cruiseAltitude); + return this; + } + + public override IEnumerable GetCurrentPath() + { + yield return Pos; + } + } + + public static class FlyUtil + { + public static void Fly(Actor self, int desiredAltitude ) + { + var aircraft = self.Trait(); + aircraft.TickMove( 1024 * aircraft.MovementSpeed, aircraft.Facing ); + aircraft.Altitude += Math.Sign(desiredAltitude - aircraft.Altitude); + } + } +} diff --git a/OpenRA.Mods.RA/Air/FlyAttack.cs b/OpenRA.Mods.RA/Air/FlyAttack.cs index ea36e5a074..00e4bd321f 100755 --- a/OpenRA.Mods.RA/Air/FlyAttack.cs +++ b/OpenRA.Mods.RA/Air/FlyAttack.cs @@ -1,71 +1,71 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Air -{ - public class FlyAttack : CancelableActivity - { - readonly Target Target; - IActivity inner; - - public FlyAttack(Target target) { Target = target; } - - public override IActivity Tick(Actor self) - { - if( !Target.IsValid ) - Cancel( self ); - var limitedAmmo = self.TraitOrDefault(); - if( limitedAmmo != null && !limitedAmmo.HasAmmo() ) - Cancel( self ); - - var attack = self.Trait(); - attack.DoAttack( self, Target ); - - if( inner == null ) - { - if( IsCanceled ) - return NextActivity; - inner = Util.SequenceActivities( - Fly.ToPx(Target.CenterLocation), - new FlyTimed(50)); - } - inner = Util.RunActivity( self, inner ); - - return this; - } - - protected override bool OnCancel( Actor self ) - { - if( inner != null ) - inner.Cancel( self ); - return base.OnCancel( self ); - } - } - - public class FlyCircle : CancelableActivity - { - int2 Target; - - public FlyCircle(int2 target) { Target = target; } - - public override IActivity Tick(Actor self) - { - if( IsCanceled ) return NextActivity; - - return Util.SequenceActivities( - Fly.ToCell(Target), - new FlyTimed(50), - this); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Air +{ + public class FlyAttack : CancelableActivity + { + readonly Target Target; + IActivity inner; + + public FlyAttack(Target target) { Target = target; } + + public override IActivity Tick(Actor self) + { + if( !Target.IsValid ) + Cancel( self ); + var limitedAmmo = self.TraitOrDefault(); + if( limitedAmmo != null && !limitedAmmo.HasAmmo() ) + Cancel( self ); + + var attack = self.Trait(); + attack.DoAttack( self, Target ); + + if( inner == null ) + { + if( IsCanceled ) + return NextActivity; + inner = Util.SequenceActivities( + Fly.ToPx(Target.CenterLocation), + new FlyTimed(50)); + } + inner = Util.RunActivity( self, inner ); + + return this; + } + + protected override bool OnCancel( Actor self ) + { + if( inner != null ) + inner.Cancel( self ); + return base.OnCancel( self ); + } + } + + public class FlyCircle : CancelableActivity + { + int2 Target; + + public FlyCircle(int2 target) { Target = target; } + + public override IActivity Tick(Actor self) + { + if( IsCanceled ) return NextActivity; + + return Util.SequenceActivities( + Fly.ToCell(Target), + new FlyTimed(50), + this); + } + } +} diff --git a/OpenRA.Mods.RA/Air/FlyTimed.cs b/OpenRA.Mods.RA/Air/FlyTimed.cs index 366d2a2888..ae093a8235 100755 --- a/OpenRA.Mods.RA/Air/FlyTimed.cs +++ b/OpenRA.Mods.RA/Air/FlyTimed.cs @@ -1,49 +1,49 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Air -{ - public class FlyTimed : CancelableActivity - { - int remainingTicks; - - public FlyTimed(int ticks) { remainingTicks = ticks; } - - public override IActivity Tick(Actor self) - { - if( IsCanceled ) return NextActivity; - var targetAltitude = self.Info.Traits.Get().CruiseAltitude; - if (remainingTicks-- == 0) return NextActivity; - FlyUtil.Fly(self, targetAltitude); - return this; - } - } - - public class FlyOffMap : CancelableActivity - { - public bool Interruptible = true; - - public override IActivity Tick(Actor self) - { - var targetAltitude = self.Info.Traits.Get().CruiseAltitude; - if (IsCanceled || !self.World.Map.IsInMap(self.Location)) return NextActivity; - FlyUtil.Fly(self, targetAltitude); - return this; - } - - protected override bool OnCancel( Actor self ) - { - return Interruptible; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Air +{ + public class FlyTimed : CancelableActivity + { + int remainingTicks; + + public FlyTimed(int ticks) { remainingTicks = ticks; } + + public override IActivity Tick(Actor self) + { + if( IsCanceled ) return NextActivity; + var targetAltitude = self.Info.Traits.Get().CruiseAltitude; + if (remainingTicks-- == 0) return NextActivity; + FlyUtil.Fly(self, targetAltitude); + return this; + } + } + + public class FlyOffMap : CancelableActivity + { + public bool Interruptible = true; + + public override IActivity Tick(Actor self) + { + var targetAltitude = self.Info.Traits.Get().CruiseAltitude; + if (IsCanceled || !self.World.Map.IsInMap(self.Location)) return NextActivity; + FlyUtil.Fly(self, targetAltitude); + return this; + } + + protected override bool OnCancel( Actor self ) + { + return Interruptible; + } + } +} diff --git a/OpenRA.Mods.RA/Air/HeliAttack.cs b/OpenRA.Mods.RA/Air/HeliAttack.cs index 93b8b57d1d..1de7b1e882 100755 --- a/OpenRA.Mods.RA/Air/HeliAttack.cs +++ b/OpenRA.Mods.RA/Air/HeliAttack.cs @@ -1,55 +1,55 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Air -{ - public class HeliAttack : CancelableActivity - { - Target target; - public HeliAttack( Target target ) { this.target = target; } - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - if (!target.IsValid) return NextActivity; - - var limitedAmmo = self.TraitOrDefault(); - if (limitedAmmo != null && !limitedAmmo.HasAmmo()) - return Util.SequenceActivities( new HeliReturn(), NextActivity ); - - var aircraft = self.Trait(); - var info = self.Info.Traits.Get(); - if (aircraft.Altitude != info.CruiseAltitude) - { - aircraft.Altitude += Math.Sign(info.CruiseAltitude - aircraft.Altitude); - return this; - } - - var attack = self.Trait(); - var range = attack.GetMaximumRange() - 1; - var dist = target.CenterLocation - self.CenterLocation; - - var desiredFacing = Util.GetFacing(dist, aircraft.Facing); - aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); - - if( !float2.WithinEpsilon( float2.Zero, dist, range * Game.CellSize ) ) - aircraft.TickMove( 1024 * aircraft.MovementSpeed, desiredFacing ); - - attack.DoAttack( self, target ); - - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Air +{ + public class HeliAttack : CancelableActivity + { + Target target; + public HeliAttack( Target target ) { this.target = target; } + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + if (!target.IsValid) return NextActivity; + + var limitedAmmo = self.TraitOrDefault(); + if (limitedAmmo != null && !limitedAmmo.HasAmmo()) + return Util.SequenceActivities( new HeliReturn(), NextActivity ); + + var aircraft = self.Trait(); + var info = self.Info.Traits.Get(); + if (aircraft.Altitude != info.CruiseAltitude) + { + aircraft.Altitude += Math.Sign(info.CruiseAltitude - aircraft.Altitude); + return this; + } + + var attack = self.Trait(); + var range = attack.GetMaximumRange() - 1; + var dist = target.CenterLocation - self.CenterLocation; + + var desiredFacing = Util.GetFacing(dist, aircraft.Facing); + aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); + + if( !float2.WithinEpsilon( float2.Zero, dist, range * Game.CellSize ) ) + aircraft.TickMove( 1024 * aircraft.MovementSpeed, desiredFacing ); + + attack.DoAttack( self, target ); + + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Air/HeliFly.cs b/OpenRA.Mods.RA/Air/HeliFly.cs index 6051b78152..808cab9a99 100755 --- a/OpenRA.Mods.RA/Air/HeliFly.cs +++ b/OpenRA.Mods.RA/Air/HeliFly.cs @@ -1,58 +1,58 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Air -{ - class HeliFly : CancelableActivity - { - public readonly int2 Dest; - public HeliFly(int2 dest) - { - Dest = dest; - } - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - - var info = self.Info.Traits.Get(); - var aircraft = self.Trait(); - - if (aircraft.Altitude != info.CruiseAltitude) - { - aircraft.Altitude += Math.Sign(info.CruiseAltitude - aircraft.Altitude); - return this; - } - - var dist = Dest - aircraft.PxPosition; - if (float2.WithinEpsilon(float2.Zero, dist, 2)) - { - aircraft.SubPxPosition = Dest * 1024; - return NextActivity; - } - - var desiredFacing = Util.GetFacing(dist, aircraft.Facing); - aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); - aircraft.TickMove( 1024 * aircraft.MovementSpeed, desiredFacing ); - - return this; - } - - public override IEnumerable GetCurrentPath() - { - yield return Dest; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Air +{ + class HeliFly : CancelableActivity + { + public readonly int2 Dest; + public HeliFly(int2 dest) + { + Dest = dest; + } + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + + var info = self.Info.Traits.Get(); + var aircraft = self.Trait(); + + if (aircraft.Altitude != info.CruiseAltitude) + { + aircraft.Altitude += Math.Sign(info.CruiseAltitude - aircraft.Altitude); + return this; + } + + var dist = Dest - aircraft.PxPosition; + if (float2.WithinEpsilon(float2.Zero, dist, 2)) + { + aircraft.SubPxPosition = Dest * 1024; + return NextActivity; + } + + var desiredFacing = Util.GetFacing(dist, aircraft.Facing); + aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); + aircraft.TickMove( 1024 * aircraft.MovementSpeed, desiredFacing ); + + return this; + } + + public override IEnumerable GetCurrentPath() + { + yield return Dest; + } + } +} diff --git a/OpenRA.Mods.RA/Air/HeliLand.cs b/OpenRA.Mods.RA/Air/HeliLand.cs index 892a91b17e..fa319b664f 100755 --- a/OpenRA.Mods.RA/Air/HeliLand.cs +++ b/OpenRA.Mods.RA/Air/HeliLand.cs @@ -1,36 +1,36 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Air -{ - class HeliLand : CancelableActivity - { - public HeliLand(bool requireSpace) { this.requireSpace = requireSpace; } - - bool requireSpace; - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - var aircraft = self.Trait(); - if (aircraft.Altitude == 0) - return NextActivity; - - if (requireSpace && !aircraft.CanLand(self.Location)) - return this; - - --aircraft.Altitude; - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Air +{ + class HeliLand : CancelableActivity + { + public HeliLand(bool requireSpace) { this.requireSpace = requireSpace; } + + bool requireSpace; + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + var aircraft = self.Trait(); + if (aircraft.Altitude == 0) + return NextActivity; + + if (requireSpace && !aircraft.CanLand(self.Location)) + return this; + + --aircraft.Altitude; + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Air/HeliReturn.cs b/OpenRA.Mods.RA/Air/HeliReturn.cs index 39951577a6..69722e2f96 100755 --- a/OpenRA.Mods.RA/Air/HeliReturn.cs +++ b/OpenRA.Mods.RA/Air/HeliReturn.cs @@ -1,56 +1,56 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Activities; - -namespace OpenRA.Mods.RA.Air -{ - public class HeliReturn : CancelableActivity - { - static Actor ChooseHelipad(Actor self) - { - var rearmBuildings = self.Info.Traits.Get().RearmBuildings; - return self.World.Queries.OwnedBy[self.Owner].FirstOrDefault( - a => rearmBuildings.Contains(a.Info.Name) && - !Reservable.IsReserved(a)); - } - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - var dest = ChooseHelipad(self); - - var initialFacing = self.Info.Traits.Get().InitialFacing; - - if (dest == null) - return Util.SequenceActivities( - new Turn(initialFacing), - new HeliLand(true), - NextActivity); - - var res = dest.TraitOrDefault(); - if (res != null) - self.Trait().reservation = res.Reserve(self); - - var exit = dest.Info.Traits.WithInterface().FirstOrDefault(); - var offset = exit != null ? exit.SpawnOffset : int2.Zero; - - return Util.SequenceActivities( - new HeliFly(dest.Trait().PxPosition + offset), - new Turn(initialFacing), - new HeliLand(false), - new Rearm(), - NextActivity); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Activities; + +namespace OpenRA.Mods.RA.Air +{ + public class HeliReturn : CancelableActivity + { + static Actor ChooseHelipad(Actor self) + { + var rearmBuildings = self.Info.Traits.Get().RearmBuildings; + return self.World.Queries.OwnedBy[self.Owner].FirstOrDefault( + a => rearmBuildings.Contains(a.Info.Name) && + !Reservable.IsReserved(a)); + } + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + var dest = ChooseHelipad(self); + + var initialFacing = self.Info.Traits.Get().InitialFacing; + + if (dest == null) + return Util.SequenceActivities( + new Turn(initialFacing), + new HeliLand(true), + NextActivity); + + var res = dest.TraitOrDefault(); + if (res != null) + self.Trait().reservation = res.Reserve(self); + + var exit = dest.Info.Traits.WithInterface().FirstOrDefault(); + var offset = exit != null ? exit.SpawnOffset : int2.Zero; + + return Util.SequenceActivities( + new HeliFly(dest.Trait().PxPosition + offset), + new Turn(initialFacing), + new HeliLand(false), + new Rearm(), + NextActivity); + } + } +} diff --git a/OpenRA.Mods.RA/Air/Helicopter.cs b/OpenRA.Mods.RA/Air/Helicopter.cs index f304d5b54c..c8e2bdda3e 100755 --- a/OpenRA.Mods.RA/Air/Helicopter.cs +++ b/OpenRA.Mods.RA/Air/Helicopter.cs @@ -1,158 +1,158 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Effects; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Air -{ - class HelicopterInfo : AircraftInfo - { - public readonly int IdealSeparation = 40; - public readonly bool LandWhenIdle = true; - - public override object Create( ActorInitializer init ) { return new Helicopter( init, this); } - } - - class Helicopter : Aircraft, ITick, IIssueOrder, IResolveOrder, IOrderVoice - { - public IDisposable reservation; - HelicopterInfo Info; - - public Helicopter( ActorInitializer init, HelicopterInfo info) : base( init, info ) - { - Info = info; - } - - public IEnumerable Orders - { - get - { - yield return new EnterOrderTargeter( "Enter", 5, false, true, - target => AircraftCanEnter( target ), target => !Reservable.IsReserved( target ) ); - - yield return new AircraftMoveOrderTargeter(); - } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "Enter" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - if( order.OrderID == "Move" ) - return new Order(order.OrderID, self, queued) { TargetLocation = Util.CellContaining(target.CenterLocation) }; - - return null; - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - return (order.OrderString == "Move" || order.OrderString == "Enter") ? "Move" : null; - } - - public void ResolveOrder(Actor self, Order order) - { - if (reservation != null) - { - reservation.Dispose(); - reservation = null; - } - - if (order.OrderString == "Move") - { - var target = order.TargetLocation.Clamp(self.World.Map.Bounds); - - self.SetTargetLine(Target.FromCell(target), Color.Green); - self.CancelActivity(); - self.QueueActivity(new HeliFly(Util.CenterOfCell(target))); - - if (Info.LandWhenIdle) - { - self.QueueActivity(new Turn(Info.InitialFacing)); - self.QueueActivity(new HeliLand(true)); - } - } - - if (order.OrderString == "Enter") - { - if (Reservable.IsReserved(order.TargetActor)) return; - var res = order.TargetActor.TraitOrDefault(); - if (res != null) - reservation = res.Reserve(self); - - var exit = order.TargetActor.Info.Traits.WithInterface().FirstOrDefault(); - var offset = exit != null ? exit.SpawnOffset : int2.Zero; - - self.SetTargetLine(Target.FromActor(order.TargetActor), Color.Green); - - self.CancelActivity(); - self.QueueActivity(new HeliFly(order.TargetActor.Trait().PxPosition + offset)); - self.QueueActivity(new Turn(Info.InitialFacing)); - self.QueueActivity(new HeliLand(false)); - self.QueueActivity(Info.RearmBuildings.Contains(order.TargetActor.Info.Name) - ? (IActivity)new Rearm() : new Repair(order.TargetActor)); - } - - if (order.OrderString == "Stop") - { - self.CancelActivity(); - - if (Info.LandWhenIdle) - { - self.QueueActivity(new Turn(Info.InitialFacing)); - self.QueueActivity(new HeliLand(true)); - } - } - } - - public void Tick(Actor self) - { - var aircraft = self.Trait(); - if (aircraft.Altitude <= 0) - return; - - var otherHelis = self.World.FindUnitsInCircle(self.CenterLocation, Info.IdealSeparation) - .Where(a => a.HasTrait()); - - var f = otherHelis - .Select(h => GetRepulseForce(self, h)) - .Aggregate(int2.Zero, (a, b) => a + b); - - int RepulsionFacing = Util.GetFacing( f, -1 ); - if( RepulsionFacing != -1 ) - aircraft.TickMove( 1024 * aircraft.MovementSpeed, RepulsionFacing ); - } - - // Returns an int2 in subPx units - public int2 GetRepulseForce(Actor self, Actor h) - { - if (self == h) - return int2.Zero; - if( h.Trait().Altitude < Altitude ) - return int2.Zero; - var d = self.CenterLocation - h.CenterLocation; - - if (d.Length > Info.IdealSeparation) - return int2.Zero; - - if (d.LengthSquared < 1) - return Util.SubPxVector[self.World.SharedRandom.Next(255)]; - return (5120 / d.LengthSquared) * d; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Effects; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Air +{ + class HelicopterInfo : AircraftInfo + { + public readonly int IdealSeparation = 40; + public readonly bool LandWhenIdle = true; + + public override object Create( ActorInitializer init ) { return new Helicopter( init, this); } + } + + class Helicopter : Aircraft, ITick, IIssueOrder, IResolveOrder, IOrderVoice + { + public IDisposable reservation; + HelicopterInfo Info; + + public Helicopter( ActorInitializer init, HelicopterInfo info) : base( init, info ) + { + Info = info; + } + + public IEnumerable Orders + { + get + { + yield return new EnterOrderTargeter( "Enter", 5, false, true, + target => AircraftCanEnter( target ), target => !Reservable.IsReserved( target ) ); + + yield return new AircraftMoveOrderTargeter(); + } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "Enter" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + if( order.OrderID == "Move" ) + return new Order(order.OrderID, self, queued) { TargetLocation = Util.CellContaining(target.CenterLocation) }; + + return null; + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return (order.OrderString == "Move" || order.OrderString == "Enter") ? "Move" : null; + } + + public void ResolveOrder(Actor self, Order order) + { + if (reservation != null) + { + reservation.Dispose(); + reservation = null; + } + + if (order.OrderString == "Move") + { + var target = order.TargetLocation.Clamp(self.World.Map.Bounds); + + self.SetTargetLine(Target.FromCell(target), Color.Green); + self.CancelActivity(); + self.QueueActivity(new HeliFly(Util.CenterOfCell(target))); + + if (Info.LandWhenIdle) + { + self.QueueActivity(new Turn(Info.InitialFacing)); + self.QueueActivity(new HeliLand(true)); + } + } + + if (order.OrderString == "Enter") + { + if (Reservable.IsReserved(order.TargetActor)) return; + var res = order.TargetActor.TraitOrDefault(); + if (res != null) + reservation = res.Reserve(self); + + var exit = order.TargetActor.Info.Traits.WithInterface().FirstOrDefault(); + var offset = exit != null ? exit.SpawnOffset : int2.Zero; + + self.SetTargetLine(Target.FromActor(order.TargetActor), Color.Green); + + self.CancelActivity(); + self.QueueActivity(new HeliFly(order.TargetActor.Trait().PxPosition + offset)); + self.QueueActivity(new Turn(Info.InitialFacing)); + self.QueueActivity(new HeliLand(false)); + self.QueueActivity(Info.RearmBuildings.Contains(order.TargetActor.Info.Name) + ? (IActivity)new Rearm() : new Repair(order.TargetActor)); + } + + if (order.OrderString == "Stop") + { + self.CancelActivity(); + + if (Info.LandWhenIdle) + { + self.QueueActivity(new Turn(Info.InitialFacing)); + self.QueueActivity(new HeliLand(true)); + } + } + } + + public void Tick(Actor self) + { + var aircraft = self.Trait(); + if (aircraft.Altitude <= 0) + return; + + var otherHelis = self.World.FindUnitsInCircle(self.CenterLocation, Info.IdealSeparation) + .Where(a => a.HasTrait()); + + var f = otherHelis + .Select(h => GetRepulseForce(self, h)) + .Aggregate(int2.Zero, (a, b) => a + b); + + int RepulsionFacing = Util.GetFacing( f, -1 ); + if( RepulsionFacing != -1 ) + aircraft.TickMove( 1024 * aircraft.MovementSpeed, RepulsionFacing ); + } + + // Returns an int2 in subPx units + public int2 GetRepulseForce(Actor self, Actor h) + { + if (self == h) + return int2.Zero; + if( h.Trait().Altitude < Altitude ) + return int2.Zero; + var d = self.CenterLocation - h.CenterLocation; + + if (d.Length > Info.IdealSeparation) + return int2.Zero; + + if (d.LengthSquared < 1) + return Util.SubPxVector[self.World.SharedRandom.Next(255)]; + return (5120 / d.LengthSquared) * d; + } + } +} diff --git a/OpenRA.Mods.RA/Air/Land.cs b/OpenRA.Mods.RA/Air/Land.cs index c72b661bd1..633292e9b3 100755 --- a/OpenRA.Mods.RA/Air/Land.cs +++ b/OpenRA.Mods.RA/Air/Land.cs @@ -1,47 +1,47 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Air -{ - public class Land : CancelableActivity - { - Target Target; - - public Land(Target t) { Target = t; } - - public override IActivity Tick(Actor self) - { - if (!Target.IsValid) - Cancel(self); - - if (IsCanceled) return NextActivity; - - var d = Target.CenterLocation - self.CenterLocation; - if (d.LengthSquared < 50) /* close enough */ - return NextActivity; - - var aircraft = self.Trait(); - - if (aircraft.Altitude > 0) - --aircraft.Altitude; - - var desiredFacing = Util.GetFacing(d, aircraft.Facing); - aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); - aircraft.TickMove( 1024 * aircraft.MovementSpeed, aircraft.Facing ); - - return this; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Air +{ + public class Land : CancelableActivity + { + Target Target; + + public Land(Target t) { Target = t; } + + public override IActivity Tick(Actor self) + { + if (!Target.IsValid) + Cancel(self); + + if (IsCanceled) return NextActivity; + + var d = Target.CenterLocation - self.CenterLocation; + if (d.LengthSquared < 50) /* close enough */ + return NextActivity; + + var aircraft = self.Trait(); + + if (aircraft.Altitude > 0) + --aircraft.Altitude; + + var desiredFacing = Util.GetFacing(d, aircraft.Facing); + aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); + aircraft.TickMove( 1024 * aircraft.MovementSpeed, aircraft.Facing ); + + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Air/Plane.cs b/OpenRA.Mods.RA/Air/Plane.cs index 2e60fc6c89..3644338c50 100755 --- a/OpenRA.Mods.RA/Air/Plane.cs +++ b/OpenRA.Mods.RA/Air/Plane.cs @@ -1,146 +1,146 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Effects; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Air -{ - public class PlaneInfo : AircraftInfo - { - public override object Create( ActorInitializer init ) { return new Plane( init, this ); } - } - - public class Plane : Aircraft, IIssueOrder, IResolveOrder, IOrderVoice, ITick - { - public IDisposable reservation; - - public Plane( ActorInitializer init, PlaneInfo info ) : base( init, info ) { } - - bool firstTick = true; - public void Tick(Actor self) - { - if (firstTick) - { - firstTick = false; - if (self.Trait().Altitude == 0) - { - /* not spawning in the air, so try to assoc. with our afld. this is a hack. */ - var res = self.World.FindUnits(self.CenterLocation, self.CenterLocation) - .Select( a => a.TraitOrDefault() ).FirstOrDefault( a => a != null ); - - if (res != null) - reservation = res.Reserve(self); - } - } - } - - public IEnumerable Orders - { - get - { - yield return new EnterOrderTargeter( "Enter", 5, false, true, - target => AircraftCanEnter( target ), target => !Reservable.IsReserved( target ) ); - - yield return new AircraftMoveOrderTargeter(); - } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "Enter" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - if( order.OrderID == "Move" ) - return new Order( order.OrderID, self, queued ) { TargetLocation = Util.CellContaining( target.CenterLocation ) }; - - return null; - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - return (order.OrderString == "Move" || order.OrderString == "Enter") ? "Move" : null; - } - - public void UnReserve() - { - if (reservation != null) - { - reservation.Dispose(); - reservation = null; - } - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "Move") - { - UnReserve(); - - var target = order.TargetLocation.Clamp(self.World.Map.Bounds); - self.SetTargetLine(Target.FromCell(target), Color.Green); - self.CancelActivity(); - self.QueueActivity(Fly.ToCell(target)); - } - - else if (order.OrderString == "Enter") - { - if (Reservable.IsReserved(order.TargetActor)) return; - - UnReserve(); - - var info = self.Info.Traits.Get(); - self.SetTargetLine(Target.FromOrder(order), Color.Green); - - self.CancelActivity(); - self.QueueActivity(new ReturnToBase(self, order.TargetActor)); - self.QueueActivity( - info.RearmBuildings.Contains(order.TargetActor.Info.Name) - ? (IActivity)new Rearm() : new Repair(order.TargetActor)); - } - else if (order.OrderString == "Stop") - { - UnReserve(); - self.CancelActivity(); - } - else - { - // Game.Debug("Unreserve due to unhandled order: {0}".F(order.OrderString)); - UnReserve(); - } - } - } - - class AircraftMoveOrderTargeter : IOrderTargeter - { - public string OrderID { get { return "Move"; } } - public int OrderPriority { get { return 4; } } - - public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - return false; - } - - public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - IsQueued = forceQueued; - cursor = self.World.Map.IsInMap(location) ? "move" : "move-blocked"; - return true; - } - public bool IsQueued { get; protected set; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Effects; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Air +{ + public class PlaneInfo : AircraftInfo + { + public override object Create( ActorInitializer init ) { return new Plane( init, this ); } + } + + public class Plane : Aircraft, IIssueOrder, IResolveOrder, IOrderVoice, ITick + { + public IDisposable reservation; + + public Plane( ActorInitializer init, PlaneInfo info ) : base( init, info ) { } + + bool firstTick = true; + public void Tick(Actor self) + { + if (firstTick) + { + firstTick = false; + if (self.Trait().Altitude == 0) + { + /* not spawning in the air, so try to assoc. with our afld. this is a hack. */ + var res = self.World.FindUnits(self.CenterLocation, self.CenterLocation) + .Select( a => a.TraitOrDefault() ).FirstOrDefault( a => a != null ); + + if (res != null) + reservation = res.Reserve(self); + } + } + } + + public IEnumerable Orders + { + get + { + yield return new EnterOrderTargeter( "Enter", 5, false, true, + target => AircraftCanEnter( target ), target => !Reservable.IsReserved( target ) ); + + yield return new AircraftMoveOrderTargeter(); + } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "Enter" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + if( order.OrderID == "Move" ) + return new Order( order.OrderID, self, queued ) { TargetLocation = Util.CellContaining( target.CenterLocation ) }; + + return null; + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return (order.OrderString == "Move" || order.OrderString == "Enter") ? "Move" : null; + } + + public void UnReserve() + { + if (reservation != null) + { + reservation.Dispose(); + reservation = null; + } + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Move") + { + UnReserve(); + + var target = order.TargetLocation.Clamp(self.World.Map.Bounds); + self.SetTargetLine(Target.FromCell(target), Color.Green); + self.CancelActivity(); + self.QueueActivity(Fly.ToCell(target)); + } + + else if (order.OrderString == "Enter") + { + if (Reservable.IsReserved(order.TargetActor)) return; + + UnReserve(); + + var info = self.Info.Traits.Get(); + self.SetTargetLine(Target.FromOrder(order), Color.Green); + + self.CancelActivity(); + self.QueueActivity(new ReturnToBase(self, order.TargetActor)); + self.QueueActivity( + info.RearmBuildings.Contains(order.TargetActor.Info.Name) + ? (IActivity)new Rearm() : new Repair(order.TargetActor)); + } + else if (order.OrderString == "Stop") + { + UnReserve(); + self.CancelActivity(); + } + else + { + // Game.Debug("Unreserve due to unhandled order: {0}".F(order.OrderString)); + UnReserve(); + } + } + } + + class AircraftMoveOrderTargeter : IOrderTargeter + { + public string OrderID { get { return "Move"; } } + public int OrderPriority { get { return 4; } } + + public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + return false; + } + + public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + IsQueued = forceQueued; + cursor = self.World.Map.IsInMap(location) ? "move" : "move-blocked"; + return true; + } + public bool IsQueued { get; protected set; } + } +} diff --git a/OpenRA.Mods.RA/Air/ReturnOnIdle.cs b/OpenRA.Mods.RA/Air/ReturnOnIdle.cs index 79230c43e2..7561749da4 100755 --- a/OpenRA.Mods.RA/Air/ReturnOnIdle.cs +++ b/OpenRA.Mods.RA/Air/ReturnOnIdle.cs @@ -1,53 +1,53 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Activities; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Air -{ - class ReturnOnIdleInfo : TraitInfo { } - - // fly home or fly-off-map behavior for idle planes - - class ReturnOnIdle : INotifyIdle - { - public void TickIdle(Actor self) - { - var altitude = self.Trait().Altitude; - if (altitude == 0) return; // we're on the ground, let's stay there. - - var airfield = ReturnToBase.ChooseAirfield(self); - if (airfield != null) - { - self.QueueActivity(new ReturnToBase(self, airfield)); - self.QueueActivity(new Rearm()); - } - else - { - //Game.Debug("Plane has nowhere to land; flying away"); - self.QueueActivity(new FlyOffMap()); - self.QueueActivity(new RemoveSelf()); - } - } - } - - class FlyAwayOnIdleInfo : TraitInfo { } - - class FlyAwayOnIdle : INotifyIdle - { - public void TickIdle(Actor self) - { - self.QueueActivity(new FlyOffMap()); - self.QueueActivity(new RemoveSelf()); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Air +{ + class ReturnOnIdleInfo : TraitInfo { } + + // fly home or fly-off-map behavior for idle planes + + class ReturnOnIdle : INotifyIdle + { + public void TickIdle(Actor self) + { + var altitude = self.Trait().Altitude; + if (altitude == 0) return; // we're on the ground, let's stay there. + + var airfield = ReturnToBase.ChooseAirfield(self); + if (airfield != null) + { + self.QueueActivity(new ReturnToBase(self, airfield)); + self.QueueActivity(new Rearm()); + } + else + { + //Game.Debug("Plane has nowhere to land; flying away"); + self.QueueActivity(new FlyOffMap()); + self.QueueActivity(new RemoveSelf()); + } + } + } + + class FlyAwayOnIdleInfo : TraitInfo { } + + class FlyAwayOnIdle : INotifyIdle + { + public void TickIdle(Actor self) + { + self.QueueActivity(new FlyOffMap()); + self.QueueActivity(new RemoveSelf()); + } + } +} diff --git a/OpenRA.Mods.RA/Air/ReturnToBase.cs b/OpenRA.Mods.RA/Air/ReturnToBase.cs index c562a9ca72..05f50dd7b1 100755 --- a/OpenRA.Mods.RA/Air/ReturnToBase.cs +++ b/OpenRA.Mods.RA/Air/ReturnToBase.cs @@ -1,103 +1,103 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA.Air -{ - public class ReturnToBase : CancelableActivity - { - bool isCalculated; - Actor dest; - - int2 w1, w2, w3; /* tangent points to turn circles */ - - public static Actor ChooseAirfield(Actor self) - { - return self.World.Queries.OwnedBy[self.Owner] - .Where(a => self.Info.Traits.Get().RearmBuildings.Contains(a.Info.Name) - && !Reservable.IsReserved(a)) - .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) - .FirstOrDefault(); - } - - void Calculate(Actor self) - { - if (dest == null) - { - dest = ChooseAirfield(self); - } - - var res = dest.TraitOrDefault(); - if (res != null) - { - var plane = self.Trait(); - plane.UnReserve(); - plane.reservation = res.Reserve(self); - } - - var landPos = dest.CenterLocation; - var aircraft = self.Trait(); - - var speed = .2f * aircraft.MovementSpeed; - - var approachStart = landPos - new float2(aircraft.Altitude * speed, 0); - var turnRadius = (128f / self.Info.Traits.Get().ROT) * speed / (float)Math.PI; - - /* work out the center points */ - var fwd = -float2.FromAngle(aircraft.Facing / 128f * (float)Math.PI); - var side = new float2(-fwd.Y, fwd.X); /* rotate */ - var sideTowardBase = new[] { side, -side } - .OrderBy(a => float2.Dot(a, self.CenterLocation - approachStart)) - .First(); - - var c1 = self.CenterLocation + turnRadius * sideTowardBase; - var c2 = approachStart + new float2(0, - turnRadius * Math.Sign(self.CenterLocation.Y - approachStart.Y)); // above or below start point - - /* work out tangent points */ - var d = c2 - c1; - var e = (turnRadius / d.Length) * d; - var f = new float2(-e.Y, e.X); /* rotate */ - - /* todo: support internal tangents, too! */ - - if (f.X > 0) f = -f; - - w1 = (c1 + f).ToInt2(); - w2 = (c2 + f).ToInt2(); - w3 = (approachStart).ToInt2(); - - isCalculated = true; - } - - public ReturnToBase(Actor self, Actor dest) - { - this.dest = dest; - } - - public override IActivity Tick(Actor self) - { - if (IsCanceled) return NextActivity; - if (!isCalculated) - Calculate(self); - - return Util.SequenceActivities( - Fly.ToPx(w1), - Fly.ToPx(w2), - Fly.ToPx(w3), - new Land(Target.FromActor(dest)), - NextActivity); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA.Air +{ + public class ReturnToBase : CancelableActivity + { + bool isCalculated; + Actor dest; + + int2 w1, w2, w3; /* tangent points to turn circles */ + + public static Actor ChooseAirfield(Actor self) + { + return self.World.Queries.OwnedBy[self.Owner] + .Where(a => self.Info.Traits.Get().RearmBuildings.Contains(a.Info.Name) + && !Reservable.IsReserved(a)) + .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) + .FirstOrDefault(); + } + + void Calculate(Actor self) + { + if (dest == null) + { + dest = ChooseAirfield(self); + } + + var res = dest.TraitOrDefault(); + if (res != null) + { + var plane = self.Trait(); + plane.UnReserve(); + plane.reservation = res.Reserve(self); + } + + var landPos = dest.CenterLocation; + var aircraft = self.Trait(); + + var speed = .2f * aircraft.MovementSpeed; + + var approachStart = landPos - new float2(aircraft.Altitude * speed, 0); + var turnRadius = (128f / self.Info.Traits.Get().ROT) * speed / (float)Math.PI; + + /* work out the center points */ + var fwd = -float2.FromAngle(aircraft.Facing / 128f * (float)Math.PI); + var side = new float2(-fwd.Y, fwd.X); /* rotate */ + var sideTowardBase = new[] { side, -side } + .OrderBy(a => float2.Dot(a, self.CenterLocation - approachStart)) + .First(); + + var c1 = self.CenterLocation + turnRadius * sideTowardBase; + var c2 = approachStart + new float2(0, + turnRadius * Math.Sign(self.CenterLocation.Y - approachStart.Y)); // above or below start point + + /* work out tangent points */ + var d = c2 - c1; + var e = (turnRadius / d.Length) * d; + var f = new float2(-e.Y, e.X); /* rotate */ + + /* todo: support internal tangents, too! */ + + if (f.X > 0) f = -f; + + w1 = (c1 + f).ToInt2(); + w2 = (c2 + f).ToInt2(); + w3 = (approachStart).ToInt2(); + + isCalculated = true; + } + + public ReturnToBase(Actor self, Actor dest) + { + this.dest = dest; + } + + public override IActivity Tick(Actor self) + { + if (IsCanceled) return NextActivity; + if (!isCalculated) + Calculate(self); + + return Util.SequenceActivities( + Fly.ToPx(w1), + Fly.ToPx(w2), + Fly.ToPx(w3), + new Land(Target.FromActor(dest)), + NextActivity); + } + } +} diff --git a/OpenRA.Mods.RA/Air/TargetableAircraft.cs b/OpenRA.Mods.RA/Air/TargetableAircraft.cs index 28d8d3211e..53eec22418 100755 --- a/OpenRA.Mods.RA/Air/TargetableAircraft.cs +++ b/OpenRA.Mods.RA/Air/TargetableAircraft.cs @@ -1,39 +1,39 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.Graphics; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Air -{ - public class TargetableAircraftInfo : TargetableUnitInfo, ITraitPrerequisite - { - public readonly string[] GroundedTargetTypes = { }; - public override object Create(ActorInitializer init) { return new TargetableAircraft(init.self, this); } - } - - public class TargetableAircraft : TargetableUnit - { - Aircraft Aircraft; - public TargetableAircraft(Actor self, TargetableAircraftInfo info) - : base(self, info) - { - Aircraft = self.Trait(); - } - - public override string[] TargetTypes - { - get { return (Aircraft.Altitude > 0) ? info.TargetTypes - : info.GroundedTargetTypes; } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.Graphics; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Air +{ + public class TargetableAircraftInfo : TargetableUnitInfo, ITraitPrerequisite + { + public readonly string[] GroundedTargetTypes = { }; + public override object Create(ActorInitializer init) { return new TargetableAircraft(init.self, this); } + } + + public class TargetableAircraft : TargetableUnit + { + Aircraft Aircraft; + public TargetableAircraft(Actor self, TargetableAircraftInfo info) + : base(self, info) + { + Aircraft = self.Trait(); + } + + public override string[] TargetTypes + { + get { return (Aircraft.Altitude > 0) ? info.TargetTypes + : info.GroundedTargetTypes; } + } + } +} diff --git a/OpenRA.Mods.RA/AppearsOnRadar.cs b/OpenRA.Mods.RA/AppearsOnRadar.cs index 49d5f74394..d5cfc7ee57 100755 --- a/OpenRA.Mods.RA/AppearsOnRadar.cs +++ b/OpenRA.Mods.RA/AppearsOnRadar.cs @@ -1,52 +1,52 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class AppearsOnRadarInfo : TraitInfo - { - public readonly bool UseLocation = false; - } - - public class AppearsOnRadar : IRadarSignature - { - AppearsOnRadarInfo info; - IOccupySpace Space; - - public IEnumerable RadarSignatureCells(Actor self) - { - if (info == null) - info = self.Info.Traits.Get(); - - if (info.UseLocation) - return new int2[] { self.Location }; - else - { - if (Space == null) - Space = self.Trait(); - return Space.OccupiedCells().Select(c => c.First); - } - } - - public Color RadarSignatureColor(Actor self) - { - var mod = self.TraitsImplementing().FirstOrDefault(); - if (mod != null) - return mod.RadarColorOverride(self); - - return self.Owner.ColorRamp.GetColor(0); - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class AppearsOnRadarInfo : TraitInfo + { + public readonly bool UseLocation = false; + } + + public class AppearsOnRadar : IRadarSignature + { + AppearsOnRadarInfo info; + IOccupySpace Space; + + public IEnumerable RadarSignatureCells(Actor self) + { + if (info == null) + info = self.Info.Traits.Get(); + + if (info.UseLocation) + return new int2[] { self.Location }; + else + { + if (Space == null) + Space = self.Trait(); + return Space.OccupiedCells().Select(c => c.First); + } + } + + public Color RadarSignatureColor(Actor self) + { + var mod = self.TraitsImplementing().FirstOrDefault(); + if (mod != null) + return mod.RadarColorOverride(self); + + return self.Owner.ColorRamp.GetColor(0); + } + } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/AttackBase.cs b/OpenRA.Mods.RA/AttackBase.cs index a31083abc9..8aa7d8c8df 100644 --- a/OpenRA.Mods.RA/AttackBase.cs +++ b/OpenRA.Mods.RA/AttackBase.cs @@ -1,284 +1,284 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public abstract class AttackBaseInfo : ITraitInfo - { - [WeaponReference] - public readonly string PrimaryWeapon = null; - [WeaponReference] - public readonly string SecondaryWeapon = null; - public readonly int Recoil = 0; - public readonly int[] PrimaryLocalOffset = { }; - public readonly int[] SecondaryLocalOffset = { }; - public readonly int[] PrimaryOffset = { 0, 0 }; - public readonly int[] SecondaryOffset = null; - public readonly bool MuzzleFlash = false; - public readonly int FireDelay = 0; - - public readonly bool AlignIdleTurrets = false; - public readonly bool CanAttackGround = true; - - public readonly float ScanTimeAverage = 2f; - public readonly float ScanTimeSpread = .5f; - - public abstract object Create(ActorInitializer init); - - public float GetMaximumRange() - { - var priRange = PrimaryWeapon != null ? Rules.Weapons[PrimaryWeapon.ToLowerInvariant()].Range : 0; - var secRange = SecondaryWeapon != null ? Rules.Weapons[SecondaryWeapon.ToLowerInvariant()].Range : 0; - - return Math.Max(priRange, secRange); - } - } - - public abstract class AttackBase : IIssueOrder, IResolveOrder, ITick, IExplodeModifier, IOrderVoice, ISync - { - [Sync] - int nextScanTime = 0; - - public bool IsAttacking { get; internal set; } - - public List Weapons = new List(); - public List Turrets = new List(); - - readonly Actor self; - - public AttackBase(Actor self) - { - this.self = self; - var info = self.Info.Traits.Get(); - - Turrets.Add(new Turret(info.PrimaryOffset)); - if (info.SecondaryOffset != null) - Turrets.Add(new Turret(info.SecondaryOffset)); - - if (info.PrimaryWeapon != null) - Weapons.Add(new Weapon(info.PrimaryWeapon, - Turrets[0], info.PrimaryLocalOffset)); - - if (info.SecondaryWeapon != null) - Weapons.Add(new Weapon(info.SecondaryWeapon, - info.SecondaryOffset != null ? Turrets[1] : Turrets[0], info.SecondaryLocalOffset)); - } - - protected virtual bool CanAttack(Actor self, Target target) - { - if (!target.IsValid) return false; - if (Weapons.All(w => w.IsReloading)) return false; - if (self.TraitsImplementing().Any(d => d.Disabled)) return false; - - if (target.IsActor && target.Actor.HasTrait() && - !target.Actor.Trait().TargetableBy(target.Actor,self)) - return false; - - return true; - } - - public bool ShouldExplode(Actor self) { return !IsReloading(); } - - public bool IsReloading() { return Weapons.Any(w => w.IsReloading); } - - List> delayedActions = new List>(); - - public virtual void Tick(Actor self) - { - --nextScanTime; - - foreach (var w in Weapons) - w.Tick(); - - for (var i = 0; i < delayedActions.Count; i++) - { - var x = delayedActions[i]; - if (--x.First <= 0) - x.Second(); - delayedActions[i] = x; - } - delayedActions.RemoveAll(a => a.First <= 0); - } - - internal void ScheduleDelayedAction(int t, Action a) - { - if (t > 0) - delayedActions.Add(Pair.New(t, a)); - else - a(); - } - - public virtual void DoAttack(Actor self, Target target) - { - if( !CanAttack( self, target ) ) return; - - var move = self.TraitOrDefault(); - var facing = self.TraitOrDefault(); - foreach (var w in Weapons) - w.CheckFire(self, this, move, facing, target); - } - - public virtual int FireDelay( Actor self, Target target, AttackBaseInfo info ) - { - return info.FireDelay; - } - - bool IsHeal { get { return Weapons[ 0 ].Info.Warheads[ 0 ].Damage < 0; } } - - public IEnumerable Orders - { - get { yield return new AttackOrderTargeter( "Attack", 6, IsHeal ); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order is AttackOrderTargeter ) - { - if( target.IsActor ) - return new Order("Attack", self, queued) { TargetActor = target.Actor }; - else - return new Order( "Attack", self, queued ) { TargetLocation = Util.CellContaining( target.CenterLocation ) }; - } - return null; - } - - public virtual void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "Attack" || order.OrderString == "AttackHold") - { - var target = Target.FromOrder(order); - self.SetTargetLine(target, Color.Red); - AttackTarget(target, order.Queued, order.OrderString == "Attack"); - } - else - { - /* hack */ - if (self.HasTrait() && self.Info.Traits.Get().AlignIdleTurrets) - self.Trait().desiredFacing = null; - } - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - return (order.OrderString == "Attack" || order.OrderString == "AttackHold") ? "Attack" : null; - } - - public abstract IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove); - - public bool HasAnyValidWeapons(Target t) { return Weapons.Any(w => w.IsValidAgainst(self.World, t)); } - public float GetMaximumRange() { return Weapons.Max(w => w.Info.Range); } - - public Weapon ChooseWeaponForTarget(Target t) { return Weapons.FirstOrDefault(w => w.IsValidAgainst(self.World, t)); } - - public void AttackTarget( Target target, bool queued, bool allowMove ) - { - if( !target.IsValid ) return; - self.QueueActivity(queued, GetAttackActivity(self, target, allowMove)); - } - - public void ScanAndAttack(Actor self, bool allowMovement, bool holdStill) - { - var targetActor = ScanForTarget(self, null); - if (targetActor != null) - AttackTarget(Target.FromActor(targetActor), false, allowMovement && !holdStill); - } - - public Actor ScanForTarget(Actor self, Actor currentTarget) - { - var range = GetMaximumRange(); - - if (self.IsIdle || currentTarget == null || !Combat.IsInRange(self.CenterLocation, range, currentTarget)) - if(nextScanTime <= 0) - return ChooseTarget(self, range); - - return currentTarget; - } - - public void ScanAndAttack(Actor self, bool allowMovement) - { - ScanAndAttack(self, allowMovement, false); - } - - Actor ChooseTarget(Actor self, float range) - { - var info = self.Info.Traits.Get(); - nextScanTime = (int)(25 * (info.ScanTimeAverage + - (self.World.SharedRandom.NextDouble() * 2 - 1) * info.ScanTimeSpread)); - - var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); - - return inRange - .Where(a => a.Owner != null && self.Owner.Stances[a.Owner] == Stance.Enemy) - .Where(a => !a.HasTrait()) - .Where(a => HasAnyValidWeapons(Target.FromActor(a))) - .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) - .FirstOrDefault(); - } - - class AttackOrderTargeter : IOrderTargeter - { - readonly bool isHeal; - - public AttackOrderTargeter( string order, int priority, bool isHeal ) - { - this.OrderID = order; - this.OrderPriority = priority; - this.isHeal = isHeal; - } - - public string OrderID { get; private set; } - public int OrderPriority { get; private set; } - - public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - IsQueued = forceQueued; - - cursor = isHeal ? "heal" : "attack"; - if( self == target ) return false; - if( !self.Trait().HasAnyValidWeapons( Target.FromActor( target ) ) ) return false; - - var playerRelationship = self.Owner.Stances[ target.Owner ]; - - if( isHeal ) - return playerRelationship == Stance.Ally || forceAttack; - - else - return playerRelationship == Stance.Enemy || forceAttack; - } - - public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - if (!self.World.Map.IsInMap(location)) - return false; - - IsQueued = forceQueued; - - cursor = isHeal ? "heal" : "attack"; - if( isHeal ) return false; - if( !self.Trait().HasAnyValidWeapons( Target.FromCell( location ) ) ) return false; - - if( forceAttack ) - if( self.Info.Traits.Get().CanAttackGround ) - return true; - - return false; - } - - public bool IsQueued { get; protected set; } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public abstract class AttackBaseInfo : ITraitInfo + { + [WeaponReference] + public readonly string PrimaryWeapon = null; + [WeaponReference] + public readonly string SecondaryWeapon = null; + public readonly int Recoil = 0; + public readonly int[] PrimaryLocalOffset = { }; + public readonly int[] SecondaryLocalOffset = { }; + public readonly int[] PrimaryOffset = { 0, 0 }; + public readonly int[] SecondaryOffset = null; + public readonly bool MuzzleFlash = false; + public readonly int FireDelay = 0; + + public readonly bool AlignIdleTurrets = false; + public readonly bool CanAttackGround = true; + + public readonly float ScanTimeAverage = 2f; + public readonly float ScanTimeSpread = .5f; + + public abstract object Create(ActorInitializer init); + + public float GetMaximumRange() + { + var priRange = PrimaryWeapon != null ? Rules.Weapons[PrimaryWeapon.ToLowerInvariant()].Range : 0; + var secRange = SecondaryWeapon != null ? Rules.Weapons[SecondaryWeapon.ToLowerInvariant()].Range : 0; + + return Math.Max(priRange, secRange); } - } -} + } + + public abstract class AttackBase : IIssueOrder, IResolveOrder, ITick, IExplodeModifier, IOrderVoice, ISync + { + [Sync] + int nextScanTime = 0; + + public bool IsAttacking { get; internal set; } + + public List Weapons = new List(); + public List Turrets = new List(); + + readonly Actor self; + + public AttackBase(Actor self) + { + this.self = self; + var info = self.Info.Traits.Get(); + + Turrets.Add(new Turret(info.PrimaryOffset)); + if (info.SecondaryOffset != null) + Turrets.Add(new Turret(info.SecondaryOffset)); + + if (info.PrimaryWeapon != null) + Weapons.Add(new Weapon(info.PrimaryWeapon, + Turrets[0], info.PrimaryLocalOffset)); + + if (info.SecondaryWeapon != null) + Weapons.Add(new Weapon(info.SecondaryWeapon, + info.SecondaryOffset != null ? Turrets[1] : Turrets[0], info.SecondaryLocalOffset)); + } + + protected virtual bool CanAttack(Actor self, Target target) + { + if (!target.IsValid) return false; + if (Weapons.All(w => w.IsReloading)) return false; + if (self.TraitsImplementing().Any(d => d.Disabled)) return false; + + if (target.IsActor && target.Actor.HasTrait() && + !target.Actor.Trait().TargetableBy(target.Actor,self)) + return false; + + return true; + } + + public bool ShouldExplode(Actor self) { return !IsReloading(); } + + public bool IsReloading() { return Weapons.Any(w => w.IsReloading); } + + List> delayedActions = new List>(); + + public virtual void Tick(Actor self) + { + --nextScanTime; + + foreach (var w in Weapons) + w.Tick(); + + for (var i = 0; i < delayedActions.Count; i++) + { + var x = delayedActions[i]; + if (--x.First <= 0) + x.Second(); + delayedActions[i] = x; + } + delayedActions.RemoveAll(a => a.First <= 0); + } + + internal void ScheduleDelayedAction(int t, Action a) + { + if (t > 0) + delayedActions.Add(Pair.New(t, a)); + else + a(); + } + + public virtual void DoAttack(Actor self, Target target) + { + if( !CanAttack( self, target ) ) return; + + var move = self.TraitOrDefault(); + var facing = self.TraitOrDefault(); + foreach (var w in Weapons) + w.CheckFire(self, this, move, facing, target); + } + + public virtual int FireDelay( Actor self, Target target, AttackBaseInfo info ) + { + return info.FireDelay; + } + + bool IsHeal { get { return Weapons[ 0 ].Info.Warheads[ 0 ].Damage < 0; } } + + public IEnumerable Orders + { + get { yield return new AttackOrderTargeter( "Attack", 6, IsHeal ); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order is AttackOrderTargeter ) + { + if( target.IsActor ) + return new Order("Attack", self, queued) { TargetActor = target.Actor }; + else + return new Order( "Attack", self, queued ) { TargetLocation = Util.CellContaining( target.CenterLocation ) }; + } + return null; + } + + public virtual void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Attack" || order.OrderString == "AttackHold") + { + var target = Target.FromOrder(order); + self.SetTargetLine(target, Color.Red); + AttackTarget(target, order.Queued, order.OrderString == "Attack"); + } + else + { + /* hack */ + if (self.HasTrait() && self.Info.Traits.Get().AlignIdleTurrets) + self.Trait().desiredFacing = null; + } + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return (order.OrderString == "Attack" || order.OrderString == "AttackHold") ? "Attack" : null; + } + + public abstract IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove); + + public bool HasAnyValidWeapons(Target t) { return Weapons.Any(w => w.IsValidAgainst(self.World, t)); } + public float GetMaximumRange() { return Weapons.Max(w => w.Info.Range); } + + public Weapon ChooseWeaponForTarget(Target t) { return Weapons.FirstOrDefault(w => w.IsValidAgainst(self.World, t)); } + + public void AttackTarget( Target target, bool queued, bool allowMove ) + { + if( !target.IsValid ) return; + self.QueueActivity(queued, GetAttackActivity(self, target, allowMove)); + } + + public void ScanAndAttack(Actor self, bool allowMovement, bool holdStill) + { + var targetActor = ScanForTarget(self, null); + if (targetActor != null) + AttackTarget(Target.FromActor(targetActor), false, allowMovement && !holdStill); + } + + public Actor ScanForTarget(Actor self, Actor currentTarget) + { + var range = GetMaximumRange(); + + if (self.IsIdle || currentTarget == null || !Combat.IsInRange(self.CenterLocation, range, currentTarget)) + if(nextScanTime <= 0) + return ChooseTarget(self, range); + + return currentTarget; + } + + public void ScanAndAttack(Actor self, bool allowMovement) + { + ScanAndAttack(self, allowMovement, false); + } + + Actor ChooseTarget(Actor self, float range) + { + var info = self.Info.Traits.Get(); + nextScanTime = (int)(25 * (info.ScanTimeAverage + + (self.World.SharedRandom.NextDouble() * 2 - 1) * info.ScanTimeSpread)); + + var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); + + return inRange + .Where(a => a.Owner != null && self.Owner.Stances[a.Owner] == Stance.Enemy) + .Where(a => !a.HasTrait()) + .Where(a => HasAnyValidWeapons(Target.FromActor(a))) + .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) + .FirstOrDefault(); + } + + class AttackOrderTargeter : IOrderTargeter + { + readonly bool isHeal; + + public AttackOrderTargeter( string order, int priority, bool isHeal ) + { + this.OrderID = order; + this.OrderPriority = priority; + this.isHeal = isHeal; + } + + public string OrderID { get; private set; } + public int OrderPriority { get; private set; } + + public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + IsQueued = forceQueued; + + cursor = isHeal ? "heal" : "attack"; + if( self == target ) return false; + if( !self.Trait().HasAnyValidWeapons( Target.FromActor( target ) ) ) return false; + + var playerRelationship = self.Owner.Stances[ target.Owner ]; + + if( isHeal ) + return playerRelationship == Stance.Ally || forceAttack; + + else + return playerRelationship == Stance.Enemy || forceAttack; + } + + public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + if (!self.World.Map.IsInMap(location)) + return false; + + IsQueued = forceQueued; + + cursor = isHeal ? "heal" : "attack"; + if( isHeal ) return false; + if( !self.Trait().HasAnyValidWeapons( Target.FromCell( location ) ) ) return false; + + if( forceAttack ) + if( self.Info.Traits.Get().CanAttackGround ) + return true; + + return false; + } + + public bool IsQueued { get; protected set; } + } + } +} diff --git a/OpenRA.Mods.RA/AttackFrontal.cs b/OpenRA.Mods.RA/AttackFrontal.cs index 78f2a47a49..9e47dba767 100644 --- a/OpenRA.Mods.RA/AttackFrontal.cs +++ b/OpenRA.Mods.RA/AttackFrontal.cs @@ -1,51 +1,51 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class AttackFrontalInfo : AttackBaseInfo - { - public readonly int FacingTolerance = 1; - - public override object Create( ActorInitializer init ) { return new AttackFrontal( init.self, this ); } - } - - public class AttackFrontal : AttackBase - { - readonly AttackFrontalInfo info; - public AttackFrontal(Actor self, AttackFrontalInfo info) - : base( self ) { this.info = info; } - - protected override bool CanAttack( Actor self, Target target ) - { - if( !base.CanAttack( self, target ) ) - return false; - - var facing = self.Trait().Facing; - var facingToTarget = Util.GetFacing(target.CenterLocation - self.CenterLocation, facing); - - if( Math.Abs( facingToTarget - facing ) % 256 > info.FacingTolerance ) - return false; - - return true; - } - - public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) - { - var weapon = ChooseWeaponForTarget(newTarget); - if( weapon == null ) - return null; - return new Activities.Attack(newTarget, Math.Max(0, (int)weapon.Info.Range), allowMove); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class AttackFrontalInfo : AttackBaseInfo + { + public readonly int FacingTolerance = 1; + + public override object Create( ActorInitializer init ) { return new AttackFrontal( init.self, this ); } + } + + public class AttackFrontal : AttackBase + { + readonly AttackFrontalInfo info; + public AttackFrontal(Actor self, AttackFrontalInfo info) + : base( self ) { this.info = info; } + + protected override bool CanAttack( Actor self, Target target ) + { + if( !base.CanAttack( self, target ) ) + return false; + + var facing = self.Trait().Facing; + var facingToTarget = Util.GetFacing(target.CenterLocation - self.CenterLocation, facing); + + if( Math.Abs( facingToTarget - facing ) % 256 > info.FacingTolerance ) + return false; + + return true; + } + + public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) + { + var weapon = ChooseWeaponForTarget(newTarget); + if( weapon == null ) + return null; + return new Activities.Attack(newTarget, Math.Max(0, (int)weapon.Info.Range), allowMove); + } + } +} diff --git a/OpenRA.Mods.RA/AttackLeap.cs b/OpenRA.Mods.RA/AttackLeap.cs index b9b93f271a..d943cb5375 100644 --- a/OpenRA.Mods.RA/AttackLeap.cs +++ b/OpenRA.Mods.RA/AttackLeap.cs @@ -1,48 +1,48 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.Mods.RA.Activities; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class AttackLeapInfo : AttackFrontalInfo - { - public override object Create(ActorInitializer init) { return new AttackLeap(init.self, this); } - } - - class AttackLeap : AttackFrontal - { - internal bool IsLeaping; - - public AttackLeap(Actor self, AttackLeapInfo info) - : base(self, info) {} - - public override void DoAttack(Actor self, Target target) - { - if( !CanAttack( self, target ) ) return; - - var weapon = Weapons[0].Info; - if( !Combat.IsInRange( self.CenterLocation, weapon.Range, target ) ) return; - - self.CancelActivity(); - self.QueueActivity(new Leap(self, target)); - } - - public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) - { - var weapon = ChooseWeaponForTarget(newTarget); - if( weapon == null ) - return null; - return new Activities.Attack(newTarget, Math.Max(0, (int)weapon.Info.Range), allowMove); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class AttackLeapInfo : AttackFrontalInfo + { + public override object Create(ActorInitializer init) { return new AttackLeap(init.self, this); } + } + + class AttackLeap : AttackFrontal + { + internal bool IsLeaping; + + public AttackLeap(Actor self, AttackLeapInfo info) + : base(self, info) {} + + public override void DoAttack(Actor self, Target target) + { + if( !CanAttack( self, target ) ) return; + + var weapon = Weapons[0].Info; + if( !Combat.IsInRange( self.CenterLocation, weapon.Range, target ) ) return; + + self.CancelActivity(); + self.QueueActivity(new Leap(self, target)); + } + + public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) + { + var weapon = ChooseWeaponForTarget(newTarget); + if( weapon == null ) + return null; + return new Activities.Attack(newTarget, Math.Max(0, (int)weapon.Info.Range), allowMove); + } + } +} diff --git a/OpenRA.Mods.RA/AttackMedic.cs b/OpenRA.Mods.RA/AttackMedic.cs index a77b65c317..d0c43a14d3 100644 --- a/OpenRA.Mods.RA/AttackMedic.cs +++ b/OpenRA.Mods.RA/AttackMedic.cs @@ -1,34 +1,34 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class AttackMedicInfo : AttackFrontalInfo - { - public override object Create( ActorInitializer init ) { return new AttackMedic( init.self, this ); } - } - - public class AttackMedic : AttackFrontal - { - public AttackMedic(Actor self, AttackMedicInfo info) - : base( self, info ) {} - - public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) - { - var weapon = ChooseWeaponForTarget(newTarget); - if( weapon == null ) - return null; - return new Activities.Heal(newTarget, Math.Max(0, (int)weapon.Info.Range), allowMove); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class AttackMedicInfo : AttackFrontalInfo + { + public override object Create( ActorInitializer init ) { return new AttackMedic( init.self, this ); } + } + + public class AttackMedic : AttackFrontal + { + public AttackMedic(Actor self, AttackMedicInfo info) + : base( self, info ) {} + + public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) + { + var weapon = ChooseWeaponForTarget(newTarget); + if( weapon == null ) + return null; + return new Activities.Heal(newTarget, Math.Max(0, (int)weapon.Info.Range), allowMove); + } + } +} diff --git a/OpenRA.Mods.RA/AttackMove.cs b/OpenRA.Mods.RA/AttackMove.cs index c050e7a33b..0b9a92779c 100644 --- a/OpenRA.Mods.RA/AttackMove.cs +++ b/OpenRA.Mods.RA/AttackMove.cs @@ -1,101 +1,101 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.Effects; -using OpenRA.Mods.RA.Move; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA -{ - class AttackMoveInfo : ITraitInfo - { - public readonly bool JustMove = false; - - public object Create(ActorInitializer init) { return new AttackMove(init.self, this); } - } - - class AttackMove : IResolveOrder, IOrderVoice, INotifyIdle, ISync - { - [Sync] public int2 _targetLocation { get { return TargetLocation.HasValue ? TargetLocation.Value : int2.Zero; } } - public int2? TargetLocation = null; - - readonly Mobile mobile; - readonly AttackMoveInfo Info; - - public AttackMove(Actor self, AttackMoveInfo info) - { - Info = info; - mobile = self.Trait(); - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - if (order.OrderString == "AttackMove") - return "AttackMove"; - return null; - } - - - void Activate(Actor self) - { - self.CancelActivity(); - self.QueueActivity(new AttackMoveActivity(mobile.MoveTo(TargetLocation.Value, 1))); - self.SetTargetLine(Target.FromCell(TargetLocation.Value), Color.Red); - } - - public void TickIdle(Actor self) - { - if (TargetLocation.HasValue) - Activate(self); - } - - public void ResolveOrder(Actor self, Order order) - { - TargetLocation = null; - if (order.OrderString == "AttackMove") - { - if (Info.JustMove) - mobile.ResolveOrder(self, new Order("Move", order)); - else - { - TargetLocation = mobile.NearestMoveableCell(order.TargetLocation); - Activate(self); - } - } - } - - class AttackMoveActivity : CancelableActivity - { - IActivity inner; - public AttackMoveActivity( IActivity inner ) { this.inner = inner; } - - public override IActivity Tick( Actor self ) - { - self.Trait().ScanAndAttack(self, true); - - if( inner == null ) - return NextActivity; - - inner = Util.RunActivity( self, inner ); - - return this; - } - - protected override bool OnCancel( Actor self ) - { - if( inner != null ) - inner.Cancel( self ); - return base.OnCancel( self ); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.Effects; +using OpenRA.Mods.RA.Move; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA +{ + class AttackMoveInfo : ITraitInfo + { + public readonly bool JustMove = false; + + public object Create(ActorInitializer init) { return new AttackMove(init.self, this); } + } + + class AttackMove : IResolveOrder, IOrderVoice, INotifyIdle, ISync + { + [Sync] public int2 _targetLocation { get { return TargetLocation.HasValue ? TargetLocation.Value : int2.Zero; } } + public int2? TargetLocation = null; + + readonly Mobile mobile; + readonly AttackMoveInfo Info; + + public AttackMove(Actor self, AttackMoveInfo info) + { + Info = info; + mobile = self.Trait(); + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + if (order.OrderString == "AttackMove") + return "AttackMove"; + return null; + } + + + void Activate(Actor self) + { + self.CancelActivity(); + self.QueueActivity(new AttackMoveActivity(mobile.MoveTo(TargetLocation.Value, 1))); + self.SetTargetLine(Target.FromCell(TargetLocation.Value), Color.Red); + } + + public void TickIdle(Actor self) + { + if (TargetLocation.HasValue) + Activate(self); + } + + public void ResolveOrder(Actor self, Order order) + { + TargetLocation = null; + if (order.OrderString == "AttackMove") + { + if (Info.JustMove) + mobile.ResolveOrder(self, new Order("Move", order)); + else + { + TargetLocation = mobile.NearestMoveableCell(order.TargetLocation); + Activate(self); + } + } + } + + class AttackMoveActivity : CancelableActivity + { + IActivity inner; + public AttackMoveActivity( IActivity inner ) { this.inner = inner; } + + public override IActivity Tick( Actor self ) + { + self.Trait().ScanAndAttack(self, true); + + if( inner == null ) + return NextActivity; + + inner = Util.RunActivity( self, inner ); + + return this; + } + + protected override bool OnCancel( Actor self ) + { + if( inner != null ) + inner.Cancel( self ); + return base.OnCancel( self ); + } + } + } +} diff --git a/OpenRA.Mods.RA/AttackOmni.cs b/OpenRA.Mods.RA/AttackOmni.cs index 8c5497c423..de1e228e50 100644 --- a/OpenRA.Mods.RA/AttackOmni.cs +++ b/OpenRA.Mods.RA/AttackOmni.cs @@ -1,55 +1,55 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA -{ - class AttackOmniInfo : AttackBaseInfo - { - public override object Create(ActorInitializer init) { return new AttackOmni(init.self); } - } - - class AttackOmni : AttackBase, INotifyBuildComplete - { - bool buildComplete = false; - public void BuildingComplete(Actor self) { buildComplete = true; } - - public AttackOmni(Actor self) : base(self) { } - - protected override bool CanAttack( Actor self, Target target ) - { - var isBuilding = ( self.HasTrait() && !buildComplete ); - return base.CanAttack( self, target ) && !isBuilding; - } - - public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) - { - return new SetTarget( newTarget ); - } - - class SetTarget : CancelableActivity - { - readonly Target target; - public SetTarget( Target target ) { this.target = target; } - - public override IActivity Tick( Actor self ) - { - if( IsCanceled || !target.IsValid ) - return NextActivity; - - self.Trait().DoAttack(self, target); - return this; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA +{ + class AttackOmniInfo : AttackBaseInfo + { + public override object Create(ActorInitializer init) { return new AttackOmni(init.self); } + } + + class AttackOmni : AttackBase, INotifyBuildComplete + { + bool buildComplete = false; + public void BuildingComplete(Actor self) { buildComplete = true; } + + public AttackOmni(Actor self) : base(self) { } + + protected override bool CanAttack( Actor self, Target target ) + { + var isBuilding = ( self.HasTrait() && !buildComplete ); + return base.CanAttack( self, target ) && !isBuilding; + } + + public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) + { + return new SetTarget( newTarget ); + } + + class SetTarget : CancelableActivity + { + readonly Target target; + public SetTarget( Target target ) { this.target = target; } + + public override IActivity Tick( Actor self ) + { + if( IsCanceled || !target.IsValid ) + return NextActivity; + + self.Trait().DoAttack(self, target); + return this; + } + } + } +} diff --git a/OpenRA.Mods.RA/AttackTesla.cs b/OpenRA.Mods.RA/AttackTesla.cs index 54111076fa..46747fe165 100644 --- a/OpenRA.Mods.RA/AttackTesla.cs +++ b/OpenRA.Mods.RA/AttackTesla.cs @@ -1,91 +1,91 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA -{ - class AttackTeslaInfo : AttackOmniInfo - { - public readonly int MaxCharges = 3; - public readonly int ReloadTime = 120; - public override object Create(ActorInitializer init) { return new AttackTesla(init.self); } - } - - class AttackTesla : AttackOmni, ITick, INotifyAttack - { - int charges; - int timeToRecharge; - - public AttackTesla( Actor self ) - : base( self ) - { - charges = self.Info.Traits.Get().MaxCharges; - } - - public override void Tick( Actor self ) - { - if( --timeToRecharge <= 0 ) - charges = self.Info.Traits.Get().MaxCharges; - - base.Tick( self ); - } - - public void Attacking(Actor self, Target target) - { - --charges; - timeToRecharge = self.Info.Traits.Get().ReloadTime; - } - - public override IActivity GetAttackActivity( Actor self, Target newTarget, bool allowMove ) - { - return new TeslaAttack( newTarget ); - } - - class TeslaAttack : CancelableActivity - { - readonly Target target; - public TeslaAttack( Target target ) { this.target = target; } - - public override IActivity Tick( Actor self ) - { - if( IsCanceled || !target.IsValid ) return NextActivity; - - var attack = self.Trait(); - if( attack.charges == 0 || !attack.CanAttack( self, target ) ) - return this; - - self.Trait().PlayCharge(self); - return Util.SequenceActivities( new Wait( 8 ), new TeslaZap( target ), this ); - } - } - - class TeslaZap : CancelableActivity - { - readonly Target target; - public TeslaZap( Target target ) { this.target = target; } - - public override IActivity Tick( Actor self ) - { - if( IsCanceled || !target.IsValid ) return NextActivity; - - var attack = self.Trait(); - if( attack.charges == 0 ) return NextActivity; - - attack.DoAttack( self, target ); - - return Util.SequenceActivities( new Wait( 3 ), this ); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA +{ + class AttackTeslaInfo : AttackOmniInfo + { + public readonly int MaxCharges = 3; + public readonly int ReloadTime = 120; + public override object Create(ActorInitializer init) { return new AttackTesla(init.self); } + } + + class AttackTesla : AttackOmni, ITick, INotifyAttack + { + int charges; + int timeToRecharge; + + public AttackTesla( Actor self ) + : base( self ) + { + charges = self.Info.Traits.Get().MaxCharges; + } + + public override void Tick( Actor self ) + { + if( --timeToRecharge <= 0 ) + charges = self.Info.Traits.Get().MaxCharges; + + base.Tick( self ); + } + + public void Attacking(Actor self, Target target) + { + --charges; + timeToRecharge = self.Info.Traits.Get().ReloadTime; + } + + public override IActivity GetAttackActivity( Actor self, Target newTarget, bool allowMove ) + { + return new TeslaAttack( newTarget ); + } + + class TeslaAttack : CancelableActivity + { + readonly Target target; + public TeslaAttack( Target target ) { this.target = target; } + + public override IActivity Tick( Actor self ) + { + if( IsCanceled || !target.IsValid ) return NextActivity; + + var attack = self.Trait(); + if( attack.charges == 0 || !attack.CanAttack( self, target ) ) + return this; + + self.Trait().PlayCharge(self); + return Util.SequenceActivities( new Wait( 8 ), new TeslaZap( target ), this ); + } + } + + class TeslaZap : CancelableActivity + { + readonly Target target; + public TeslaZap( Target target ) { this.target = target; } + + public override IActivity Tick( Actor self ) + { + if( IsCanceled || !target.IsValid ) return NextActivity; + + var attack = self.Trait(); + if( attack.charges == 0 ) return NextActivity; + + attack.DoAttack( self, target ); + + return Util.SequenceActivities( new Wait( 3 ), this ); + } + } + } +} diff --git a/OpenRA.Mods.RA/AttackTurreted.cs b/OpenRA.Mods.RA/AttackTurreted.cs index 0322fd0a29..68650be6b0 100644 --- a/OpenRA.Mods.RA/AttackTurreted.cs +++ b/OpenRA.Mods.RA/AttackTurreted.cs @@ -1,95 +1,95 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Move; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA -{ - class AttackTurretedInfo : AttackBaseInfo - { - public override object Create(ActorInitializer init) { return new AttackTurreted( init.self ); } - } - - class AttackTurreted : AttackBase, INotifyBuildComplete - { - protected Target target; - public AttackTurreted(Actor self) : base(self) { } - - protected override bool CanAttack( Actor self, Target target ) - { - if( self.HasTrait() && !buildComplete ) - return false; - - if (!target.IsValid) return false; - var turreted = self.Trait(); - turreted.desiredFacing = Util.GetFacing( target.CenterLocation - self.CenterLocation, turreted.turretFacing ); - if( turreted.desiredFacing != turreted.turretFacing ) - return false; - - return base.CanAttack( self, target ); - } - - public override void Tick(Actor self) - { - base.Tick(self); - DoAttack( self, target ); - } - - public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) - { - return new AttackActivity( newTarget ); - } - - public override void ResolveOrder(Actor self, Order order) - { - base.ResolveOrder(self, order); - - if (order.OrderString == "Stop") - target = Target.None; - } - - bool buildComplete = false; - public void BuildingComplete(Actor self) { buildComplete = true; } - - class AttackActivity : CancelableActivity - { - readonly Target target; - public AttackActivity( Target newTarget ) { this.target = newTarget; } - - public override IActivity Tick( Actor self ) - { - if( IsCanceled || !target.IsValid ) return NextActivity; - - if (self.TraitsImplementing().Any(d => d.Disabled)) - return this; - - var attack = self.Trait(); - const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ - var weapon = attack.ChooseWeaponForTarget(target); - if (weapon != null) - { - attack.target = target; - - if (self.HasTrait() && !self.Info.Traits.Get().OnRails) - return Util.SequenceActivities( - new Follow( target, Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ), - this ); - } - return NextActivity; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Move; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA +{ + class AttackTurretedInfo : AttackBaseInfo + { + public override object Create(ActorInitializer init) { return new AttackTurreted( init.self ); } + } + + class AttackTurreted : AttackBase, INotifyBuildComplete + { + protected Target target; + public AttackTurreted(Actor self) : base(self) { } + + protected override bool CanAttack( Actor self, Target target ) + { + if( self.HasTrait() && !buildComplete ) + return false; + + if (!target.IsValid) return false; + var turreted = self.Trait(); + turreted.desiredFacing = Util.GetFacing( target.CenterLocation - self.CenterLocation, turreted.turretFacing ); + if( turreted.desiredFacing != turreted.turretFacing ) + return false; + + return base.CanAttack( self, target ); + } + + public override void Tick(Actor self) + { + base.Tick(self); + DoAttack( self, target ); + } + + public override IActivity GetAttackActivity(Actor self, Target newTarget, bool allowMove) + { + return new AttackActivity( newTarget ); + } + + public override void ResolveOrder(Actor self, Order order) + { + base.ResolveOrder(self, order); + + if (order.OrderString == "Stop") + target = Target.None; + } + + bool buildComplete = false; + public void BuildingComplete(Actor self) { buildComplete = true; } + + class AttackActivity : CancelableActivity + { + readonly Target target; + public AttackActivity( Target newTarget ) { this.target = newTarget; } + + public override IActivity Tick( Actor self ) + { + if( IsCanceled || !target.IsValid ) return NextActivity; + + if (self.TraitsImplementing().Any(d => d.Disabled)) + return this; + + var attack = self.Trait(); + const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ + var weapon = attack.ChooseWeaponForTarget(target); + if (weapon != null) + { + attack.target = target; + + if (self.HasTrait() && !self.Info.Traits.Get().OnRails) + return Util.SequenceActivities( + new Follow( target, Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ), + this ); + } + return NextActivity; + } + } + } +} diff --git a/OpenRA.Mods.RA/AttackWander.cs b/OpenRA.Mods.RA/AttackWander.cs index 1e71ec79d0..4920d44f0a 100644 --- a/OpenRA.Mods.RA/AttackWander.cs +++ b/OpenRA.Mods.RA/AttackWander.cs @@ -1,39 +1,39 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using System.Drawing; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA -{ - class AttackWanderInfo : ITraitInfo - { - public readonly int MoveRadius = 4; - - public object Create(ActorInitializer init) { return new AttackWander(init.self, this); } - } - - class AttackWander : INotifyIdle - { - readonly AttackWanderInfo Info; - public AttackWander(Actor self, AttackWanderInfo info) - { - Info = info; - } - - public void TickIdle(Actor self) - { - var target = Util.SubPxVector[self.World.SharedRandom.Next(255)]* Info.MoveRadius / 1024 + self.Location; - self.Trait().ResolveOrder(self, new Order("AttackMove", self, false) { TargetLocation = target }); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using System.Drawing; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA +{ + class AttackWanderInfo : ITraitInfo + { + public readonly int MoveRadius = 4; + + public object Create(ActorInitializer init) { return new AttackWander(init.self, this); } + } + + class AttackWander : INotifyIdle + { + readonly AttackWanderInfo Info; + public AttackWander(Actor self, AttackWanderInfo info) + { + Info = info; + } + + public void TickIdle(Actor self) + { + var target = Util.SubPxVector[self.World.SharedRandom.Next(255)]* Info.MoveRadius / 1024 + self.Location; + self.Trait().ResolveOrder(self, new Order("AttackMove", self, false) { TargetLocation = target }); + } + } +} diff --git a/OpenRA.Mods.RA/AutoHeal.cs b/OpenRA.Mods.RA/AutoHeal.cs index 5cdacc509a..02288d8d31 100644 --- a/OpenRA.Mods.RA/AutoHeal.cs +++ b/OpenRA.Mods.RA/AutoHeal.cs @@ -1,38 +1,38 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; -using OpenRA.Traits.Activities; - -namespace OpenRA.Mods.RA -{ - class AutoHealInfo : TraitInfo { } - - class AutoHeal : INotifyIdle - { - public void TickIdle( Actor self ) - { - var attack = self.Trait(); - var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * attack.GetMaximumRange()); - - var target = inRange - .Where(a => a != self && self.Owner.Stances[a.Owner] == Stance.Ally) - .Where(a => a.IsInWorld && !a.IsDead()) - .Where(a => a.HasTrait() && a.GetDamageState() > DamageState.Undamaged) - .Where(a => attack.HasAnyValidWeapons(Target.FromActor(a))) - .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) - .FirstOrDefault(); - - if( target != null ) - self.QueueActivity(self.Trait().GetAttackActivity(self, Target.FromActor( target ), false )); - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; +using OpenRA.Traits.Activities; + +namespace OpenRA.Mods.RA +{ + class AutoHealInfo : TraitInfo { } + + class AutoHeal : INotifyIdle + { + public void TickIdle( Actor self ) + { + var attack = self.Trait(); + var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * attack.GetMaximumRange()); + + var target = inRange + .Where(a => a != self && self.Owner.Stances[a.Owner] == Stance.Ally) + .Where(a => a.IsInWorld && !a.IsDead()) + .Where(a => a.HasTrait() && a.GetDamageState() > DamageState.Undamaged) + .Where(a => attack.HasAnyValidWeapons(Target.FromActor(a))) + .OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared) + .FirstOrDefault(); + + if( target != null ) + self.QueueActivity(self.Trait().GetAttackActivity(self, Target.FromActor( target ), false )); + } + } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/AutoTarget.cs b/OpenRA.Mods.RA/AutoTarget.cs index 8cd225760e..b95e307b41 100644 --- a/OpenRA.Mods.RA/AutoTarget.cs +++ b/OpenRA.Mods.RA/AutoTarget.cs @@ -1,57 +1,57 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using System.Drawing; - -namespace OpenRA.Mods.RA -{ - class AutoTargetInfo : TraitInfo - { - public readonly bool AllowMovement = true; - } - - class AutoTarget : INotifyIdle, INotifyDamage - { - public void Damaged(Actor self, AttackInfo e) - { - if (!self.IsIdle) return; - if (e.Attacker.Destroyed) return; - - // not a lot we can do about things we can't hurt... although maybe we should automatically run away? - var attack = self.Trait(); - if (!attack.HasAnyValidWeapons(Target.FromActor(e.Attacker))) return; - - // don't retaliate against own units force-firing on us. it's usually not what the player wanted. - if (self.Owner.Stances[e.Attacker.Owner] == Stance.Ally) return; - - if (e.Damage < 0) return; // don't retaliate against healers - - self.Trait().AttackTarget(Target.FromActor(e.Attacker), false, self.Info.Traits.Get().AllowMovement); - } - - public void TickIdle(Actor self) - { - var attack = self.Trait(); - var target = attack.ScanForTarget(self, null); - if (target != null) - { - self.SetTargetLine(Target.FromActor(target), Color.Red, false); - self.QueueActivity(attack.GetAttackActivity(self, - Target.FromActor(target), - self.Info.Traits.Get().AllowMovement)); - } - } - } - - class AutoTargetIgnoreInfo : TraitInfo { } - class AutoTargetIgnore { } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using System.Drawing; + +namespace OpenRA.Mods.RA +{ + class AutoTargetInfo : TraitInfo + { + public readonly bool AllowMovement = true; + } + + class AutoTarget : INotifyIdle, INotifyDamage + { + public void Damaged(Actor self, AttackInfo e) + { + if (!self.IsIdle) return; + if (e.Attacker.Destroyed) return; + + // not a lot we can do about things we can't hurt... although maybe we should automatically run away? + var attack = self.Trait(); + if (!attack.HasAnyValidWeapons(Target.FromActor(e.Attacker))) return; + + // don't retaliate against own units force-firing on us. it's usually not what the player wanted. + if (self.Owner.Stances[e.Attacker.Owner] == Stance.Ally) return; + + if (e.Damage < 0) return; // don't retaliate against healers + + self.Trait().AttackTarget(Target.FromActor(e.Attacker), false, self.Info.Traits.Get().AllowMovement); + } + + public void TickIdle(Actor self) + { + var attack = self.Trait(); + var target = attack.ScanForTarget(self, null); + if (target != null) + { + self.SetTargetLine(Target.FromActor(target), Color.Red, false); + self.QueueActivity(attack.GetAttackActivity(self, + Target.FromActor(target), + self.Info.Traits.Get().AllowMovement)); + } + } + } + + class AutoTargetIgnoreInfo : TraitInfo { } + class AutoTargetIgnore { } +} diff --git a/OpenRA.Mods.RA/BelowUnits.cs b/OpenRA.Mods.RA/BelowUnits.cs index 6f3698cb5c..e39597e5a2 100644 --- a/OpenRA.Mods.RA/BelowUnits.cs +++ b/OpenRA.Mods.RA/BelowUnits.cs @@ -1,26 +1,26 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class BelowUnitsInfo : TraitInfo { } - - class BelowUnits : IRenderModifier - { - public IEnumerable ModifyRender(Actor self, IEnumerable r) - { - return r.Select(a => a.WithZOffset((int) -a.Sprite.size.Y)); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class BelowUnitsInfo : TraitInfo { } + + class BelowUnits : IRenderModifier + { + public IEnumerable ModifyRender(Actor self, IEnumerable r) + { + return r.Select(a => a.WithZOffset((int) -a.Sprite.size.Y)); + } + } +} diff --git a/OpenRA.Mods.RA/Bridge.cs b/OpenRA.Mods.RA/Bridge.cs index 0cd5af6c48..0bf67b3c92 100644 --- a/OpenRA.Mods.RA/Bridge.cs +++ b/OpenRA.Mods.RA/Bridge.cs @@ -1,205 +1,205 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class BridgeInfo : ITraitInfo, ITraitPrerequisite - { - public readonly bool Long = false; - - #pragma warning disable 0649 - public readonly ushort Template; - public readonly ushort DamagedTemplate; - public readonly ushort DestroyedTemplate; - - // For long bridges - public readonly ushort DestroyedPlusNorthTemplate; - public readonly ushort DestroyedPlusSouthTemplate; - public readonly ushort DestroyedPlusBothTemplate; - #pragma warning restore 0649 - public readonly string[] ShorePieces = {"br1", "br2"}; - public readonly int[] NorthOffset = null; - public readonly int[] SouthOffset = null; - - public object Create(ActorInitializer init) { return new Bridge(init.self, this); } - - public IEnumerable> Templates - { - get - { - if (Template != 0) - yield return Pair.New(Template, 1f); - - if (DamagedTemplate != 0) - yield return Pair.New(DamagedTemplate, .5f); - - if (DestroyedTemplate != 0) - yield return Pair.New(DestroyedTemplate, 0f); - - if (DestroyedPlusNorthTemplate != 0) - yield return Pair.New(DestroyedPlusNorthTemplate, 0f); - - if (DestroyedPlusSouthTemplate != 0) - yield return Pair.New(DestroyedPlusSouthTemplate, 0f); - - if (DestroyedPlusBothTemplate != 0) - yield return Pair.New(DestroyedPlusBothTemplate, 0f); - } - } - } - - class Bridge: IRenderAsTerrain, INotifyDamage - { - static string cachedTileset; - static Cache, Sprite> sprites; - - Dictionary> TileSprites = new Dictionary>(); - Dictionary Templates = new Dictionary(); - ushort currentTemplate; - - Actor self; - BridgeInfo Info; - public string Type; - Bridge northNeighbour, southNeighbour; - Health Health; - - public Bridge(Actor self, BridgeInfo info) - { - this.self = self; - Health = self.Trait(); - Health.RemoveOnDeath = false; - this.Info = info; - this.Type = self.Info.Name; - } - - public void Create(ushort template, Dictionary subtiles) - { - currentTemplate = template; - - // Create a new cache to store the tile data - if (cachedTileset != self.World.Map.Tileset) - { - cachedTileset = self.World.Map.Tileset; - sprites = new Cache, Sprite>( - x => Game.modData.SheetBuilder.Add(self.World.TileSet.GetBytes(x), - new Size(Game.CellSize, Game.CellSize))); - } - - // Cache templates and tiles for the different states - foreach (var t in Info.Templates) - { - Templates.Add(t.First,self.World.TileSet.Templates[t.First]); - TileSprites.Add(t.First,subtiles.ToDictionary( - a => a.Key, - a => sprites[new TileReference(t.First, (byte)a.Value)])); - } - } - - public string GetTerrainType(int2 cell) - { - var dx = cell - self.Location; - var index = dx.X + Templates[currentTemplate].Size.X*dx.Y; - return self.World.TileSet.GetTerrainType(new TileReference(currentTemplate,(byte)index)); - } - - public void LinkNeighbouringBridges(World world, BridgeLayer bridges) - { - // go looking for our neighbors if this is a long bridge. - if (Info.NorthOffset != null) - northNeighbour = GetNeighbor(Info.NorthOffset, bridges); - if (Info.SouthOffset != null) - southNeighbour = GetNeighbor(Info.SouthOffset, bridges); - } - - public Bridge GetNeighbor(int[] offset, BridgeLayer bridges) - { - if (offset == null) return null; - return bridges.GetBridge(self.Location + new int2(offset[0], offset[1])); - } - - public IEnumerable RenderAsTerrain(Actor self) - { - foreach (var t in TileSprites[currentTemplate]) - yield return new Renderable(t.Value, Game.CellSize * t.Key, "terrain", Game.CellSize * t.Key.Y); - } - - bool IsIntact(Bridge b) - { - return b != null && !b.self.IsDead(); - } - - void KillUnitsOnBridge() - { - var uim = self.World.WorldActor.Trait(); - - foreach (var c in TileSprites[currentTemplate].Keys) - foreach (var a in uim.GetUnitsAt(c)) - if (a.HasTrait() && !a.Trait().CanEnterCell(c)) - a.Kill(self); - } - - bool dead = false; - void UpdateState() - { - // If this is a long bridge next to a destroyed shore piece, we need die to give clean edges to the break - if (Info.Long && Health.DamageState != DamageState.Dead && - ((southNeighbour != null && Info.ShorePieces.Contains(southNeighbour.Type) && !IsIntact(southNeighbour)) || - (northNeighbour != null && Info.ShorePieces.Contains(northNeighbour.Type) && !IsIntact(northNeighbour)))) - { - self.Kill(self); // this changes the damagestate - } - - var ds = Health.DamageState; - currentTemplate = (ds == DamageState.Dead && Info.DestroyedTemplate > 0) ? Info.DestroyedTemplate : - (ds >= DamageState.Heavy && Info.DamagedTemplate > 0) ? Info.DamagedTemplate : Info.Template; - - if (Info.Long && ds == DamageState.Dead) - { - // Long bridges have custom art for multiple segments being destroyed - bool waterToSouth = !IsIntact(southNeighbour); - bool waterToNorth = !IsIntact(northNeighbour); - - if (waterToSouth && waterToNorth) - currentTemplate = Info.DestroyedPlusBothTemplate; - else if (waterToNorth) - currentTemplate = Info.DestroyedPlusNorthTemplate; - else if (waterToSouth) - currentTemplate = Info.DestroyedPlusSouthTemplate; - } - - if (ds == DamageState.Dead && !dead) - { - dead = true; - KillUnitsOnBridge(); - } - - // Update map - foreach (var c in TileSprites[currentTemplate].Keys) - self.World.Map.CustomTerrain[c.X, c.Y] = GetTerrainType(c); - } - - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageStateChanged) - { - UpdateState(); - if (northNeighbour != null) northNeighbour.UpdateState(); - if (southNeighbour != null) southNeighbour.UpdateState(); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class BridgeInfo : ITraitInfo, ITraitPrerequisite + { + public readonly bool Long = false; + + #pragma warning disable 0649 + public readonly ushort Template; + public readonly ushort DamagedTemplate; + public readonly ushort DestroyedTemplate; + + // For long bridges + public readonly ushort DestroyedPlusNorthTemplate; + public readonly ushort DestroyedPlusSouthTemplate; + public readonly ushort DestroyedPlusBothTemplate; + #pragma warning restore 0649 + public readonly string[] ShorePieces = {"br1", "br2"}; + public readonly int[] NorthOffset = null; + public readonly int[] SouthOffset = null; + + public object Create(ActorInitializer init) { return new Bridge(init.self, this); } + + public IEnumerable> Templates + { + get + { + if (Template != 0) + yield return Pair.New(Template, 1f); + + if (DamagedTemplate != 0) + yield return Pair.New(DamagedTemplate, .5f); + + if (DestroyedTemplate != 0) + yield return Pair.New(DestroyedTemplate, 0f); + + if (DestroyedPlusNorthTemplate != 0) + yield return Pair.New(DestroyedPlusNorthTemplate, 0f); + + if (DestroyedPlusSouthTemplate != 0) + yield return Pair.New(DestroyedPlusSouthTemplate, 0f); + + if (DestroyedPlusBothTemplate != 0) + yield return Pair.New(DestroyedPlusBothTemplate, 0f); + } + } + } + + class Bridge: IRenderAsTerrain, INotifyDamage + { + static string cachedTileset; + static Cache, Sprite> sprites; + + Dictionary> TileSprites = new Dictionary>(); + Dictionary Templates = new Dictionary(); + ushort currentTemplate; + + Actor self; + BridgeInfo Info; + public string Type; + Bridge northNeighbour, southNeighbour; + Health Health; + + public Bridge(Actor self, BridgeInfo info) + { + this.self = self; + Health = self.Trait(); + Health.RemoveOnDeath = false; + this.Info = info; + this.Type = self.Info.Name; + } + + public void Create(ushort template, Dictionary subtiles) + { + currentTemplate = template; + + // Create a new cache to store the tile data + if (cachedTileset != self.World.Map.Tileset) + { + cachedTileset = self.World.Map.Tileset; + sprites = new Cache, Sprite>( + x => Game.modData.SheetBuilder.Add(self.World.TileSet.GetBytes(x), + new Size(Game.CellSize, Game.CellSize))); + } + + // Cache templates and tiles for the different states + foreach (var t in Info.Templates) + { + Templates.Add(t.First,self.World.TileSet.Templates[t.First]); + TileSprites.Add(t.First,subtiles.ToDictionary( + a => a.Key, + a => sprites[new TileReference(t.First, (byte)a.Value)])); + } + } + + public string GetTerrainType(int2 cell) + { + var dx = cell - self.Location; + var index = dx.X + Templates[currentTemplate].Size.X*dx.Y; + return self.World.TileSet.GetTerrainType(new TileReference(currentTemplate,(byte)index)); + } + + public void LinkNeighbouringBridges(World world, BridgeLayer bridges) + { + // go looking for our neighbors if this is a long bridge. + if (Info.NorthOffset != null) + northNeighbour = GetNeighbor(Info.NorthOffset, bridges); + if (Info.SouthOffset != null) + southNeighbour = GetNeighbor(Info.SouthOffset, bridges); + } + + public Bridge GetNeighbor(int[] offset, BridgeLayer bridges) + { + if (offset == null) return null; + return bridges.GetBridge(self.Location + new int2(offset[0], offset[1])); + } + + public IEnumerable RenderAsTerrain(Actor self) + { + foreach (var t in TileSprites[currentTemplate]) + yield return new Renderable(t.Value, Game.CellSize * t.Key, "terrain", Game.CellSize * t.Key.Y); + } + + bool IsIntact(Bridge b) + { + return b != null && !b.self.IsDead(); + } + + void KillUnitsOnBridge() + { + var uim = self.World.WorldActor.Trait(); + + foreach (var c in TileSprites[currentTemplate].Keys) + foreach (var a in uim.GetUnitsAt(c)) + if (a.HasTrait() && !a.Trait().CanEnterCell(c)) + a.Kill(self); + } + + bool dead = false; + void UpdateState() + { + // If this is a long bridge next to a destroyed shore piece, we need die to give clean edges to the break + if (Info.Long && Health.DamageState != DamageState.Dead && + ((southNeighbour != null && Info.ShorePieces.Contains(southNeighbour.Type) && !IsIntact(southNeighbour)) || + (northNeighbour != null && Info.ShorePieces.Contains(northNeighbour.Type) && !IsIntact(northNeighbour)))) + { + self.Kill(self); // this changes the damagestate + } + + var ds = Health.DamageState; + currentTemplate = (ds == DamageState.Dead && Info.DestroyedTemplate > 0) ? Info.DestroyedTemplate : + (ds >= DamageState.Heavy && Info.DamagedTemplate > 0) ? Info.DamagedTemplate : Info.Template; + + if (Info.Long && ds == DamageState.Dead) + { + // Long bridges have custom art for multiple segments being destroyed + bool waterToSouth = !IsIntact(southNeighbour); + bool waterToNorth = !IsIntact(northNeighbour); + + if (waterToSouth && waterToNorth) + currentTemplate = Info.DestroyedPlusBothTemplate; + else if (waterToNorth) + currentTemplate = Info.DestroyedPlusNorthTemplate; + else if (waterToSouth) + currentTemplate = Info.DestroyedPlusSouthTemplate; + } + + if (ds == DamageState.Dead && !dead) + { + dead = true; + KillUnitsOnBridge(); + } + + // Update map + foreach (var c in TileSprites[currentTemplate].Keys) + self.World.Map.CustomTerrain[c.X, c.Y] = GetTerrainType(c); + } + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageStateChanged) + { + UpdateState(); + if (northNeighbour != null) northNeighbour.UpdateState(); + if (southNeighbour != null) southNeighbour.UpdateState(); + } + } + } +} diff --git a/OpenRA.Mods.RA/BridgeLayer.cs b/OpenRA.Mods.RA/BridgeLayer.cs index 14211c6992..c5f00d2439 100644 --- a/OpenRA.Mods.RA/BridgeLayer.cs +++ b/OpenRA.Mods.RA/BridgeLayer.cs @@ -1,115 +1,115 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class BridgeLayerInfo : ITraitInfo - { - [ActorReference] - public readonly string[] Bridges = {"bridge1", "bridge2"}; - - public object Create(ActorInitializer init) { return new BridgeLayer(init.self, this); } - } - - class BridgeLayer : IWorldLoaded - { - readonly BridgeLayerInfo Info; - readonly World world; - Dictionary> BridgeTypes = new Dictionary>(); - Bridge[,] Bridges; - - public BridgeLayer(Actor self, BridgeLayerInfo Info) - { - this.Info = Info; - this.world = self.World; - } - - public void WorldLoaded(World w) - { - Bridges = new Bridge[w.Map.MapSize.X, w.Map.MapSize.Y]; - - // Build a list of templates that should be overlayed with bridges - foreach(var bridge in Info.Bridges) - { - var bi = Rules.Info[bridge].Traits.Get(); - foreach (var template in bi.Templates) - BridgeTypes.Add(template.First, Pair.New(bridge, template.Second)); - } - - // Loop through the map looking for templates to overlay - for (int i = w.Map.Bounds.Left; i < w.Map.Bounds.Right; i++) - for (int j = w.Map.Bounds.Top; j < w.Map.Bounds.Bottom; j++) - if (BridgeTypes.Keys.Contains(w.Map.MapTiles.Value[i, j].type)) - ConvertBridgeToActor(w, i, j); - - // Link adjacent (long)-bridges so that artwork is updated correctly - foreach (var b in w.Actors.SelectMany(a => a.TraitsImplementing())) - b.LinkNeighbouringBridges(w,this); - } - - void ConvertBridgeToActor(World w, int i, int j) - { - // This cell already has a bridge overlaying it from a previous iteration - if (Bridges[i,j] != null) - return; - - // Correlate the tile "image" aka subtile with its position to find the template origin - var tile = w.Map.MapTiles.Value[i, j].type; - var index = w.Map.MapTiles.Value[i, j].index; - var template = w.TileSet.Templates[tile]; - var ni = i - index % template.Size.X; - var nj = j - index / template.Size.X; - - // Create a new actor for this bridge and keep track of which subtiles this bridge includes - var bridge = w.CreateActor(BridgeTypes[tile].First, new TypeDictionary - { - new LocationInit( new int2(ni, nj) ), - new OwnerInit( w.WorldActor.Owner ), - new HealthInit( BridgeTypes[tile].Second ), - }).Trait(); - - Dictionary subTiles = new Dictionary(); - - // For each subtile in the template - for (byte ind = 0; ind < template.Size.X*template.Size.Y; ind++) - { - // Is this tile actually included in the bridge template? - if (!template.Tiles.Keys.Contains(ind)) - continue; - - // Where do we expect to find the subtile - var x = ni + ind % template.Size.X; - var y = nj + ind / template.Size.X; - - // This isn't the bridge you're looking for - if (!w.Map.IsInMap(x, y) || w.Map.MapTiles.Value[x, y].index != ind) - continue; - - subTiles.Add(new int2(x,y),ind); - Bridges[x,y] = bridge; - } - bridge.Create(tile, subTiles); - } - - // Used to check for neighbouring bridges - public Bridge GetBridge(int2 cell) - { - if (!world.Map.IsInMap(cell.X, cell.Y)) - return null; - - return Bridges[ cell.X, cell.Y ]; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class BridgeLayerInfo : ITraitInfo + { + [ActorReference] + public readonly string[] Bridges = {"bridge1", "bridge2"}; + + public object Create(ActorInitializer init) { return new BridgeLayer(init.self, this); } + } + + class BridgeLayer : IWorldLoaded + { + readonly BridgeLayerInfo Info; + readonly World world; + Dictionary> BridgeTypes = new Dictionary>(); + Bridge[,] Bridges; + + public BridgeLayer(Actor self, BridgeLayerInfo Info) + { + this.Info = Info; + this.world = self.World; + } + + public void WorldLoaded(World w) + { + Bridges = new Bridge[w.Map.MapSize.X, w.Map.MapSize.Y]; + + // Build a list of templates that should be overlayed with bridges + foreach(var bridge in Info.Bridges) + { + var bi = Rules.Info[bridge].Traits.Get(); + foreach (var template in bi.Templates) + BridgeTypes.Add(template.First, Pair.New(bridge, template.Second)); + } + + // Loop through the map looking for templates to overlay + for (int i = w.Map.Bounds.Left; i < w.Map.Bounds.Right; i++) + for (int j = w.Map.Bounds.Top; j < w.Map.Bounds.Bottom; j++) + if (BridgeTypes.Keys.Contains(w.Map.MapTiles.Value[i, j].type)) + ConvertBridgeToActor(w, i, j); + + // Link adjacent (long)-bridges so that artwork is updated correctly + foreach (var b in w.Actors.SelectMany(a => a.TraitsImplementing())) + b.LinkNeighbouringBridges(w,this); + } + + void ConvertBridgeToActor(World w, int i, int j) + { + // This cell already has a bridge overlaying it from a previous iteration + if (Bridges[i,j] != null) + return; + + // Correlate the tile "image" aka subtile with its position to find the template origin + var tile = w.Map.MapTiles.Value[i, j].type; + var index = w.Map.MapTiles.Value[i, j].index; + var template = w.TileSet.Templates[tile]; + var ni = i - index % template.Size.X; + var nj = j - index / template.Size.X; + + // Create a new actor for this bridge and keep track of which subtiles this bridge includes + var bridge = w.CreateActor(BridgeTypes[tile].First, new TypeDictionary + { + new LocationInit( new int2(ni, nj) ), + new OwnerInit( w.WorldActor.Owner ), + new HealthInit( BridgeTypes[tile].Second ), + }).Trait(); + + Dictionary subTiles = new Dictionary(); + + // For each subtile in the template + for (byte ind = 0; ind < template.Size.X*template.Size.Y; ind++) + { + // Is this tile actually included in the bridge template? + if (!template.Tiles.Keys.Contains(ind)) + continue; + + // Where do we expect to find the subtile + var x = ni + ind % template.Size.X; + var y = nj + ind / template.Size.X; + + // This isn't the bridge you're looking for + if (!w.Map.IsInMap(x, y) || w.Map.MapTiles.Value[x, y].index != ind) + continue; + + subTiles.Add(new int2(x,y),ind); + Bridges[x,y] = bridge; + } + bridge.Create(tile, subTiles); + } + + // Used to check for neighbouring bridges + public Bridge GetBridge(int2 cell) + { + if (!world.Map.IsInMap(cell.X, cell.Y)) + return null; + + return Bridges[ cell.X, cell.Y ]; + } + } +} diff --git a/OpenRA.Mods.RA/Buildable.cs b/OpenRA.Mods.RA/Buildable.cs index f862384815..044277d306 100755 --- a/OpenRA.Mods.RA/Buildable.cs +++ b/OpenRA.Mods.RA/Buildable.cs @@ -1,28 +1,28 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + namespace OpenRA.Mods.RA { public class BuildableInfo : ITraitInfo { - [ActorReference] + [ActorReference] public readonly string[] Prerequisites = { }; - [ActorReference] + [ActorReference] public readonly string[] BuiltAt = { }; - - public readonly string[] Owner = { }; - - public readonly string Queue; - public readonly bool Hidden = false; + + public readonly string[] Owner = { }; + + public readonly string Queue; + public readonly bool Hidden = false; // todo: UI fluff; doesn't belong here public readonly int BuildPaletteOrder = 9999; @@ -30,5 +30,5 @@ namespace OpenRA.Mods.RA public object Create(ActorInitializer init) { return new Buildable(); } } - class Buildable { } + class Buildable { } } diff --git a/OpenRA.Mods.RA/BuildingCaptureNotification.cs b/OpenRA.Mods.RA/BuildingCaptureNotification.cs index 267b811fa2..9ad55db76a 100644 --- a/OpenRA.Mods.RA/BuildingCaptureNotification.cs +++ b/OpenRA.Mods.RA/BuildingCaptureNotification.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.RA/Buildings/BibLayer.cs b/OpenRA.Mods.RA/Buildings/BibLayer.cs index b7d2a37291..76e6ca8e45 100755 --- a/OpenRA.Mods.RA/Buildings/BibLayer.cs +++ b/OpenRA.Mods.RA/Buildings/BibLayer.cs @@ -1,19 +1,19 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Graphics; +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA.Buildings @@ -28,7 +28,7 @@ namespace OpenRA.Mods.RA.Buildings class BibLayer: IRenderOverlay, IWorldLoaded { World world; - BibLayerInfo info; + BibLayerInfo info; Dictionary> tiles; Sprite[][] bibSprites; @@ -45,7 +45,7 @@ namespace OpenRA.Mods.RA.Buildings public void WorldLoaded(World w) { - world = w; + world = w; tiles = new Dictionary>(); } @@ -64,26 +64,26 @@ namespace OpenRA.Mods.RA.Buildings for (int i = 0; i < 2 * size; i++) { - var p = b.Location + new int2(i % size, i / size + bibOffset); - if (isAdd) - tiles[p] = new TileReference((byte)((isAdd) ? bib + 1 : 0), (byte)i); - else + var p = b.Location + new int2(i % size, i / size + bibOffset); + if (isAdd) + tiles[p] = new TileReference((byte)((isAdd) ? bib + 1 : 0), (byte)i); + else tiles.Remove(p); } } public void Render( WorldRenderer wr ) - { + { var cliprect = Game.viewport.WorldBounds(world); - foreach (var kv in tiles) - { - if (!cliprect.Contains(kv.Key.X, kv.Key.Y)) - continue; - if (!world.LocalShroud.IsExplored(kv.Key)) - continue; - - bibSprites[kv.Value.type - 1][kv.Value.index].DrawAt( wr, - Game.CellSize * kv.Key, "terrain"); + foreach (var kv in tiles) + { + if (!cliprect.Contains(kv.Key.X, kv.Key.Y)) + continue; + if (!world.LocalShroud.IsExplored(kv.Key)) + continue; + + bibSprites[kv.Value.type - 1][kv.Value.index].DrawAt( wr, + Game.CellSize * kv.Key, "terrain"); } } } diff --git a/OpenRA.Mods.RA/Buildings/Building.cs b/OpenRA.Mods.RA/Buildings/Building.cs index f0ee97001b..4b6bf269e6 100755 --- a/OpenRA.Mods.RA/Buildings/Building.cs +++ b/OpenRA.Mods.RA/Buildings/Building.cs @@ -1,124 +1,124 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.RA.Buildings -{ - public class BuildingInfo : ITraitInfo - { - public readonly int Power = 0; - public readonly bool BaseNormal = true; - public readonly bool WaterBound = false; - public readonly int Adjacent = 2; - public readonly bool Capturable = false; - public readonly string Footprint = "x"; - public readonly int2 Dimensions = new int2(1, 1); - public readonly bool Unsellable = false; - public readonly int RefundPercent = 50; - - public readonly string[] BuildSounds = {"placbldg.aud", "build5.aud"}; - public readonly string[] SellSounds = {"cashturn.aud"}; - - - public object Create(ActorInitializer init) { return new Building(init, this); } - - public bool IsCloseEnoughToBase(World world, Player p, string buildingName, int2 topLeft) - { - var buildingMaxBounds = Dimensions; - if( Rules.Info[ buildingName ].Traits.Contains() ) - buildingMaxBounds.Y += 1; - - var scanStart = world.ClampToWorld( topLeft - new int2( Adjacent, Adjacent ) ); - var scanEnd = world.ClampToWorld( topLeft + buildingMaxBounds + new int2( Adjacent, Adjacent ) ); - - var nearnessCandidates = new List(); - - for( int y = scanStart.Y ; y < scanEnd.Y ; y++ ) - { - for( int x = scanStart.X ; x < scanEnd.X ; x++ ) - { - var at = world.WorldActor.Trait().GetBuildingAt( new int2( x, y ) ); - if( at != null && at.Owner.Stances[ p ] == Stance.Ally && at.Info.Traits.Get().BaseNormal ) - nearnessCandidates.Add( new int2( x, y ) ); - } - } - var buildingTiles = FootprintUtils.Tiles( buildingName, this, topLeft ).ToList(); - return nearnessCandidates - .Any( a => buildingTiles - .Any( b => Math.Abs( a.X - b.X ) <= Adjacent - && Math.Abs( a.Y - b.Y ) <= Adjacent ) ); - } - } - - public class Building : INotifyDamage, IResolveOrder, IOccupySpace, INotifyCapture, ISync - { - readonly Actor self; - public readonly BuildingInfo Info; - [Sync] - readonly int2 topLeft; - - PowerManager PlayerPower; - - public int2 PxPosition { get { return ( 2 * topLeft + Info.Dimensions ) * Game.CellSize / 2; } } - - public Building(ActorInitializer init, BuildingInfo info) - { - this.self = init.self; - this.topLeft = init.Get(); - this.Info = info; - this.PlayerPower = init.self.Owner.PlayerActor.Trait(); - } - - public int GetPowerUsage() - { - if (Info.Power <= 0) - return Info.Power; - - var health = self.TraitOrDefault(); - return health != null ? (Info.Power * health.HP / health.MaxHP) : Info.Power; - } - - public void Damaged(Actor self, AttackInfo e) - { - // Power plants lose power with damage - if (Info.Power > 0) - PlayerPower.UpdateActor(self, GetPowerUsage()); - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "Sell") - { - self.CancelActivity(); - self.QueueActivity(new Sell()); - } - } - - public int2 TopLeft - { - get { return topLeft; } - } - - public IEnumerable> OccupiedCells() - { - return FootprintUtils.UnpathableTiles( self.Info.Name, Info, TopLeft ).Select(c => Pair.New(c, SubCell.FullCell)); - } - - public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) - { - PlayerPower = newOwner.PlayerActor.Trait(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.RA.Buildings +{ + public class BuildingInfo : ITraitInfo + { + public readonly int Power = 0; + public readonly bool BaseNormal = true; + public readonly bool WaterBound = false; + public readonly int Adjacent = 2; + public readonly bool Capturable = false; + public readonly string Footprint = "x"; + public readonly int2 Dimensions = new int2(1, 1); + public readonly bool Unsellable = false; + public readonly int RefundPercent = 50; + + public readonly string[] BuildSounds = {"placbldg.aud", "build5.aud"}; + public readonly string[] SellSounds = {"cashturn.aud"}; + + + public object Create(ActorInitializer init) { return new Building(init, this); } + + public bool IsCloseEnoughToBase(World world, Player p, string buildingName, int2 topLeft) + { + var buildingMaxBounds = Dimensions; + if( Rules.Info[ buildingName ].Traits.Contains() ) + buildingMaxBounds.Y += 1; + + var scanStart = world.ClampToWorld( topLeft - new int2( Adjacent, Adjacent ) ); + var scanEnd = world.ClampToWorld( topLeft + buildingMaxBounds + new int2( Adjacent, Adjacent ) ); + + var nearnessCandidates = new List(); + + for( int y = scanStart.Y ; y < scanEnd.Y ; y++ ) + { + for( int x = scanStart.X ; x < scanEnd.X ; x++ ) + { + var at = world.WorldActor.Trait().GetBuildingAt( new int2( x, y ) ); + if( at != null && at.Owner.Stances[ p ] == Stance.Ally && at.Info.Traits.Get().BaseNormal ) + nearnessCandidates.Add( new int2( x, y ) ); + } + } + var buildingTiles = FootprintUtils.Tiles( buildingName, this, topLeft ).ToList(); + return nearnessCandidates + .Any( a => buildingTiles + .Any( b => Math.Abs( a.X - b.X ) <= Adjacent + && Math.Abs( a.Y - b.Y ) <= Adjacent ) ); + } + } + + public class Building : INotifyDamage, IResolveOrder, IOccupySpace, INotifyCapture, ISync + { + readonly Actor self; + public readonly BuildingInfo Info; + [Sync] + readonly int2 topLeft; + + PowerManager PlayerPower; + + public int2 PxPosition { get { return ( 2 * topLeft + Info.Dimensions ) * Game.CellSize / 2; } } + + public Building(ActorInitializer init, BuildingInfo info) + { + this.self = init.self; + this.topLeft = init.Get(); + this.Info = info; + this.PlayerPower = init.self.Owner.PlayerActor.Trait(); + } + + public int GetPowerUsage() + { + if (Info.Power <= 0) + return Info.Power; + + var health = self.TraitOrDefault(); + return health != null ? (Info.Power * health.HP / health.MaxHP) : Info.Power; + } + + public void Damaged(Actor self, AttackInfo e) + { + // Power plants lose power with damage + if (Info.Power > 0) + PlayerPower.UpdateActor(self, GetPowerUsage()); + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Sell") + { + self.CancelActivity(); + self.QueueActivity(new Sell()); + } + } + + public int2 TopLeft + { + get { return topLeft; } + } + + public IEnumerable> OccupiedCells() + { + return FootprintUtils.UnpathableTiles( self.Info.Name, Info, TopLeft ).Select(c => Pair.New(c, SubCell.FullCell)); + } + + public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + { + PlayerPower = newOwner.PlayerActor.Trait(); + } + } +} diff --git a/OpenRA.Mods.RA/Buildings/BuildingInfluence.cs b/OpenRA.Mods.RA/Buildings/BuildingInfluence.cs index 3b5e622094..77d5764ceb 100755 --- a/OpenRA.Mods.RA/Buildings/BuildingInfluence.cs +++ b/OpenRA.Mods.RA/Buildings/BuildingInfluence.cs @@ -1,52 +1,52 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Buildings -{ - public class BuildingInfluenceInfo : ITraitInfo - { - public object Create( ActorInitializer init ) { return new BuildingInfluence( init.world ); } - } - - public class BuildingInfluence - { - Actor[,] influence; - Map map; - - public BuildingInfluence( World world ) - { - map = world.Map; - - influence = new Actor[map.MapSize.X, map.MapSize.Y]; - - world.ActorAdded += - a => { if (a.HasTrait()) - ChangeInfluence(a, a.Trait(), true); }; - world.ActorRemoved += - a => { if (a.HasTrait()) - ChangeInfluence(a, a.Trait(), false); }; - } - - void ChangeInfluence( Actor a, Building building, bool isAdd ) - { - foreach( var u in FootprintUtils.Tiles( a.Info.Name, a.Info.Traits.Get(), a.Location ) ) - if( map.IsInMap( u ) ) - influence[ u.X, u.Y ] = isAdd ? a : null; - } - - public Actor GetBuildingAt(int2 cell) - { - if (!map.IsInMap(cell)) return null; - return influence[cell.X, cell.Y]; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Buildings +{ + public class BuildingInfluenceInfo : ITraitInfo + { + public object Create( ActorInitializer init ) { return new BuildingInfluence( init.world ); } + } + + public class BuildingInfluence + { + Actor[,] influence; + Map map; + + public BuildingInfluence( World world ) + { + map = world.Map; + + influence = new Actor[map.MapSize.X, map.MapSize.Y]; + + world.ActorAdded += + a => { if (a.HasTrait()) + ChangeInfluence(a, a.Trait(), true); }; + world.ActorRemoved += + a => { if (a.HasTrait()) + ChangeInfluence(a, a.Trait(), false); }; + } + + void ChangeInfluence( Actor a, Building building, bool isAdd ) + { + foreach( var u in FootprintUtils.Tiles( a.Info.Name, a.Info.Traits.Get(), a.Location ) ) + if( map.IsInMap( u ) ) + influence[ u.X, u.Y ] = isAdd ? a : null; + } + + public Actor GetBuildingAt(int2 cell) + { + if (!map.IsInMap(cell)) return null; + return influence[cell.X, cell.Y]; + } + } +} diff --git a/OpenRA.Mods.RA/Buildings/CanPowerDown.cs b/OpenRA.Mods.RA/Buildings/CanPowerDown.cs index f1faaec23f..3ef7f73ae3 100755 --- a/OpenRA.Mods.RA/Buildings/CanPowerDown.cs +++ b/OpenRA.Mods.RA/Buildings/CanPowerDown.cs @@ -1,57 +1,57 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Buildings -{ - public class CanPowerDownInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new CanPowerDown(init); } - } - - public class CanPowerDown : IResolveOrder, IDisable, INotifyCapture, ISync - { - [Sync] - bool disabled = false; - int normalPower = 0; - PowerManager PowerManager; - TechTree TechTree; - - public CanPowerDown(ActorInitializer init) - { - PowerManager = init.self.Owner.PlayerActor.Trait(); - TechTree = init.self.Owner.PlayerActor.Trait(); - normalPower = init.self.Info.Traits.Get().Power; - } - public bool Disabled { get { return disabled; } } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "PowerDown") - { - disabled = !disabled; - var eva = self.World.WorldActor.Info.Traits.Get(); - Sound.PlayToPlayer(self.Owner, disabled ? eva.EnablePower : eva.DisablePower); - - PowerManager.UpdateActor(self, disabled ? 0 : normalPower); - - // Rebuild the tech tree; some support powers require active buildings - TechTree.Update(); - } - } - - public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) - { - PowerManager = newOwner.PlayerActor.Trait(); - TechTree = newOwner.PlayerActor.Trait(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Buildings +{ + public class CanPowerDownInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new CanPowerDown(init); } + } + + public class CanPowerDown : IResolveOrder, IDisable, INotifyCapture, ISync + { + [Sync] + bool disabled = false; + int normalPower = 0; + PowerManager PowerManager; + TechTree TechTree; + + public CanPowerDown(ActorInitializer init) + { + PowerManager = init.self.Owner.PlayerActor.Trait(); + TechTree = init.self.Owner.PlayerActor.Trait(); + normalPower = init.self.Info.Traits.Get().Power; + } + public bool Disabled { get { return disabled; } } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "PowerDown") + { + disabled = !disabled; + var eva = self.World.WorldActor.Info.Traits.Get(); + Sound.PlayToPlayer(self.Owner, disabled ? eva.EnablePower : eva.DisablePower); + + PowerManager.UpdateActor(self, disabled ? 0 : normalPower); + + // Rebuild the tech tree; some support powers require active buildings + TechTree.Update(); + } + } + + public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + { + PowerManager = newOwner.PlayerActor.Trait(); + TechTree = newOwner.PlayerActor.Trait(); + } + } +} diff --git a/OpenRA.Mods.RA/Buildings/CustomSellValue.cs b/OpenRA.Mods.RA/Buildings/CustomSellValue.cs index 3ea834724b..94260e637d 100755 --- a/OpenRA.Mods.RA/Buildings/CustomSellValue.cs +++ b/OpenRA.Mods.RA/Buildings/CustomSellValue.cs @@ -1,24 +1,24 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Buildings -{ - // allow a nonstandard sell/repair value to avoid - // buy-sell exploits like c&c's PROC. - - public class CustomSellValueInfo : TraitInfo - { - public readonly int Value = 0; - } - - public class CustomSellValue { } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Buildings +{ + // allow a nonstandard sell/repair value to avoid + // buy-sell exploits like c&c's PROC. + + public class CustomSellValueInfo : TraitInfo + { + public readonly int Value = 0; + } + + public class CustomSellValue { } +} diff --git a/OpenRA.Mods.RA/Buildings/FootprintUtils.cs b/OpenRA.Mods.RA/Buildings/FootprintUtils.cs index 26d3de4eb9..8cd18e9012 100755 --- a/OpenRA.Mods.RA/Buildings/FootprintUtils.cs +++ b/OpenRA.Mods.RA/Buildings/FootprintUtils.cs @@ -1,64 +1,64 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace OpenRA.Mods.RA.Buildings -{ - public static class FootprintUtils - { - public static IEnumerable Tiles( string name, BuildingInfo buildingInfo, int2 topLeft ) - { - var dim = buildingInfo.Dimensions; - - var footprint = buildingInfo.Footprint.Where(x => !char.IsWhiteSpace(x)); - - if (Rules.Info[ name ].Traits.Contains()) - { - dim.Y += 1; - footprint = footprint.Concat(new char[dim.X]); - } - - return TilesWhere( name, dim, footprint.ToArray(), a => a != '_' ).Select( t => t + topLeft ); - } - - public static IEnumerable Tiles(Actor a) - { - return Tiles( a.Info.Name, a.Info.Traits.Get(), a.Location ); - } - - public static IEnumerable UnpathableTiles( string name, BuildingInfo buildingInfo, int2 position ) - { - var footprint = buildingInfo.Footprint.Where( x => !char.IsWhiteSpace( x ) ).ToArray(); - foreach( var tile in TilesWhere( name, buildingInfo.Dimensions, footprint, a => a == 'x' ) ) - yield return tile + position; - } - - static IEnumerable TilesWhere( string name, int2 dim, char[] footprint, Func cond ) - { - if( footprint.Length != dim.X * dim.Y ) - throw new InvalidOperationException( "Invalid footprint for " + name ); - int index = 0; - - for( int y = 0 ; y < dim.Y ; y++ ) - for( int x = 0 ; x < dim.X ; x++ ) - if( cond( footprint[ index++ ] ) ) - yield return new int2( x, y ); - } - - public static int2 AdjustForBuildingSize( BuildingInfo buildingInfo ) - { - var dim = buildingInfo.Dimensions; - return new int2( dim.X / 2, dim.Y > 1 ? ( dim.Y + 1 ) / 2 : 0 ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.RA.Buildings +{ + public static class FootprintUtils + { + public static IEnumerable Tiles( string name, BuildingInfo buildingInfo, int2 topLeft ) + { + var dim = buildingInfo.Dimensions; + + var footprint = buildingInfo.Footprint.Where(x => !char.IsWhiteSpace(x)); + + if (Rules.Info[ name ].Traits.Contains()) + { + dim.Y += 1; + footprint = footprint.Concat(new char[dim.X]); + } + + return TilesWhere( name, dim, footprint.ToArray(), a => a != '_' ).Select( t => t + topLeft ); + } + + public static IEnumerable Tiles(Actor a) + { + return Tiles( a.Info.Name, a.Info.Traits.Get(), a.Location ); + } + + public static IEnumerable UnpathableTiles( string name, BuildingInfo buildingInfo, int2 position ) + { + var footprint = buildingInfo.Footprint.Where( x => !char.IsWhiteSpace( x ) ).ToArray(); + foreach( var tile in TilesWhere( name, buildingInfo.Dimensions, footprint, a => a == 'x' ) ) + yield return tile + position; + } + + static IEnumerable TilesWhere( string name, int2 dim, char[] footprint, Func cond ) + { + if( footprint.Length != dim.X * dim.Y ) + throw new InvalidOperationException( "Invalid footprint for " + name ); + int index = 0; + + for( int y = 0 ; y < dim.Y ; y++ ) + for( int x = 0 ; x < dim.X ; x++ ) + if( cond( footprint[ index++ ] ) ) + yield return new int2( x, y ); + } + + public static int2 AdjustForBuildingSize( BuildingInfo buildingInfo ) + { + var dim = buildingInfo.Dimensions; + return new int2( dim.X / 2, dim.Y > 1 ? ( dim.Y + 1 ) / 2 : 0 ); + } + } +} diff --git a/OpenRA.Mods.RA/Buildings/LineBuild.cs b/OpenRA.Mods.RA/Buildings/LineBuild.cs index a8f7a99959..3ea1de0393 100755 --- a/OpenRA.Mods.RA/Buildings/LineBuild.cs +++ b/OpenRA.Mods.RA/Buildings/LineBuild.cs @@ -1,21 +1,21 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Buildings -{ - public class LineBuildInfo : TraitInfo - { - public readonly int Range = 5; - } - - public class LineBuild {} -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Buildings +{ + public class LineBuildInfo : TraitInfo + { + public readonly int Range = 5; + } + + public class LineBuild {} +} diff --git a/OpenRA.Mods.RA/Buildings/PowerManager.cs b/OpenRA.Mods.RA/Buildings/PowerManager.cs index 510312a264..463916cc4c 100755 --- a/OpenRA.Mods.RA/Buildings/PowerManager.cs +++ b/OpenRA.Mods.RA/Buildings/PowerManager.cs @@ -1,14 +1,14 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Collections.Generic; +#endregion + +using System.Collections.Generic; using OpenRA.Traits; namespace OpenRA.Mods.RA.Buildings @@ -17,12 +17,12 @@ namespace OpenRA.Mods.RA.Buildings { public readonly int AdviceInterval = 250; public object Create(ActorInitializer init) { return new PowerManager(init, this); } - } - + } + public class PowerManager : ITick, ISync { PowerManagerInfo Info; - Player Player; + Player Player; DeveloperMode devMode; Dictionary PowerDrain = new Dictionary(); @@ -38,9 +38,9 @@ namespace OpenRA.Mods.RA.Buildings Player = init.self.Owner; init.world.ActorAdded += ActorAdded; - init.world.ActorRemoved += ActorRemoved; - - devMode = init.self.Trait(); + init.world.ActorRemoved += ActorRemoved; + + devMode = init.self.Trait(); wasHackEnabled = devMode.UnlimitedPower; } @@ -71,9 +71,9 @@ namespace OpenRA.Mods.RA.Buildings totalProvided += p; else totalDrained -= p; - } - - if (devMode.UnlimitedPower) + } + + if (devMode.UnlimitedPower) totalProvided = 1000000; } @@ -87,15 +87,15 @@ namespace OpenRA.Mods.RA.Buildings } int nextPowerAdviceTime = 0; - bool wasLowPower = false; + bool wasLowPower = false; bool wasHackEnabled; public void Tick(Actor self) - { - if (wasHackEnabled != devMode.UnlimitedPower) - { - UpdateTotals(); - wasHackEnabled = devMode.UnlimitedPower; + { + if (wasHackEnabled != devMode.UnlimitedPower) + { + UpdateTotals(); + wasHackEnabled = devMode.UnlimitedPower; } var lowPower = totalProvided < totalDrained; diff --git a/OpenRA.Mods.RA/Buildings/RepairableBuilding.cs b/OpenRA.Mods.RA/Buildings/RepairableBuilding.cs index f6bd837af8..fae3f0d508 100755 --- a/OpenRA.Mods.RA/Buildings/RepairableBuilding.cs +++ b/OpenRA.Mods.RA/Buildings/RepairableBuilding.cs @@ -1,15 +1,15 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System; -using OpenRA.Mods.RA.Effects; +#endregion + +using System; +using OpenRA.Mods.RA.Effects; using OpenRA.Traits; namespace OpenRA.Mods.RA.Buildings @@ -20,8 +20,8 @@ namespace OpenRA.Mods.RA.Buildings public readonly float RepairRate = 0.016f; public readonly int RepairStep = 7; public object Create(ActorInitializer init) { return new RepairableBuilding(init.self, this); } - } - + } + public class RepairableBuilding : ITick, IResolveOrder, ISync { [Sync] diff --git a/OpenRA.Mods.RA/Buildings/RequiresPower.cs b/OpenRA.Mods.RA/Buildings/RequiresPower.cs index 6b6634cda6..7e7f9561be 100755 --- a/OpenRA.Mods.RA/Buildings/RequiresPower.cs +++ b/OpenRA.Mods.RA/Buildings/RequiresPower.cs @@ -1,38 +1,38 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Buildings -{ - class RequiresPowerInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new RequiresPower(init.self); } - } - - class RequiresPower : IDisable, INotifyCapture - { - PowerManager power; - public RequiresPower( Actor self ) - { - power = self.Owner.PlayerActor.Trait(); - } - - public bool Disabled - { - get { return power.PowerProvided < power.PowerDrained; } - } - - public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) - { - power = newOwner.PlayerActor.Trait(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Buildings +{ + class RequiresPowerInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new RequiresPower(init.self); } + } + + class RequiresPower : IDisable, INotifyCapture + { + PowerManager power; + public RequiresPower( Actor self ) + { + power = self.Owner.PlayerActor.Trait(); + } + + public bool Disabled + { + get { return power.PowerProvided < power.PowerDrained; } + } + + public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + { + power = newOwner.PlayerActor.Trait(); + } + } +} diff --git a/OpenRA.Mods.RA/Buildings/Sell.cs b/OpenRA.Mods.RA/Buildings/Sell.cs index 0442c55362..671e1cfeb4 100755 --- a/OpenRA.Mods.RA/Buildings/Sell.cs +++ b/OpenRA.Mods.RA/Buildings/Sell.cs @@ -1,77 +1,77 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Buildings -{ - class Sell : IActivity - { - IActivity NextActivity { get; set; } - - bool started; - - int framesRemaining; - - void DoSell(Actor self) - { - var h = self.TraitOrDefault(); - var bi = self.Info.Traits.Get(); - var pr = self.Owner.PlayerActor.Trait(); - var csv = self.Info.Traits.GetOrDefault(); - - var cost = csv != null ? csv.Value : self.Info.Traits.Get().Cost; - - var refund = (cost * bi.RefundPercent * (h == null ? 1 : h.HP)) / (100 * (h == null ? 1 : h.MaxHP)); - pr.GiveCash(refund); - - foreach (var ns in self.TraitsImplementing()) - ns.Sold(self); - self.Destroy(); - } - - public IActivity Tick(Actor self) - { - if( !started ) - { - framesRemaining = self.Trait().anim.HasSequence("make") - ? self.Trait().anim.GetSequence( "make" ).Length : 0; - - foreach( var ns in self.TraitsImplementing() ) - ns.Selling( self ); - - started = true; - } - else if( framesRemaining <= 0 ) - DoSell( self ); - - else - --framesRemaining; - - return this; - } - - public void Cancel(Actor self) { /* never gonna give you up.. */ } - - public void Queue( IActivity activity ) - { - if( NextActivity != null ) - NextActivity.Queue( activity ); - else - NextActivity = activity; - } - - public IEnumerable GetCurrentPath() - { - yield break; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Buildings +{ + class Sell : IActivity + { + IActivity NextActivity { get; set; } + + bool started; + + int framesRemaining; + + void DoSell(Actor self) + { + var h = self.TraitOrDefault(); + var bi = self.Info.Traits.Get(); + var pr = self.Owner.PlayerActor.Trait(); + var csv = self.Info.Traits.GetOrDefault(); + + var cost = csv != null ? csv.Value : self.Info.Traits.Get().Cost; + + var refund = (cost * bi.RefundPercent * (h == null ? 1 : h.HP)) / (100 * (h == null ? 1 : h.MaxHP)); + pr.GiveCash(refund); + + foreach (var ns in self.TraitsImplementing()) + ns.Sold(self); + self.Destroy(); + } + + public IActivity Tick(Actor self) + { + if( !started ) + { + framesRemaining = self.Trait().anim.HasSequence("make") + ? self.Trait().anim.GetSequence( "make" ).Length : 0; + + foreach( var ns in self.TraitsImplementing() ) + ns.Selling( self ); + + started = true; + } + else if( framesRemaining <= 0 ) + DoSell( self ); + + else + --framesRemaining; + + return this; + } + + public void Cancel(Actor self) { /* never gonna give you up.. */ } + + public void Queue( IActivity activity ) + { + if( NextActivity != null ) + NextActivity.Queue( activity ); + else + NextActivity = activity; + } + + public IEnumerable GetCurrentPath() + { + yield break; + } + } +} diff --git a/OpenRA.Mods.RA/Buildings/ShakeOnDeath.cs b/OpenRA.Mods.RA/Buildings/ShakeOnDeath.cs index 64d3a14b63..3c32c1e194 100644 --- a/OpenRA.Mods.RA/Buildings/ShakeOnDeath.cs +++ b/OpenRA.Mods.RA/Buildings/ShakeOnDeath.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.RA/Buildings/SoundOnDamageTransition.cs b/OpenRA.Mods.RA/Buildings/SoundOnDamageTransition.cs index 8a18bf97f4..3634887c6f 100644 --- a/OpenRA.Mods.RA/Buildings/SoundOnDamageTransition.cs +++ b/OpenRA.Mods.RA/Buildings/SoundOnDamageTransition.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.RA/Buildings/TechTree.cs b/OpenRA.Mods.RA/Buildings/TechTree.cs index 5c928ee208..534aa1618e 100755 --- a/OpenRA.Mods.RA/Buildings/TechTree.cs +++ b/OpenRA.Mods.RA/Buildings/TechTree.cs @@ -1,116 +1,116 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Buildings -{ - public class TechTreeInfo : ITraitInfo - { - public object Create(ActorInitializer init) { return new TechTree(init);} - } - - public class TechTree - { - readonly List watchers = new List(); - readonly Player player; - public TechTree(ActorInitializer init) - { - player = init.self.Owner; - init.world.ActorAdded += ActorChanged; - init.world.ActorRemoved += ActorChanged; - } - - public void ActorChanged(Actor a) - { - if (a.Owner == player && a.HasTrait()) - Update(); - } - - public void Update() - { - var buildings = GatherBuildings(player); - foreach(var w in watchers) - w.Update(buildings); - } - - public void Add(string key, List prerequisites, ITechTreeElement tte) - { - watchers.Add(new Watcher( key, prerequisites, tte )); - } - - public void Remove(string key) - { - watchers.RemoveAll(x => x.key == key); - } - - static Cache> GatherBuildings( Player player ) - { - var ret = new Cache>( x => new List() ); - if (player == null) - return ret; - - foreach( var b in player.World.Queries.OwnedBy[player].Where( x=>x.Info.Traits.Contains() ) ) - { - ret[ b.Info.Name ].Add( b ); - var tt = b.Info.Traits.GetOrDefault(); - if( tt != null ) - foreach( var alt in tt.AlternateName ) - ret[ alt ].Add( b ); - } - return ret; - } - - class Watcher - { - public readonly string key; - // strings may be either actor type, or "alternate name" key - public readonly List prerequisites; - public readonly ITechTreeElement watcher; - bool hasPrerequisites; - - public Watcher(string key, List prerequisites, ITechTreeElement watcher) - { - this.key = key; - this.prerequisites = prerequisites; - this.watcher = watcher; - this.hasPrerequisites = false; - } - - public void Update(Cache> buildings) - { - var nowHasPrerequisites = true; - foreach (var p in prerequisites) - if (!buildings.Keys.Contains(p)) - { - nowHasPrerequisites = false; - break; - } - - if( nowHasPrerequisites && !hasPrerequisites ) - watcher.PrerequisitesAvailable(key); - - if( !nowHasPrerequisites && hasPrerequisites ) - watcher.PrerequisitesUnavailable(key); - - hasPrerequisites = nowHasPrerequisites; - } - } - } - - public interface ITechTreeElement - { - void PrerequisitesAvailable(string key); - void PrerequisitesUnavailable(string key); - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Buildings +{ + public class TechTreeInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new TechTree(init);} + } + + public class TechTree + { + readonly List watchers = new List(); + readonly Player player; + public TechTree(ActorInitializer init) + { + player = init.self.Owner; + init.world.ActorAdded += ActorChanged; + init.world.ActorRemoved += ActorChanged; + } + + public void ActorChanged(Actor a) + { + if (a.Owner == player && a.HasTrait()) + Update(); + } + + public void Update() + { + var buildings = GatherBuildings(player); + foreach(var w in watchers) + w.Update(buildings); + } + + public void Add(string key, List prerequisites, ITechTreeElement tte) + { + watchers.Add(new Watcher( key, prerequisites, tte )); + } + + public void Remove(string key) + { + watchers.RemoveAll(x => x.key == key); + } + + static Cache> GatherBuildings( Player player ) + { + var ret = new Cache>( x => new List() ); + if (player == null) + return ret; + + foreach( var b in player.World.Queries.OwnedBy[player].Where( x=>x.Info.Traits.Contains() ) ) + { + ret[ b.Info.Name ].Add( b ); + var tt = b.Info.Traits.GetOrDefault(); + if( tt != null ) + foreach( var alt in tt.AlternateName ) + ret[ alt ].Add( b ); + } + return ret; + } + + class Watcher + { + public readonly string key; + // strings may be either actor type, or "alternate name" key + public readonly List prerequisites; + public readonly ITechTreeElement watcher; + bool hasPrerequisites; + + public Watcher(string key, List prerequisites, ITechTreeElement watcher) + { + this.key = key; + this.prerequisites = prerequisites; + this.watcher = watcher; + this.hasPrerequisites = false; + } + + public void Update(Cache> buildings) + { + var nowHasPrerequisites = true; + foreach (var p in prerequisites) + if (!buildings.Keys.Contains(p)) + { + nowHasPrerequisites = false; + break; + } + + if( nowHasPrerequisites && !hasPrerequisites ) + watcher.PrerequisitesAvailable(key); + + if( !nowHasPrerequisites && hasPrerequisites ) + watcher.PrerequisitesUnavailable(key); + + hasPrerequisites = nowHasPrerequisites; + } + } + } + + public interface ITechTreeElement + { + void PrerequisitesAvailable(string key); + void PrerequisitesUnavailable(string key); + } +} diff --git a/OpenRA.Mods.RA/Buildings/Util.cs b/OpenRA.Mods.RA/Buildings/Util.cs index ca61c8eb84..de42f2f49e 100755 --- a/OpenRA.Mods.RA/Buildings/Util.cs +++ b/OpenRA.Mods.RA/Buildings/Util.cs @@ -1,80 +1,80 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Buildings -{ - public static class BuildingUtils - { - public static bool IsCellBuildable(this World world, int2 a, bool waterBound) - { - return world.IsCellBuildable(a, waterBound, null); - } - - public static bool IsCellBuildable(this World world, int2 a, bool waterBound, Actor toIgnore) - { - if (world.WorldActor.Trait().GetBuildingAt(a) != null) return false; - if (world.WorldActor.Trait().GetUnitsAt(a).Any(b => b != toIgnore)) return false; - - if (waterBound) - return world.Map.IsInMap(a.X,a.Y) && world.GetTerrainInfo(a).IsWater; - - return world.Map.IsInMap(a.X, a.Y) && world.GetTerrainInfo(a).Buildable; - } - - public static bool CanPlaceBuilding(this World world, string name, BuildingInfo building, int2 topLeft, Actor toIgnore) - { - var res = world.WorldActor.Trait(); - return FootprintUtils.Tiles(name, building, topLeft).All( - t => world.Map.IsInMap(t.X, t.Y) && res.GetResource(t) == null && - world.IsCellBuildable(t, building.WaterBound, toIgnore)); - } - - public static IEnumerable GetLineBuildCells(World world, int2 location, string name, BuildingInfo bi) - { - int range = Rules.Info[name].Traits.Get().Range; - var topLeft = location; // 1x1 assumption! - - if (world.IsCellBuildable(topLeft, bi.WaterBound)) - yield return topLeft; - - // Start at place location, search outwards - // TODO: First make it work, then make it nice - var vecs = new[] { new int2(1, 0), new int2(0, 1), new int2(-1, 0), new int2(0, -1) }; - int[] dirs = { 0, 0, 0, 0 }; - for (int d = 0; d < 4; d++) - { - for (int i = 1; i < range; i++) - { - if (dirs[d] != 0) - continue; - - int2 cell = topLeft + i * vecs[d]; - if (world.IsCellBuildable(cell, bi.WaterBound)) - continue; // Cell is empty; continue search - - // Cell contains an actor. Is it the type we want? - if (world.Queries.WithTrait().Any(a => (a.Actor.Info.Name == name && a.Actor.Location.X == cell.X && a.Actor.Location.Y == cell.Y))) - dirs[d] = i; // Cell contains actor of correct type - else - dirs[d] = -1; // Cell is blocked by another actor type - } - - // Place intermediate-line sections - if (dirs[d] > 0) - for (int i = 1; i < dirs[d]; i++) - yield return topLeft + i * vecs[d]; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Buildings +{ + public static class BuildingUtils + { + public static bool IsCellBuildable(this World world, int2 a, bool waterBound) + { + return world.IsCellBuildable(a, waterBound, null); + } + + public static bool IsCellBuildable(this World world, int2 a, bool waterBound, Actor toIgnore) + { + if (world.WorldActor.Trait().GetBuildingAt(a) != null) return false; + if (world.WorldActor.Trait().GetUnitsAt(a).Any(b => b != toIgnore)) return false; + + if (waterBound) + return world.Map.IsInMap(a.X,a.Y) && world.GetTerrainInfo(a).IsWater; + + return world.Map.IsInMap(a.X, a.Y) && world.GetTerrainInfo(a).Buildable; + } + + public static bool CanPlaceBuilding(this World world, string name, BuildingInfo building, int2 topLeft, Actor toIgnore) + { + var res = world.WorldActor.Trait(); + return FootprintUtils.Tiles(name, building, topLeft).All( + t => world.Map.IsInMap(t.X, t.Y) && res.GetResource(t) == null && + world.IsCellBuildable(t, building.WaterBound, toIgnore)); + } + + public static IEnumerable GetLineBuildCells(World world, int2 location, string name, BuildingInfo bi) + { + int range = Rules.Info[name].Traits.Get().Range; + var topLeft = location; // 1x1 assumption! + + if (world.IsCellBuildable(topLeft, bi.WaterBound)) + yield return topLeft; + + // Start at place location, search outwards + // TODO: First make it work, then make it nice + var vecs = new[] { new int2(1, 0), new int2(0, 1), new int2(-1, 0), new int2(0, -1) }; + int[] dirs = { 0, 0, 0, 0 }; + for (int d = 0; d < 4; d++) + { + for (int i = 1; i < range; i++) + { + if (dirs[d] != 0) + continue; + + int2 cell = topLeft + i * vecs[d]; + if (world.IsCellBuildable(cell, bi.WaterBound)) + continue; // Cell is empty; continue search + + // Cell contains an actor. Is it the type we want? + if (world.Queries.WithTrait().Any(a => (a.Actor.Info.Name == name && a.Actor.Location.X == cell.X && a.Actor.Location.Y == cell.Y))) + dirs[d] = i; // Cell contains actor of correct type + else + dirs[d] = -1; // Cell is blocked by another actor type + } + + // Place intermediate-line sections + if (dirs[d] > 0) + for (int i = 1; i < dirs[d]; i++) + yield return topLeft + i * vecs[d]; + } + } + } +} diff --git a/OpenRA.Mods.RA/Buildings/Wall.cs b/OpenRA.Mods.RA/Buildings/Wall.cs index 61213d4353..0e42d685f5 100755 --- a/OpenRA.Mods.RA/Buildings/Wall.cs +++ b/OpenRA.Mods.RA/Buildings/Wall.cs @@ -1,41 +1,41 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Buildings -{ - public class WallInfo : ITraitInfo, ITraitPrerequisite - { - public readonly string[] CrushClasses = { }; - public readonly string CrushSound; - public object Create(ActorInitializer init) { return new Wall(init.self, this); } - } - - public class Wall : ICrushable, IBlocksBullets - { - readonly Actor self; - readonly WallInfo info; - - public Wall(Actor self, WallInfo info) - { - this.self = self; - this.info = info; - } - - public IEnumerable CrushClasses { get { return info.CrushClasses; } } - public void OnCrush(Actor crusher) - { - self.Kill(crusher); - Sound.Play(info.CrushSound, self.CenterLocation); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Buildings +{ + public class WallInfo : ITraitInfo, ITraitPrerequisite + { + public readonly string[] CrushClasses = { }; + public readonly string CrushSound; + public object Create(ActorInitializer init) { return new Wall(init.self, this); } + } + + public class Wall : ICrushable, IBlocksBullets + { + readonly Actor self; + readonly WallInfo info; + + public Wall(Actor self, WallInfo info) + { + this.self = self; + this.info = info; + } + + public IEnumerable CrushClasses { get { return info.CrushClasses; } } + public void OnCrush(Actor crusher) + { + self.Kill(crusher); + Sound.Play(info.CrushSound, self.CenterLocation); + } + } +} diff --git a/OpenRA.Mods.RA/Burns.cs b/OpenRA.Mods.RA/Burns.cs index e42530b546..a47f0f0680 100644 --- a/OpenRA.Mods.RA/Burns.cs +++ b/OpenRA.Mods.RA/Burns.cs @@ -1,48 +1,48 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class BurnsInfo : TraitInfo - { - public readonly string Anim = "1"; - public readonly int Damage = 1; - public readonly int Interval = 8; - } - - class Burns : ITick, ISync - { - [Sync] - int ticks; - bool isSetup; - - public void Tick(Actor self) - { - if (!isSetup) - { - isSetup = true; - - var anim = new Animation("fire", () => 0); - anim.PlayRepeating(self.Info.Traits.Get().Anim); - self.Trait().anims.Add("fire", - new RenderSimple.AnimationWithOffset(anim, () => new float2(0, -3), null)); - } - - if (--ticks <= 0) - { - self.InflictDamage(self, self.Info.Traits.Get().Damage, null); - ticks = self.Info.Traits.Get().Interval; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class BurnsInfo : TraitInfo + { + public readonly string Anim = "1"; + public readonly int Damage = 1; + public readonly int Interval = 8; + } + + class Burns : ITick, ISync + { + [Sync] + int ticks; + bool isSetup; + + public void Tick(Actor self) + { + if (!isSetup) + { + isSetup = true; + + var anim = new Animation("fire", () => 0); + anim.PlayRepeating(self.Info.Traits.Get().Anim); + self.Trait().anims.Add("fire", + new RenderSimple.AnimationWithOffset(anim, () => new float2(0, -3), null)); + } + + if (--ticks <= 0) + { + self.InflictDamage(self, self.Info.Traits.Get().Damage, null); + ticks = self.Info.Traits.Get().Interval; + } + } + } +} diff --git a/OpenRA.Mods.RA/C4Demolition.cs b/OpenRA.Mods.RA/C4Demolition.cs index 92e5b1d6ce..7bdb9ce367 100644 --- a/OpenRA.Mods.RA/C4Demolition.cs +++ b/OpenRA.Mods.RA/C4Demolition.cs @@ -1,62 +1,62 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using OpenRA.Effects; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Move; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class C4DemolitionInfo : TraitInfo - { - public readonly float C4Delay = 0; - } - - class C4Demolition : IIssueOrder, IResolveOrder, IOrderVoice - { - public IEnumerable Orders - { - get { yield return new UnitTraitOrderTargeter( "C4", 6, "c4", true, false ); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "C4" ) - return new Order("C4", self, queued) { TargetActor = target.Actor }; - - return null; - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "C4") - { - self.SetTargetLine(Target.FromOrder(order), Color.Red); - - var mobile = self.Trait(); - self.CancelActivity(); - self.QueueActivity(new Enter(order.TargetActor)); - //self.QueueActivity(new Move(order.TargetActor.Location, order.TargetActor)); - self.QueueActivity(new Demolish(order.TargetActor)); - self.QueueActivity(mobile.MoveTo(self.Location, 0)); - } - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - return (order.OrderString == "C4") ? "Attack" : null; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using OpenRA.Effects; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Move; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class C4DemolitionInfo : TraitInfo + { + public readonly float C4Delay = 0; + } + + class C4Demolition : IIssueOrder, IResolveOrder, IOrderVoice + { + public IEnumerable Orders + { + get { yield return new UnitTraitOrderTargeter( "C4", 6, "c4", true, false ); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "C4" ) + return new Order("C4", self, queued) { TargetActor = target.Actor }; + + return null; + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "C4") + { + self.SetTargetLine(Target.FromOrder(order), Color.Red); + + var mobile = self.Trait(); + self.CancelActivity(); + self.QueueActivity(new Enter(order.TargetActor)); + //self.QueueActivity(new Move(order.TargetActor.Location, order.TargetActor)); + self.QueueActivity(new Demolish(order.TargetActor)); + self.QueueActivity(mobile.MoveTo(self.Location, 0)); + } + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return (order.OrderString == "C4") ? "Attack" : null; + } + } +} diff --git a/OpenRA.Mods.RA/Cargo.cs b/OpenRA.Mods.RA/Cargo.cs index b564fed69e..4121fe820a 100644 --- a/OpenRA.Mods.RA/Cargo.cs +++ b/OpenRA.Mods.RA/Cargo.cs @@ -1,158 +1,158 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class CargoInfo : ITraitInfo - { - public readonly int Passengers = 0; - public readonly string[] Types = { }; - public readonly int UnloadFacing = 0; - - public object Create( ActorInitializer init ) { return new Cargo( init.self ); } - } - - public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderVoice, INotifyDamage - { - readonly Actor self; - List cargo = new List(); - public IEnumerable Passengers { get { return cargo; } } - - public Cargo( Actor self ) - { - this.self = self; - } - - public IEnumerable Orders - { - get - { - yield return new DeployOrderTargeter( "Unload", 10, () => CanUnload( self ) ); - yield return new UnitTraitOrderTargeter( "ReverseEnterTransport", 6, null, false, true ); - } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "Unload" ) - return new Order( order.OrderID, self, queued ); - - if( order.OrderID == "ReverseEnterTransport" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - return null; - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "Unload") - { - if (!CanUnload(self)) - return; - - self.CancelActivity(); - self.QueueActivity(new UnloadCargo()); - } - - if( order.OrderString == "ReverseEnterTransport" ) - { - if( order.TargetActor != null && order.Subject.Owner == order.TargetActor.Owner ) - { - var passenger = order.TargetActor.Trait(); - passenger.ResolveOrder(order.TargetActor, - new Order("EnterTransport", order.TargetActor, false) { TargetActor = self }); - } - } - } - - bool CanUnload(Actor self) - { - if (IsEmpty(self)) - return false; - - // Cannot unload mid-air - var move = self.TraitOrDefault(); - if (move != null && move.Altitude > 0) - return false; - - // Todo: Check if there is a free tile to unload to - return true; - } - - public string CursorForOrder(Actor self, Order order) - { - if (order.OrderString != "Unload") return null; - return CanUnload(self) ? "deploy" : "deploy-blocked"; - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - if (order.OrderString != "Unload" || IsEmpty(self)) return null; - return "Move"; - } - - public bool IsFull(Actor self) - { - return cargo.Count == self.Info.Traits.Get().Passengers; - } - - public bool IsEmpty(Actor self) - { - return cargo.Count == 0; - } - - public Actor Peek(Actor self) - { - return cargo[0]; - } - - public Actor Unload(Actor self) - { - var a = cargo[0]; - cargo.RemoveAt(0); - return a; - } - - public IEnumerable GetPips( Actor self ) - { - var numPips = self.Info.Traits.Get().Passengers; - for (var i = 0; i < numPips; i++) - if (i >= cargo.Count) - yield return PipType.Transparent; - else - yield return GetPipForPassenger(cargo[i]); - } - - static PipType GetPipForPassenger(Actor a) - { - return a.Trait().ColorOfCargoPip( a ); - } - - public void Load(Actor self, Actor a) - { - cargo.Add(a); - } - - public void Damaged(Actor self, AttackInfo e) - { - if( e.DamageStateChanged && e.DamageState == DamageState.Dead ) - { - foreach( var c in cargo ) - c.Destroy(); - cargo.Clear(); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class CargoInfo : ITraitInfo + { + public readonly int Passengers = 0; + public readonly string[] Types = { }; + public readonly int UnloadFacing = 0; + + public object Create( ActorInitializer init ) { return new Cargo( init.self ); } + } + + public class Cargo : IPips, IIssueOrder, IResolveOrder, IOrderVoice, INotifyDamage + { + readonly Actor self; + List cargo = new List(); + public IEnumerable Passengers { get { return cargo; } } + + public Cargo( Actor self ) + { + this.self = self; + } + + public IEnumerable Orders + { + get + { + yield return new DeployOrderTargeter( "Unload", 10, () => CanUnload( self ) ); + yield return new UnitTraitOrderTargeter( "ReverseEnterTransport", 6, null, false, true ); + } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "Unload" ) + return new Order( order.OrderID, self, queued ); + + if( order.OrderID == "ReverseEnterTransport" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + return null; + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Unload") + { + if (!CanUnload(self)) + return; + + self.CancelActivity(); + self.QueueActivity(new UnloadCargo()); + } + + if( order.OrderString == "ReverseEnterTransport" ) + { + if( order.TargetActor != null && order.Subject.Owner == order.TargetActor.Owner ) + { + var passenger = order.TargetActor.Trait(); + passenger.ResolveOrder(order.TargetActor, + new Order("EnterTransport", order.TargetActor, false) { TargetActor = self }); + } + } + } + + bool CanUnload(Actor self) + { + if (IsEmpty(self)) + return false; + + // Cannot unload mid-air + var move = self.TraitOrDefault(); + if (move != null && move.Altitude > 0) + return false; + + // Todo: Check if there is a free tile to unload to + return true; + } + + public string CursorForOrder(Actor self, Order order) + { + if (order.OrderString != "Unload") return null; + return CanUnload(self) ? "deploy" : "deploy-blocked"; + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + if (order.OrderString != "Unload" || IsEmpty(self)) return null; + return "Move"; + } + + public bool IsFull(Actor self) + { + return cargo.Count == self.Info.Traits.Get().Passengers; + } + + public bool IsEmpty(Actor self) + { + return cargo.Count == 0; + } + + public Actor Peek(Actor self) + { + return cargo[0]; + } + + public Actor Unload(Actor self) + { + var a = cargo[0]; + cargo.RemoveAt(0); + return a; + } + + public IEnumerable GetPips( Actor self ) + { + var numPips = self.Info.Traits.Get().Passengers; + for (var i = 0; i < numPips; i++) + if (i >= cargo.Count) + yield return PipType.Transparent; + else + yield return GetPipForPassenger(cargo[i]); + } + + static PipType GetPipForPassenger(Actor a) + { + return a.Trait().ColorOfCargoPip( a ); + } + + public void Load(Actor self, Actor a) + { + cargo.Add(a); + } + + public void Damaged(Actor self, AttackInfo e) + { + if( e.DamageStateChanged && e.DamageState == DamageState.Dead ) + { + foreach( var c in cargo ) + c.Destroy(); + cargo.Clear(); + } + } + } +} diff --git a/OpenRA.Mods.RA/CarpetBomb.cs b/OpenRA.Mods.RA/CarpetBomb.cs index 4069b4c3ae..e8ef651cb9 100644 --- a/OpenRA.Mods.RA/CarpetBomb.cs +++ b/OpenRA.Mods.RA/CarpetBomb.cs @@ -1,64 +1,64 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.GameRules; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class CarpetBombInfo : TraitInfo - { - [WeaponReference] - public readonly string Weapon = null; - public readonly int Range = 3; - } - - class CarpetBomb : ITick // todo: maybe integrate this better with the normal weapons system? - { - int2 Target; - int dropDelay; - - public void SetTarget(int2 targetCell) { Target = targetCell; } - - public void Tick(Actor self) - { - var info = self.Info.Traits.Get(); - - if( !Combat.IsInRange( self.CenterLocation, info.Range, Target * Game.CellSize ) ) - return; - - var limitedAmmo = self.TraitOrDefault(); - if (limitedAmmo != null && !limitedAmmo.HasAmmo()) - return; - - if (--dropDelay <= 0) - { - var weapon = Rules.Weapons[info.Weapon.ToLowerInvariant()]; - dropDelay = weapon.ROF; - - var args = new ProjectileArgs - { - srcAltitude = self.Trait().Altitude, - destAltitude = 0, - src = self.CenterLocation, - dest = self.CenterLocation, - facing = self.Trait().Facing, - firedBy = self, - weapon = weapon - }; - - self.World.Add(args.weapon.Projectile.Create(args)); - - if (!string.IsNullOrEmpty(args.weapon.Report)) - Sound.Play(args.weapon.Report + ".aud", self.CenterLocation); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class CarpetBombInfo : TraitInfo + { + [WeaponReference] + public readonly string Weapon = null; + public readonly int Range = 3; + } + + class CarpetBomb : ITick // todo: maybe integrate this better with the normal weapons system? + { + int2 Target; + int dropDelay; + + public void SetTarget(int2 targetCell) { Target = targetCell; } + + public void Tick(Actor self) + { + var info = self.Info.Traits.Get(); + + if( !Combat.IsInRange( self.CenterLocation, info.Range, Target * Game.CellSize ) ) + return; + + var limitedAmmo = self.TraitOrDefault(); + if (limitedAmmo != null && !limitedAmmo.HasAmmo()) + return; + + if (--dropDelay <= 0) + { + var weapon = Rules.Weapons[info.Weapon.ToLowerInvariant()]; + dropDelay = weapon.ROF; + + var args = new ProjectileArgs + { + srcAltitude = self.Trait().Altitude, + destAltitude = 0, + src = self.CenterLocation, + dest = self.CenterLocation, + facing = self.Trait().Facing, + firedBy = self, + weapon = weapon + }; + + self.World.Add(args.weapon.Projectile.Create(args)); + + if (!string.IsNullOrEmpty(args.weapon.Report)) + Sound.Play(args.weapon.Report + ".aud", self.CenterLocation); + } + } + } +} diff --git a/OpenRA.Mods.RA/CashTrickler.cs b/OpenRA.Mods.RA/CashTrickler.cs index f25d10046d..6036887334 100644 --- a/OpenRA.Mods.RA/CashTrickler.cs +++ b/OpenRA.Mods.RA/CashTrickler.cs @@ -1,36 +1,36 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class CashTricklerInfo : TraitInfo - { - public readonly int Period = 10; - public readonly int Amount = 3; - } - - class CashTrickler : ITick, ISync - { - [Sync] - int ticks; - - public void Tick(Actor self) - { - if (--ticks < 0) - { - var info = self.Info.Traits.Get(); - self.Owner.PlayerActor.Trait().GiveCash(info.Amount); - ticks = info.Period; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class CashTricklerInfo : TraitInfo + { + public readonly int Period = 10; + public readonly int Amount = 3; + } + + class CashTrickler : ITick, ISync + { + [Sync] + int ticks; + + public void Tick(Actor self) + { + if (--ticks < 0) + { + var info = self.Info.Traits.Get(); + self.Owner.PlayerActor.Trait().GiveCash(info.Amount); + ticks = info.Period; + } + } + } +} diff --git a/OpenRA.Mods.RA/ChronoshiftDeploy.cs b/OpenRA.Mods.RA/ChronoshiftDeploy.cs index 34e6a2f94f..ab129f1420 100644 --- a/OpenRA.Mods.RA/ChronoshiftDeploy.cs +++ b/OpenRA.Mods.RA/ChronoshiftDeploy.cs @@ -1,105 +1,105 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class ChronoshiftDeployInfo : TraitInfo - { - public readonly int ChargeTime = 120; // Seconds - } - - class ChronoshiftDeploy : IIssueOrder, IResolveOrder, ITick, IPips, IOrderVoice, ISync - { - // Recharge logic - [Sync] - int chargeTick = 0; // How long until we can chronoshift again? - - public void Tick(Actor self) - { - if (chargeTick > 0) - chargeTick--; - } - - public IEnumerable Orders - { - get { yield return new DeployOrderTargeter( "ChronoshiftDeploy", 5, () => chargeTick <= 0 ); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "ChronoshiftDeploy" ) - if (chargeTick <= 0) - self.World.OrderGenerator = new SetChronoTankDestination( self ); - - return null; - } - - public void ResolveOrder(Actor self, Order order) - { - var movement = self.TraitOrDefault(); - if (order.OrderString == "ChronoshiftSelf" && movement.CanEnterCell(order.TargetLocation)) - { - if (self.Owner == self.World.LocalPlayer) - { - self.World.CancelInputMode(); - } - - self.CancelActivity(); - self.QueueActivity(new Teleport(order.TargetLocation)); - Sound.Play("chrotnk1.aud", self.CenterLocation); - Sound.Play("chrotnk1.aud", Game.CellSize * order.TargetLocation.ToFloat2()); - chargeTick = 25 * self.Info.Traits.Get().ChargeTime; - - foreach (var a in self.World.Queries.WithTrait()) - a.Trait.Enable(); - } - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - return (order.OrderString == "ChronoshiftDeploy" && chargeTick <= 0) ? "Move" : null; - } - - // Display 5 pips indicating the current charge status - public IEnumerable GetPips(Actor self) - { - const int numPips = 5; - for (int i = 0; i < numPips; i++) - { - if ((1 - chargeTick * 1.0f / (25 * self.Info.Traits.Get().ChargeTime)) * numPips < i + 1) - { - yield return PipType.Transparent; - continue; - } - - switch (i) - { - case 0: - case 1: - yield return PipType.Red; - break; - case 2: - case 3: - yield return PipType.Yellow; - break; - case 4: - yield return PipType.Green; - break; - } - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class ChronoshiftDeployInfo : TraitInfo + { + public readonly int ChargeTime = 120; // Seconds + } + + class ChronoshiftDeploy : IIssueOrder, IResolveOrder, ITick, IPips, IOrderVoice, ISync + { + // Recharge logic + [Sync] + int chargeTick = 0; // How long until we can chronoshift again? + + public void Tick(Actor self) + { + if (chargeTick > 0) + chargeTick--; + } + + public IEnumerable Orders + { + get { yield return new DeployOrderTargeter( "ChronoshiftDeploy", 5, () => chargeTick <= 0 ); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "ChronoshiftDeploy" ) + if (chargeTick <= 0) + self.World.OrderGenerator = new SetChronoTankDestination( self ); + + return null; + } + + public void ResolveOrder(Actor self, Order order) + { + var movement = self.TraitOrDefault(); + if (order.OrderString == "ChronoshiftSelf" && movement.CanEnterCell(order.TargetLocation)) + { + if (self.Owner == self.World.LocalPlayer) + { + self.World.CancelInputMode(); + } + + self.CancelActivity(); + self.QueueActivity(new Teleport(order.TargetLocation)); + Sound.Play("chrotnk1.aud", self.CenterLocation); + Sound.Play("chrotnk1.aud", Game.CellSize * order.TargetLocation.ToFloat2()); + chargeTick = 25 * self.Info.Traits.Get().ChargeTime; + + foreach (var a in self.World.Queries.WithTrait()) + a.Trait.Enable(); + } + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return (order.OrderString == "ChronoshiftDeploy" && chargeTick <= 0) ? "Move" : null; + } + + // Display 5 pips indicating the current charge status + public IEnumerable GetPips(Actor self) + { + const int numPips = 5; + for (int i = 0; i < numPips; i++) + { + if ((1 - chargeTick * 1.0f / (25 * self.Info.Traits.Get().ChargeTime)) * numPips < i + 1) + { + yield return PipType.Transparent; + continue; + } + + switch (i) + { + case 0: + case 1: + yield return PipType.Red; + break; + case 2: + case 3: + yield return PipType.Yellow; + break; + case 4: + yield return PipType.Green; + break; + } + } + } + } +} diff --git a/OpenRA.Mods.RA/ChronoshiftPaletteEffect.cs b/OpenRA.Mods.RA/ChronoshiftPaletteEffect.cs index ff91094fc1..b9007173e9 100644 --- a/OpenRA.Mods.RA/ChronoshiftPaletteEffect.cs +++ b/OpenRA.Mods.RA/ChronoshiftPaletteEffect.cs @@ -1,58 +1,58 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class ChronoshiftPaletteEffectInfo : TraitInfo { } - - public class ChronoshiftPaletteEffect : IPaletteModifier, ITick - { - const int chronoEffectLength = 20; - int remainingFrames; - - public void Enable() - { - remainingFrames = chronoEffectLength; - } - - public void Tick(Actor self) - { - if (remainingFrames > 0) - remainingFrames--; - } - - public void AdjustPalette(Dictionary palettes) - { - if (remainingFrames == 0) - return; - - var frac = (float)remainingFrames / chronoEffectLength; - var excludePalettes = new List(){"cursor", "chrome", "colorpicker", "shroud", "fog"}; - foreach (var pal in palettes) - { - if (excludePalettes.Contains(pal.Key)) - continue; - - for (var x = 0; x < 256; x++) - { - var orig = pal.Value.GetColor(x); - var lum = (int)(255 * orig.GetBrightness()); - var desat = Color.FromArgb(orig.A, lum, lum, lum); - pal.Value.SetColor(x, OpenRA.Graphics.Util.Lerp(frac, orig, desat)); - } - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class ChronoshiftPaletteEffectInfo : TraitInfo { } + + public class ChronoshiftPaletteEffect : IPaletteModifier, ITick + { + const int chronoEffectLength = 20; + int remainingFrames; + + public void Enable() + { + remainingFrames = chronoEffectLength; + } + + public void Tick(Actor self) + { + if (remainingFrames > 0) + remainingFrames--; + } + + public void AdjustPalette(Dictionary palettes) + { + if (remainingFrames == 0) + return; + + var frac = (float)remainingFrames / chronoEffectLength; + var excludePalettes = new List(){"cursor", "chrome", "colorpicker", "shroud", "fog"}; + foreach (var pal in palettes) + { + if (excludePalettes.Contains(pal.Key)) + continue; + + for (var x = 0; x < 256; x++) + { + var orig = pal.Value.GetColor(x); + var lum = (int)(255 * orig.GetBrightness()); + var desat = Color.FromArgb(orig.A, lum, lum, lum); + pal.Value.SetColor(x, OpenRA.Graphics.Util.Lerp(frac, orig, desat)); + } + } + } + } +} diff --git a/OpenRA.Mods.RA/Chronoshiftable.cs b/OpenRA.Mods.RA/Chronoshiftable.cs index 96babb4b4e..c062e64d9e 100755 --- a/OpenRA.Mods.RA/Chronoshiftable.cs +++ b/OpenRA.Mods.RA/Chronoshiftable.cs @@ -1,77 +1,77 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Activities; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class ChronoshiftableInfo : TraitInfo { } - - public class Chronoshiftable : ITick, ISync - { - // Return-to-sender logic - [Sync] - int2 chronoshiftOrigin; - [Sync] - int chronoshiftReturnTicks = 0; - - public void Tick(Actor self) - { - if (chronoshiftReturnTicks <= 0) - return; - - if (chronoshiftReturnTicks > 0) - chronoshiftReturnTicks--; - - // Return to original location - if (chronoshiftReturnTicks == 0) - { - self.CancelActivity(); - // Todo: need a new Teleport method that will move to the closest available cell - self.QueueActivity(new Teleport(chronoshiftOrigin)); - } - } - - // Can't be used in synced code, except with ignoreVis. - public virtual bool CanChronoshiftTo(Actor self, int2 targetLocation, bool ignoreVis) - { - // Todo: Allow enemy units to be chronoshifted into bad terrain to kill them - return self.HasTrait() && - self.Trait().CanEnterCell(targetLocation) && - (ignoreVis || self.World.LocalShroud.IsExplored(targetLocation)); - } - - public virtual bool Teleport(Actor self, int2 targetLocation, int duration, bool killCargo, Actor chronosphere) - { - /// Set up return-to-sender info - chronoshiftOrigin = self.Location; - chronoshiftReturnTicks = duration; - - // Kill cargo - if (killCargo && self.HasTrait()) - { - var cargo = self.Trait(); - while (!cargo.IsEmpty(self)) - { - chronosphere.Owner.Kills++; - var a = cargo.Unload(self); - a.Owner.Deaths++; - } - } - - // Set up the teleport - self.CancelActivity(); - self.QueueActivity(new Teleport(targetLocation)); - - return true; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class ChronoshiftableInfo : TraitInfo { } + + public class Chronoshiftable : ITick, ISync + { + // Return-to-sender logic + [Sync] + int2 chronoshiftOrigin; + [Sync] + int chronoshiftReturnTicks = 0; + + public void Tick(Actor self) + { + if (chronoshiftReturnTicks <= 0) + return; + + if (chronoshiftReturnTicks > 0) + chronoshiftReturnTicks--; + + // Return to original location + if (chronoshiftReturnTicks == 0) + { + self.CancelActivity(); + // Todo: need a new Teleport method that will move to the closest available cell + self.QueueActivity(new Teleport(chronoshiftOrigin)); + } + } + + // Can't be used in synced code, except with ignoreVis. + public virtual bool CanChronoshiftTo(Actor self, int2 targetLocation, bool ignoreVis) + { + // Todo: Allow enemy units to be chronoshifted into bad terrain to kill them + return self.HasTrait() && + self.Trait().CanEnterCell(targetLocation) && + (ignoreVis || self.World.LocalShroud.IsExplored(targetLocation)); + } + + public virtual bool Teleport(Actor self, int2 targetLocation, int duration, bool killCargo, Actor chronosphere) + { + /// Set up return-to-sender info + chronoshiftOrigin = self.Location; + chronoshiftReturnTicks = duration; + + // Kill cargo + if (killCargo && self.HasTrait()) + { + var cargo = self.Trait(); + while (!cargo.IsEmpty(self)) + { + chronosphere.Owner.Kills++; + var a = cargo.Unload(self); + a.Owner.Deaths++; + } + } + + // Set up the teleport + self.CancelActivity(); + self.QueueActivity(new Teleport(targetLocation)); + + return true; + } + } +} diff --git a/OpenRA.Mods.RA/Cloak.cs b/OpenRA.Mods.RA/Cloak.cs index 01f68463d8..98eaf414ce 100644 --- a/OpenRA.Mods.RA/Cloak.cs +++ b/OpenRA.Mods.RA/Cloak.cs @@ -1,126 +1,126 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class CloakInfo : ITraitInfo - { - public readonly float InitialDelay = .4f; // seconds - public readonly float CloakDelay = 1.2f; // Seconds - public readonly string CloakSound = "subshow1.aud"; - public readonly string UncloakSound = "subshow1.aud"; - - public CloakInfo() { } /* only because we have other ctors */ - - /* for CloakCrateAction */ - public CloakInfo(float initialDelay, float cloakDelay, string cloakSound, string uncloakSound) - { - InitialDelay = initialDelay; - CloakDelay = cloakDelay; - CloakSound = cloakSound; - UncloakSound = uncloakSound; - } - - public object Create(ActorInitializer init) { return new Cloak(init.self, this); } - } - - public class Cloak : IRenderModifier, INotifyDamage, INotifyAttack, ITick, IVisibilityModifier, IRadarColorModifier, ISync - { - [Sync] - int remainingTime; - [Sync] - bool canCloak = true; - - Actor self; - CloakInfo info; - public Cloak(Actor self, CloakInfo info) - { - this.info = info; - this.self = self; - - remainingTime = (int)(info.InitialDelay * 25); - } - - void DoUncloak() - { - if (remainingTime <= 0) - OnCloak(); - - remainingTime = Math.Max(remainingTime, (int)(info.CloakDelay * 25)); - } - - public void Attacking(Actor self, Target target) { DoUncloak(); } - public void Damaged(Actor self, AttackInfo e) - { - canCloak = (e.DamageState < DamageState.Critical); - if (Cloaked && !canCloak) - DoUncloak(); - } - - public IEnumerable - ModifyRender(Actor self, IEnumerable rs) - { - if (remainingTime > 0) - return rs; - - if (Cloaked && IsVisible(self)) - return rs.Select(a => a.WithPalette("shadow")); - else - return new Renderable[] { }; - } - - public void Tick(Actor self) - { - if (remainingTime > 0 && canCloak) - if (--remainingTime <= 0) - OnCloak(); - } - - void OnUncloak() - { - Sound.Play(info.UncloakSound, self.CenterLocation); - } - - void OnCloak() - { - Sound.Play(info.CloakSound, self.CenterLocation); - } - - public bool Cloaked { get { return remainingTime == 0; } } - - public bool IsVisible(Actor self) - { - if (!Cloaked || self.Owner == self.World.LocalPlayer || self.Owner.Stances[self.World.LocalPlayer] == Stance.Ally) - return true; - - return self.World.Queries.WithTrait().Any(a => (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get().Range); - } - - public Color RadarColorOverride(Actor self) - { - var c = self.Owner.ColorRamp.GetColor(0); - if (self.Owner == self.World.LocalPlayer && Cloaked) - c = Color.FromArgb(128, c); - return c; - } - - public void Decloak(int time) - { - DoUncloak(); - remainingTime = Math.Max(remainingTime, time); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class CloakInfo : ITraitInfo + { + public readonly float InitialDelay = .4f; // seconds + public readonly float CloakDelay = 1.2f; // Seconds + public readonly string CloakSound = "subshow1.aud"; + public readonly string UncloakSound = "subshow1.aud"; + + public CloakInfo() { } /* only because we have other ctors */ + + /* for CloakCrateAction */ + public CloakInfo(float initialDelay, float cloakDelay, string cloakSound, string uncloakSound) + { + InitialDelay = initialDelay; + CloakDelay = cloakDelay; + CloakSound = cloakSound; + UncloakSound = uncloakSound; + } + + public object Create(ActorInitializer init) { return new Cloak(init.self, this); } + } + + public class Cloak : IRenderModifier, INotifyDamage, INotifyAttack, ITick, IVisibilityModifier, IRadarColorModifier, ISync + { + [Sync] + int remainingTime; + [Sync] + bool canCloak = true; + + Actor self; + CloakInfo info; + public Cloak(Actor self, CloakInfo info) + { + this.info = info; + this.self = self; + + remainingTime = (int)(info.InitialDelay * 25); + } + + void DoUncloak() + { + if (remainingTime <= 0) + OnCloak(); + + remainingTime = Math.Max(remainingTime, (int)(info.CloakDelay * 25)); + } + + public void Attacking(Actor self, Target target) { DoUncloak(); } + public void Damaged(Actor self, AttackInfo e) + { + canCloak = (e.DamageState < DamageState.Critical); + if (Cloaked && !canCloak) + DoUncloak(); + } + + public IEnumerable + ModifyRender(Actor self, IEnumerable rs) + { + if (remainingTime > 0) + return rs; + + if (Cloaked && IsVisible(self)) + return rs.Select(a => a.WithPalette("shadow")); + else + return new Renderable[] { }; + } + + public void Tick(Actor self) + { + if (remainingTime > 0 && canCloak) + if (--remainingTime <= 0) + OnCloak(); + } + + void OnUncloak() + { + Sound.Play(info.UncloakSound, self.CenterLocation); + } + + void OnCloak() + { + Sound.Play(info.CloakSound, self.CenterLocation); + } + + public bool Cloaked { get { return remainingTime == 0; } } + + public bool IsVisible(Actor self) + { + if (!Cloaked || self.Owner == self.World.LocalPlayer || self.Owner.Stances[self.World.LocalPlayer] == Stance.Ally) + return true; + + return self.World.Queries.WithTrait().Any(a => (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get().Range); + } + + public Color RadarColorOverride(Actor self) + { + var c = self.Owner.ColorRamp.GetColor(0); + if (self.Owner == self.World.LocalPlayer && Cloaked) + c = Color.FromArgb(128, c); + return c; + } + + public void Decloak(int time) + { + DoUncloak(); + remainingTime = Math.Max(remainingTime, time); + } + } +} diff --git a/OpenRA.Mods.RA/ColorPickerPaletteModifier.cs b/OpenRA.Mods.RA/ColorPickerPaletteModifier.cs index 6127f2192c..bcc7f148b6 100644 --- a/OpenRA.Mods.RA/ColorPickerPaletteModifier.cs +++ b/OpenRA.Mods.RA/ColorPickerPaletteModifier.cs @@ -1,18 +1,18 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Collections.Generic; -using OpenRA.FileFormats; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Widgets.Delegates; -using OpenRA.Traits; +#endregion + +using System.Collections.Generic; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Widgets.Delegates; +using OpenRA.Traits; namespace OpenRA.Mods.RA { @@ -21,17 +21,17 @@ namespace OpenRA.Mods.RA class ColorPickerPaletteModifier : IPalette, IPaletteModifier { PaletteFormat format; - public void InitPalette( WorldRenderer wr ) - { + public void InitPalette( WorldRenderer wr ) + { var info = Rules.Info["player"].Traits.Get(); format = info.PaletteFormat; wr.AddPalette("colorpicker", wr.GetPalette(info.BasePalette)); - } - - public void AdjustPalette(Dictionary palettes) - { - palettes["colorpicker"] = new Palette(palettes["colorpicker"], - new PlayerColorRemap(LobbyDelegate.CurrentColorPreview, format)); - } + } + + public void AdjustPalette(Dictionary palettes) + { + palettes["colorpicker"] = new Palette(palettes["colorpicker"], + new PlayerColorRemap(LobbyDelegate.CurrentColorPreview, format)); + } } } diff --git a/OpenRA.Mods.RA/Combat.cs b/OpenRA.Mods.RA/Combat.cs index 7891c05669..7b2860d8b8 100755 --- a/OpenRA.Mods.RA/Combat.cs +++ b/OpenRA.Mods.RA/Combat.cs @@ -1,248 +1,248 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; -using OpenRA.Effects; -using OpenRA.GameRules; -using OpenRA.Mods.RA.Effects; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public static class Combat /* some utility bits that are shared between various things */ - { - static string GetImpactSound(WarheadInfo warhead, bool isWater) - { - if (isWater && warhead.WaterImpactSound != null) - return warhead.WaterImpactSound + ".aud"; - - if (warhead.ImpactSound != null) - return warhead.ImpactSound + ".aud"; - - return null; - } - - public static void DoImpact(WarheadInfo warhead, ProjectileArgs args) - { - var world = args.firedBy.World; - var targetTile = Util.CellContaining(args.dest); - - if (!world.Map.IsInMap(targetTile)) - return; - - var isWater = world.GetTerrainInfo(targetTile).IsWater; - var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion; - - if (explosionType != null) - world.AddFrameEndTask( - w => w.Add(new Explosion(w, args.dest, explosionType, isWater, args.destAltitude))); - - Sound.Play(GetImpactSound(warhead, isWater), args.dest); - - if (warhead.SmudgeType != null) - { - var smudgeLayer = world.WorldActor.TraitsImplementing() - .FirstOrDefault(x => x.Info.Type == warhead.SmudgeType); - if (smudgeLayer == null) - throw new NotImplementedException("Unknown smudge type `{0}`".F(warhead.SmudgeType)); - - if (warhead.Size[0] > 0) - { - var smudgeCells = world.FindTilesInCircle(targetTile, warhead.Size[0]); - if (warhead.Size.Length == 2 ) - smudgeCells = smudgeCells.Except(world.FindTilesInCircle(targetTile, warhead.Size[1])) ; - - foreach (var sc in smudgeCells) - { - smudgeLayer.AddSmudge(sc); - if (warhead.Ore) - world.WorldActor.Trait().Destroy(sc); - } - } - else - smudgeLayer.AddSmudge(targetTile); - } - - if (warhead.Ore) - world.WorldActor.Trait().Destroy(targetTile); - - switch (warhead.DamageModel) - { - case DamageModel.Normal: - { - var maxSpread = warhead.Spread * (float)Math.Log(Math.Abs(warhead.Damage), 2); - var hitActors = world.FindUnitsInCircle(args.dest, maxSpread); - - foreach (var victim in hitActors) - { - var damage = (int)GetDamageToInflict(victim, args, warhead, args.firepowerModifier); - victim.InflictDamage(args.firedBy, damage, warhead); - } - } break; - - case DamageModel.PerCell: - { - foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0])) - foreach (var unit in world.FindUnits(Game.CellSize * t, Game.CellSize * (t + new float2(1,1)))) - unit.InflictDamage(args.firedBy, - (int)(warhead.Damage * warhead.EffectivenessAgainst(unit)), warhead); - } break; - } - } - - public static void DoImpacts(ProjectileArgs args) - { - foreach (var warhead in args.weapon.Warheads) - { - Action a = () => DoImpact(warhead, args); - if (warhead.Delay > 0) - args.firedBy.World.AddFrameEndTask( - w => w.Add(new DelayedAction(warhead.Delay, a))); - else - a(); - } - } - - public static void DoExplosion(Actor attacker, string weapontype, int2 pos, int altitude) - { - var args = new ProjectileArgs - { - src = pos, - dest = pos, - srcAltitude = altitude, - destAltitude = altitude, - firedBy = attacker, - target = Target.FromPos(pos), - weapon = Rules.Weapons[ weapontype.ToLowerInvariant() ], - facing = 0 - }; - - if (args.weapon.Report != null) - Sound.Play(args.weapon.Report + ".aud", pos); - - DoImpacts(args); - } - - static readonly float[] falloff = - { - 1f, 0.3678795f, 0.1353353f, 0.04978707f, - 0.01831564f, 0.006737947f, 0.002478752f, 0.000911882f - }; - - static float GetDamageFalloff(float x) - { - var u = (int)x; - if (u >= falloff.Length - 1) return 0; - var t = x - u; - return (falloff[u] * (1 - t)) + (falloff[u + 1] * t); - } - - static float GetDamageToInflict(Actor target, ProjectileArgs args, WarheadInfo warhead, float modifier) - { - // don't hit air units with splash from ground explosions, etc - if (!WeaponValidForTarget(args.weapon, target)) return 0f; - - var health = target.Info.Traits.GetOrDefault(); - if( health == null ) return 0f; - - var distance = (int)Math.Max(0, (target.CenterLocation - args.dest).Length - health.Radius); - var falloff = (float)GetDamageFalloff(distance / warhead.Spread); - var rawDamage = (float)(warhead.Damage * modifier * falloff); - var multiplier = (float)warhead.EffectivenessAgainst(target); - - return (float)(rawDamage * multiplier); - } - - public static bool WeaponValidForTarget(WeaponInfo weapon, Actor target) +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.Effects; +using OpenRA.GameRules; +using OpenRA.Mods.RA.Effects; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public static class Combat /* some utility bits that are shared between various things */ + { + static string GetImpactSound(WarheadInfo warhead, bool isWater) { - var targetable = target.TraitOrDefault(); - if (targetable == null || !weapon.ValidTargets.Intersect(targetable.TargetTypes).Any()) - return false; - - if (weapon.Warheads.All( w => w.EffectivenessAgainst(target) <= 0)) - return false; - - return true; - } - - public static bool WeaponValidForTarget( WeaponInfo weapon, World world, int2 location ) - { - if( weapon.ValidTargets.Contains( "Ground" ) && world.GetTerrainType( location ) != "Water" ) return true; - if( weapon.ValidTargets.Contains( "Water" ) && world.GetTerrainType( location ) == "Water" ) return true; - return false; - } - - static float2 GetRecoil(Actor self, float recoil) - { - var abInfo = self.Info.Traits.GetOrDefault(); - if (abInfo == null || abInfo.Recoil == 0) return float2.Zero; - - var rut = self.TraitOrDefault(); - if (rut == null) return float2.Zero; - - var facing = self.Trait().turretFacing; - var localRecoil = new float2(0, recoil * abInfo.Recoil); // vector in turret-space. - - return Util.RotateVectorByFacing(localRecoil, facing, .7f); - } - public static float2 GetTurretPosition(Actor self, IFacing facing, Turret turret) - { - if(facing == null) return turret.ScreenSpacePosition; /* things that don't have a rotating base don't need the turrets repositioned */ - - var ru = self.TraitOrDefault(); - var numDirs = (ru != null) ? ru.anim.CurrentSequence.Facings : 8; - var bodyFacing = facing.Facing; - var quantizedFacing = Util.QuantizeFacing(bodyFacing, numDirs) * (256 / numDirs); - - return (Util.RotateVectorByFacing(turret.UnitSpacePosition, quantizedFacing, .7f) - + GetRecoil(self, turret.Recoil)) - + turret.ScreenSpacePosition; - } - - // gets the screen-space position of a barrel. - public static float2 GetBarrelPosition(Actor self, IFacing facing, Turret turret, Barrel barrel) - { - var turreted = self.TraitOrDefault(); - - if (turreted == null && facing == null) - return float2.Zero; - - var turretFacing = turreted != null ? turreted.turretFacing : facing.Facing; - - return Util.RotateVectorByFacing(barrel.Position, turretFacing, .7f); - } - - public static bool IsInRange( float2 attackOrigin, float range, Actor target ) - { - var rsq = range * range * Game.CellSize * Game.CellSize; - foreach( var cell in target.Trait().TargetableCells( target ) ) - if( ( attackOrigin - cell * Game.CellSize ).LengthSquared <= rsq ) - return true; - return false; - } - - public static bool IsInRange( float2 attackOrigin, float range, float2 targetLocation ) - { - var rsq = range * range * Game.CellSize * Game.CellSize; - return ( attackOrigin - targetLocation ).LengthSquared <= rsq; - } - - public static bool IsInRange( float2 attackOrigin, float range, Target target ) - { - if( !target.IsValid ) return false; - if( target.IsActor ) - return IsInRange( attackOrigin, range, target.Actor ); - else - return IsInRange( attackOrigin, range, target.CenterLocation ); - } - } -} + if (isWater && warhead.WaterImpactSound != null) + return warhead.WaterImpactSound + ".aud"; + + if (warhead.ImpactSound != null) + return warhead.ImpactSound + ".aud"; + + return null; + } + + public static void DoImpact(WarheadInfo warhead, ProjectileArgs args) + { + var world = args.firedBy.World; + var targetTile = Util.CellContaining(args.dest); + + if (!world.Map.IsInMap(targetTile)) + return; + + var isWater = world.GetTerrainInfo(targetTile).IsWater; + var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion; + + if (explosionType != null) + world.AddFrameEndTask( + w => w.Add(new Explosion(w, args.dest, explosionType, isWater, args.destAltitude))); + + Sound.Play(GetImpactSound(warhead, isWater), args.dest); + + if (warhead.SmudgeType != null) + { + var smudgeLayer = world.WorldActor.TraitsImplementing() + .FirstOrDefault(x => x.Info.Type == warhead.SmudgeType); + if (smudgeLayer == null) + throw new NotImplementedException("Unknown smudge type `{0}`".F(warhead.SmudgeType)); + + if (warhead.Size[0] > 0) + { + var smudgeCells = world.FindTilesInCircle(targetTile, warhead.Size[0]); + if (warhead.Size.Length == 2 ) + smudgeCells = smudgeCells.Except(world.FindTilesInCircle(targetTile, warhead.Size[1])) ; + + foreach (var sc in smudgeCells) + { + smudgeLayer.AddSmudge(sc); + if (warhead.Ore) + world.WorldActor.Trait().Destroy(sc); + } + } + else + smudgeLayer.AddSmudge(targetTile); + } + + if (warhead.Ore) + world.WorldActor.Trait().Destroy(targetTile); + + switch (warhead.DamageModel) + { + case DamageModel.Normal: + { + var maxSpread = warhead.Spread * (float)Math.Log(Math.Abs(warhead.Damage), 2); + var hitActors = world.FindUnitsInCircle(args.dest, maxSpread); + + foreach (var victim in hitActors) + { + var damage = (int)GetDamageToInflict(victim, args, warhead, args.firepowerModifier); + victim.InflictDamage(args.firedBy, damage, warhead); + } + } break; + + case DamageModel.PerCell: + { + foreach (var t in world.FindTilesInCircle(targetTile, warhead.Size[0])) + foreach (var unit in world.FindUnits(Game.CellSize * t, Game.CellSize * (t + new float2(1,1)))) + unit.InflictDamage(args.firedBy, + (int)(warhead.Damage * warhead.EffectivenessAgainst(unit)), warhead); + } break; + } + } + + public static void DoImpacts(ProjectileArgs args) + { + foreach (var warhead in args.weapon.Warheads) + { + Action a = () => DoImpact(warhead, args); + if (warhead.Delay > 0) + args.firedBy.World.AddFrameEndTask( + w => w.Add(new DelayedAction(warhead.Delay, a))); + else + a(); + } + } + + public static void DoExplosion(Actor attacker, string weapontype, int2 pos, int altitude) + { + var args = new ProjectileArgs + { + src = pos, + dest = pos, + srcAltitude = altitude, + destAltitude = altitude, + firedBy = attacker, + target = Target.FromPos(pos), + weapon = Rules.Weapons[ weapontype.ToLowerInvariant() ], + facing = 0 + }; + + if (args.weapon.Report != null) + Sound.Play(args.weapon.Report + ".aud", pos); + + DoImpacts(args); + } + + static readonly float[] falloff = + { + 1f, 0.3678795f, 0.1353353f, 0.04978707f, + 0.01831564f, 0.006737947f, 0.002478752f, 0.000911882f + }; + + static float GetDamageFalloff(float x) + { + var u = (int)x; + if (u >= falloff.Length - 1) return 0; + var t = x - u; + return (falloff[u] * (1 - t)) + (falloff[u + 1] * t); + } + + static float GetDamageToInflict(Actor target, ProjectileArgs args, WarheadInfo warhead, float modifier) + { + // don't hit air units with splash from ground explosions, etc + if (!WeaponValidForTarget(args.weapon, target)) return 0f; + + var health = target.Info.Traits.GetOrDefault(); + if( health == null ) return 0f; + + var distance = (int)Math.Max(0, (target.CenterLocation - args.dest).Length - health.Radius); + var falloff = (float)GetDamageFalloff(distance / warhead.Spread); + var rawDamage = (float)(warhead.Damage * modifier * falloff); + var multiplier = (float)warhead.EffectivenessAgainst(target); + + return (float)(rawDamage * multiplier); + } + + public static bool WeaponValidForTarget(WeaponInfo weapon, Actor target) + { + var targetable = target.TraitOrDefault(); + if (targetable == null || !weapon.ValidTargets.Intersect(targetable.TargetTypes).Any()) + return false; + + if (weapon.Warheads.All( w => w.EffectivenessAgainst(target) <= 0)) + return false; + + return true; + } + + public static bool WeaponValidForTarget( WeaponInfo weapon, World world, int2 location ) + { + if( weapon.ValidTargets.Contains( "Ground" ) && world.GetTerrainType( location ) != "Water" ) return true; + if( weapon.ValidTargets.Contains( "Water" ) && world.GetTerrainType( location ) == "Water" ) return true; + return false; + } + + static float2 GetRecoil(Actor self, float recoil) + { + var abInfo = self.Info.Traits.GetOrDefault(); + if (abInfo == null || abInfo.Recoil == 0) return float2.Zero; + + var rut = self.TraitOrDefault(); + if (rut == null) return float2.Zero; + + var facing = self.Trait().turretFacing; + var localRecoil = new float2(0, recoil * abInfo.Recoil); // vector in turret-space. + + return Util.RotateVectorByFacing(localRecoil, facing, .7f); + } + public static float2 GetTurretPosition(Actor self, IFacing facing, Turret turret) + { + if(facing == null) return turret.ScreenSpacePosition; /* things that don't have a rotating base don't need the turrets repositioned */ + + var ru = self.TraitOrDefault(); + var numDirs = (ru != null) ? ru.anim.CurrentSequence.Facings : 8; + var bodyFacing = facing.Facing; + var quantizedFacing = Util.QuantizeFacing(bodyFacing, numDirs) * (256 / numDirs); + + return (Util.RotateVectorByFacing(turret.UnitSpacePosition, quantizedFacing, .7f) + + GetRecoil(self, turret.Recoil)) + + turret.ScreenSpacePosition; + } + + // gets the screen-space position of a barrel. + public static float2 GetBarrelPosition(Actor self, IFacing facing, Turret turret, Barrel barrel) + { + var turreted = self.TraitOrDefault(); + + if (turreted == null && facing == null) + return float2.Zero; + + var turretFacing = turreted != null ? turreted.turretFacing : facing.Facing; + + return Util.RotateVectorByFacing(barrel.Position, turretFacing, .7f); + } + + public static bool IsInRange( float2 attackOrigin, float range, Actor target ) + { + var rsq = range * range * Game.CellSize * Game.CellSize; + foreach( var cell in target.Trait().TargetableCells( target ) ) + if( ( attackOrigin - cell * Game.CellSize ).LengthSquared <= rsq ) + return true; + return false; + } + + public static bool IsInRange( float2 attackOrigin, float range, float2 targetLocation ) + { + var rsq = range * range * Game.CellSize * Game.CellSize; + return ( attackOrigin - targetLocation ).LengthSquared <= rsq; + } + + public static bool IsInRange( float2 attackOrigin, float range, Target target ) + { + if( !target.IsValid ) return false; + if( target.IsActor ) + return IsInRange( attackOrigin, range, target.Actor ); + else + return IsInRange( attackOrigin, range, target.CenterLocation ); + } + } +} diff --git a/OpenRA.Mods.RA/ConquestVictoryConditions.cs b/OpenRA.Mods.RA/ConquestVictoryConditions.cs index d9c0f13654..a2d5e46cc7 100644 --- a/OpenRA.Mods.RA/ConquestVictoryConditions.cs +++ b/OpenRA.Mods.RA/ConquestVictoryConditions.cs @@ -1,71 +1,71 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class ConquestVictoryConditionsInfo : TraitInfo { } - - public class ConquestVictoryConditions : ITick, IResolveOrder - { - public void Tick(Actor self) - { - if (self.Owner.WinState != WinState.Undefined || self.Owner.NonCombatant) return; - - var hasAnything = self.World.Queries.OwnedBy[self.Owner] - .WithTrait().Any(); - - if (!hasAnything && !self.Owner.NonCombatant) - Surrender(self); - - var others = self.World.players.Where( p => !p.Value.NonCombatant && p.Value != self.Owner && p.Value.Stances[self.Owner] != Stance.Ally ); - if (others.Count() == 0) return; - - if(others.All(p => p.Value.WinState == WinState.Lost)) - Win(self); - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "Surrender") - Surrender(self); - } - - public void Surrender(Actor self) - { - if (self.Owner.WinState == WinState.Lost) return; - self.Owner.WinState = WinState.Lost; - - Game.Debug("{0} is defeated.".F(self.Owner.PlayerName)); - foreach (var a in self.World.Queries.OwnedBy[self.Owner]) - a.Kill(a); - - if (self.Owner == self.World.LocalPlayer) - self.World.LocalShroud.Disabled = true; - } - - public void Win(Actor self) - { - if (self.Owner.WinState == WinState.Won) return; - self.Owner.WinState = WinState.Won; - - Game.Debug("{0} is victorious.".F(self.Owner.PlayerName)); - if (self.Owner == self.World.LocalPlayer) - self.World.LocalShroud.Disabled = true; - } - } - - /* tag trait for things that must be destroyed for a short game to end */ - - class MustBeDestroyedInfo : TraitInfo { } - class MustBeDestroyed { } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class ConquestVictoryConditionsInfo : TraitInfo { } + + public class ConquestVictoryConditions : ITick, IResolveOrder + { + public void Tick(Actor self) + { + if (self.Owner.WinState != WinState.Undefined || self.Owner.NonCombatant) return; + + var hasAnything = self.World.Queries.OwnedBy[self.Owner] + .WithTrait().Any(); + + if (!hasAnything && !self.Owner.NonCombatant) + Surrender(self); + + var others = self.World.players.Where( p => !p.Value.NonCombatant && p.Value != self.Owner && p.Value.Stances[self.Owner] != Stance.Ally ); + if (others.Count() == 0) return; + + if(others.All(p => p.Value.WinState == WinState.Lost)) + Win(self); + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Surrender") + Surrender(self); + } + + public void Surrender(Actor self) + { + if (self.Owner.WinState == WinState.Lost) return; + self.Owner.WinState = WinState.Lost; + + Game.Debug("{0} is defeated.".F(self.Owner.PlayerName)); + foreach (var a in self.World.Queries.OwnedBy[self.Owner]) + a.Kill(a); + + if (self.Owner == self.World.LocalPlayer) + self.World.LocalShroud.Disabled = true; + } + + public void Win(Actor self) + { + if (self.Owner.WinState == WinState.Won) return; + self.Owner.WinState = WinState.Won; + + Game.Debug("{0} is victorious.".F(self.Owner.PlayerName)); + if (self.Owner == self.World.LocalPlayer) + self.World.LocalShroud.Disabled = true; + } + } + + /* tag trait for things that must be destroyed for a short game to end */ + + class MustBeDestroyedInfo : TraitInfo { } + class MustBeDestroyed { } +} diff --git a/OpenRA.Mods.RA/Crate.cs b/OpenRA.Mods.RA/Crate.cs index 50fdf9b603..799033fbc3 100644 --- a/OpenRA.Mods.RA/Crate.cs +++ b/OpenRA.Mods.RA/Crate.cs @@ -1,121 +1,121 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; - -/* - * Crates left to implement: -HealBase=1,INVUN ; all buildings to full strength -ICBM=1,MISSILE2 ; nuke missile one time shot -Sonar=3,SONARBOX ; one time sonar pulse -Squad=20,NONE ; squad of random infantry -Unit=20,NONE ; vehicle -Invulnerability=3,INVULBOX,1.0 ; invulnerability (duration in minutes) -TimeQuake=3,TQUAKE ; time quake -*/ - -namespace OpenRA.Mods.RA -{ - class CrateInfo : ITraitInfo, ITraitPrerequisite - { - public readonly int Lifetime = 5; // Seconds - public readonly string[] TerrainTypes = { }; - public object Create(ActorInitializer init) { return new Crate(init, this); } - } - - // ITeleportable is required for paradrop - class Crate : ITick, IOccupySpace, ITeleportable, ICrushable, ISync - { - readonly Actor self; - [Sync] - int ticks; - - [Sync] - public int2 Location; - - CrateInfo Info; - public Crate(ActorInitializer init, CrateInfo info) - { - this.self = init.self; - if (init.Contains()) - { - this.Location = init.Get(); - PxPosition = Util.CenterOfCell(Location); - } - this.Info = info; - } - - public void OnCrush(Actor crusher) - { - var shares = self.TraitsImplementing().Select( - a => Pair.New(a, a.GetSelectionSharesOuter(crusher))); - var totalShares = shares.Sum(a => a.Second); - var n = self.World.SharedRandom.Next(totalShares); - - self.Destroy(); - foreach (var s in shares) - if (n < s.Second) - { - s.First.Activate(crusher); - return; - } - else - n -= s.Second; - } - - public void Tick(Actor self) - { - if( ++ticks >= self.Info.Traits.Get().Lifetime * 25 ) - self.Destroy(); - } - - public int2 TopLeft { get { return Location; } } - public IEnumerable> OccupiedCells() { yield return Pair.New( Location, SubCell.FullCell); } - - public int2 PxPosition { get; private set; } - - public void SetPxPosition( Actor self, int2 px ) - { - SetPosition( self, Util.CellContaining( px ) ); - } - - public void AdjustPxPosition(Actor self, int2 px) { SetPxPosition(self, px); } - - public bool CanEnterCell(int2 cell) - { - if (!self.World.Map.IsInMap(cell.X, cell.Y)) return false; - var type = self.World.GetTerrainType(cell); - return Info.TerrainTypes.Contains(type); - } - - public void SetPosition(Actor self, int2 cell) - { - var uim = self.World.WorldActor.Trait(); - - if( self.IsInWorld ) - uim.Remove(self, this); - - Location = cell; - PxPosition = Util.CenterOfCell(cell); - - var seq = self.World.GetTerrainInfo(cell).IsWater ? "water" : "idle"; - if (seq != self.Trait().anim.CurrentSequence.Name) - self.Trait().anim.PlayRepeating(seq); - - if( self.IsInWorld ) - uim.Add(self, this); - } - - public IEnumerable CrushClasses { get { yield return "crate"; } } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; + +/* + * Crates left to implement: +HealBase=1,INVUN ; all buildings to full strength +ICBM=1,MISSILE2 ; nuke missile one time shot +Sonar=3,SONARBOX ; one time sonar pulse +Squad=20,NONE ; squad of random infantry +Unit=20,NONE ; vehicle +Invulnerability=3,INVULBOX,1.0 ; invulnerability (duration in minutes) +TimeQuake=3,TQUAKE ; time quake +*/ + +namespace OpenRA.Mods.RA +{ + class CrateInfo : ITraitInfo, ITraitPrerequisite + { + public readonly int Lifetime = 5; // Seconds + public readonly string[] TerrainTypes = { }; + public object Create(ActorInitializer init) { return new Crate(init, this); } + } + + // ITeleportable is required for paradrop + class Crate : ITick, IOccupySpace, ITeleportable, ICrushable, ISync + { + readonly Actor self; + [Sync] + int ticks; + + [Sync] + public int2 Location; + + CrateInfo Info; + public Crate(ActorInitializer init, CrateInfo info) + { + this.self = init.self; + if (init.Contains()) + { + this.Location = init.Get(); + PxPosition = Util.CenterOfCell(Location); + } + this.Info = info; + } + + public void OnCrush(Actor crusher) + { + var shares = self.TraitsImplementing().Select( + a => Pair.New(a, a.GetSelectionSharesOuter(crusher))); + var totalShares = shares.Sum(a => a.Second); + var n = self.World.SharedRandom.Next(totalShares); + + self.Destroy(); + foreach (var s in shares) + if (n < s.Second) + { + s.First.Activate(crusher); + return; + } + else + n -= s.Second; + } + + public void Tick(Actor self) + { + if( ++ticks >= self.Info.Traits.Get().Lifetime * 25 ) + self.Destroy(); + } + + public int2 TopLeft { get { return Location; } } + public IEnumerable> OccupiedCells() { yield return Pair.New( Location, SubCell.FullCell); } + + public int2 PxPosition { get; private set; } + + public void SetPxPosition( Actor self, int2 px ) + { + SetPosition( self, Util.CellContaining( px ) ); + } + + public void AdjustPxPosition(Actor self, int2 px) { SetPxPosition(self, px); } + + public bool CanEnterCell(int2 cell) + { + if (!self.World.Map.IsInMap(cell.X, cell.Y)) return false; + var type = self.World.GetTerrainType(cell); + return Info.TerrainTypes.Contains(type); + } + + public void SetPosition(Actor self, int2 cell) + { + var uim = self.World.WorldActor.Trait(); + + if( self.IsInWorld ) + uim.Remove(self, this); + + Location = cell; + PxPosition = Util.CenterOfCell(cell); + + var seq = self.World.GetTerrainInfo(cell).IsWater ? "water" : "idle"; + if (seq != self.Trait().anim.CurrentSequence.Name) + self.Trait().anim.PlayRepeating(seq); + + if( self.IsInWorld ) + uim.Add(self, this); + } + + public IEnumerable CrushClasses { get { yield return "crate"; } } + } +} diff --git a/OpenRA.Mods.RA/CrateAction.cs b/OpenRA.Mods.RA/CrateAction.cs index 3afb3ecdb6..1d25298997 100644 --- a/OpenRA.Mods.RA/CrateAction.cs +++ b/OpenRA.Mods.RA/CrateAction.cs @@ -1,60 +1,60 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Mods.RA.Effects; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class CrateActionInfo : ITraitInfo - { - public int SelectionShares = 10; - public string Effect = null; - public string Notification = null; - public string[] ExcludedActorTypes = { }; - - public virtual object Create(ActorInitializer init) { return new CrateAction(init.self, this); } - } - - public class CrateAction - { - public Actor self; - public CrateActionInfo info; - - public CrateAction(Actor self, CrateActionInfo info) - { - this.self = self; - this.info = info; - } - - public int GetSelectionSharesOuter(Actor collector) - { - if (info.ExcludedActorTypes.Contains(collector.Info.Name)) - return 0; - - return GetSelectionShares(collector); - } - - public virtual int GetSelectionShares(Actor collector) - { - return info.SelectionShares; - } - - public virtual void Activate(Actor collector) - { - Sound.PlayToPlayer(collector.Owner, info.Notification); - - if (info.Effect != null) - collector.World.AddFrameEndTask( - w => w.Add(new CrateEffect(collector, info.Effect))); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.RA.Effects; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class CrateActionInfo : ITraitInfo + { + public int SelectionShares = 10; + public string Effect = null; + public string Notification = null; + public string[] ExcludedActorTypes = { }; + + public virtual object Create(ActorInitializer init) { return new CrateAction(init.self, this); } + } + + public class CrateAction + { + public Actor self; + public CrateActionInfo info; + + public CrateAction(Actor self, CrateActionInfo info) + { + this.self = self; + this.info = info; + } + + public int GetSelectionSharesOuter(Actor collector) + { + if (info.ExcludedActorTypes.Contains(collector.Info.Name)) + return 0; + + return GetSelectionShares(collector); + } + + public virtual int GetSelectionShares(Actor collector) + { + return info.SelectionShares; + } + + public virtual void Activate(Actor collector) + { + Sound.PlayToPlayer(collector.Owner, info.Notification); + + if (info.Effect != null) + collector.World.AddFrameEndTask( + w => w.Add(new CrateEffect(collector, info.Effect))); + } + } +} diff --git a/OpenRA.Mods.RA/CrateDrop.cs b/OpenRA.Mods.RA/CrateDrop.cs index 4a4636b942..eb4a4e2c0b 100644 --- a/OpenRA.Mods.RA/CrateDrop.cs +++ b/OpenRA.Mods.RA/CrateDrop.cs @@ -1,92 +1,92 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Mods.RA.Air; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class CrateDropInfo : TraitInfo - { - public readonly int Minimum = 1; // Minumum number of crates - public readonly int Maximum = 255; // Maximum number of crates - public readonly string[] ValidGround = {"Clear", "Rough", "Road", "Ore", "Beach"}; // Which terrain types can we drop on? - public readonly string[] ValidWater = {"Water"}; - public readonly int SpawnInterval = 180; // Average time (seconds) between crate spawn - public readonly float WaterChance = .2f; // Chance of generating a water crate instead of a land crate - } - - public class CrateDrop : ITick - { - List crates = new List(); - int ticks = 0; - - public void Tick(Actor self) - { - if (--ticks <= 0) - { - var info = self.Info.Traits.Get(); - ticks = info.SpawnInterval * 25; // todo: randomize - - crates.RemoveAll(x => !x.IsInWorld); // BUG: this removes crates that are cargo of a BADR! - - var toSpawn = Math.Max(0, info.Minimum - crates.Count) - + (crates.Count < info.Maximum ? 1 : 0); - - for (var n = 0; n < toSpawn; n++) - SpawnCrate(self, info); - } - } - - void SpawnCrate(Actor self, CrateDropInfo info) - { - var threshold = 100; - var inWater = self.World.SharedRandom.NextDouble() < info.WaterChance; - - for (var n = 0; n < threshold; n++ ) - { - var p = self.World.ChooseRandomCell(self.World.SharedRandom); - - // Is this valid terrain? - var terrainType = self.World.GetTerrainType(p); - if (!(inWater ? info.ValidWater : info.ValidGround).Contains(terrainType)) continue; - - // Don't drop on any actors - if (self.World.WorldActor.Trait().GetBuildingAt(p) != null) continue; - if (self.World.WorldActor.Trait().GetUnitsAt(p).Any()) continue; - - self.World.AddFrameEndTask(w => - { - var crate = w.CreateActor(false, "crate", new TypeDictionary { new OwnerInit(w.WorldActor.Owner) }); - crates.Add(crate); - - var startPos = w.ChooseRandomEdgeCell(); - var plane = w.CreateActor("badr", new TypeDictionary - { - new LocationInit( startPos ), - new OwnerInit( w.WorldActor.Owner), - new FacingInit( Util.GetFacing(p - startPos, 0) ), - new AltitudeInit( Rules.Info["badr"].Traits.Get().CruiseAltitude ), - }); - plane.CancelActivity(); - plane.QueueActivity(new FlyCircle(p)); - plane.Trait().SetLZ(p, null); - plane.Trait().Load(plane, crate); - }); - return; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Air; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class CrateDropInfo : TraitInfo + { + public readonly int Minimum = 1; // Minumum number of crates + public readonly int Maximum = 255; // Maximum number of crates + public readonly string[] ValidGround = {"Clear", "Rough", "Road", "Ore", "Beach"}; // Which terrain types can we drop on? + public readonly string[] ValidWater = {"Water"}; + public readonly int SpawnInterval = 180; // Average time (seconds) between crate spawn + public readonly float WaterChance = .2f; // Chance of generating a water crate instead of a land crate + } + + public class CrateDrop : ITick + { + List crates = new List(); + int ticks = 0; + + public void Tick(Actor self) + { + if (--ticks <= 0) + { + var info = self.Info.Traits.Get(); + ticks = info.SpawnInterval * 25; // todo: randomize + + crates.RemoveAll(x => !x.IsInWorld); // BUG: this removes crates that are cargo of a BADR! + + var toSpawn = Math.Max(0, info.Minimum - crates.Count) + + (crates.Count < info.Maximum ? 1 : 0); + + for (var n = 0; n < toSpawn; n++) + SpawnCrate(self, info); + } + } + + void SpawnCrate(Actor self, CrateDropInfo info) + { + var threshold = 100; + var inWater = self.World.SharedRandom.NextDouble() < info.WaterChance; + + for (var n = 0; n < threshold; n++ ) + { + var p = self.World.ChooseRandomCell(self.World.SharedRandom); + + // Is this valid terrain? + var terrainType = self.World.GetTerrainType(p); + if (!(inWater ? info.ValidWater : info.ValidGround).Contains(terrainType)) continue; + + // Don't drop on any actors + if (self.World.WorldActor.Trait().GetBuildingAt(p) != null) continue; + if (self.World.WorldActor.Trait().GetUnitsAt(p).Any()) continue; + + self.World.AddFrameEndTask(w => + { + var crate = w.CreateActor(false, "crate", new TypeDictionary { new OwnerInit(w.WorldActor.Owner) }); + crates.Add(crate); + + var startPos = w.ChooseRandomEdgeCell(); + var plane = w.CreateActor("badr", new TypeDictionary + { + new LocationInit( startPos ), + new OwnerInit( w.WorldActor.Owner), + new FacingInit( Util.GetFacing(p - startPos, 0) ), + new AltitudeInit( Rules.Info["badr"].Traits.Get().CruiseAltitude ), + }); + plane.CancelActivity(); + plane.QueueActivity(new FlyCircle(p)); + plane.Trait().SetLZ(p, null); + plane.Trait().Load(plane, crate); + }); + return; + } + } + } +} diff --git a/OpenRA.Mods.RA/CrateSpawner.cs b/OpenRA.Mods.RA/CrateSpawner.cs index e2e1ed02f4..8c8df81a8f 100644 --- a/OpenRA.Mods.RA/CrateSpawner.cs +++ b/OpenRA.Mods.RA/CrateSpawner.cs @@ -1,18 +1,18 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Mods.RA.Buildings; +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Buildings; using OpenRA.Traits; namespace OpenRA.Mods.RA diff --git a/OpenRA.Mods.RA/Crates/CloakCrateAction.cs b/OpenRA.Mods.RA/Crates/CloakCrateAction.cs index 550d8e34b8..62a338f2d7 100644 --- a/OpenRA.Mods.RA/Crates/CloakCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/CloakCrateAction.cs @@ -1,59 +1,59 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.FileFormats; -using OpenRA.Mods.RA; - -namespace OpenRA.Mods.RA.Crates -{ - class CloakCrateActionInfo : CrateActionInfo - { - public readonly float InitialDelay = .4f; - public readonly float CloakDelay = 1.2f; - public readonly string CloakSound = "subshow1.aud"; - public readonly string UncloakSound = "subshow1.aud"; - - public override object Create(ActorInitializer init) { return new CloakCrateAction(init.self, this); } - } - - class CloakCrateAction : CrateAction - { - CloakCrateActionInfo Info; - public CloakCrateAction(Actor self, CloakCrateActionInfo info) - : base(self, info) { Info = info; } - - public override int GetSelectionShares(Actor collector) - { - return collector.HasTrait() - ? 0 : base.GetSelectionShares(collector); - } - - public override void Activate(Actor collector) - { - var cloakInfo = new CloakInfo(Info.InitialDelay, Info.CloakDelay, - Info.CloakSound, Info.UncloakSound); - - var cloak = cloakInfo.Create(new ActorInitializer(collector, new TypeDictionary() )); - - collector.World.AddFrameEndTask(w => - { - w.Remove(collector); - - collector.AddTrait(cloak); - if (collector.HasTrait>()) - collector.Trait>().RecievedCloak(collector); - - w.Add(collector); - }); - - base.Activate(collector); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.FileFormats; +using OpenRA.Mods.RA; + +namespace OpenRA.Mods.RA.Crates +{ + class CloakCrateActionInfo : CrateActionInfo + { + public readonly float InitialDelay = .4f; + public readonly float CloakDelay = 1.2f; + public readonly string CloakSound = "subshow1.aud"; + public readonly string UncloakSound = "subshow1.aud"; + + public override object Create(ActorInitializer init) { return new CloakCrateAction(init.self, this); } + } + + class CloakCrateAction : CrateAction + { + CloakCrateActionInfo Info; + public CloakCrateAction(Actor self, CloakCrateActionInfo info) + : base(self, info) { Info = info; } + + public override int GetSelectionShares(Actor collector) + { + return collector.HasTrait() + ? 0 : base.GetSelectionShares(collector); + } + + public override void Activate(Actor collector) + { + var cloakInfo = new CloakInfo(Info.InitialDelay, Info.CloakDelay, + Info.CloakSound, Info.UncloakSound); + + var cloak = cloakInfo.Create(new ActorInitializer(collector, new TypeDictionary() )); + + collector.World.AddFrameEndTask(w => + { + w.Remove(collector); + + collector.AddTrait(cloak); + if (collector.HasTrait>()) + collector.Trait>().RecievedCloak(collector); + + w.Add(collector); + }); + + base.Activate(collector); + } + } +} diff --git a/OpenRA.Mods.RA/Crates/ExplodeCrateAction.cs b/OpenRA.Mods.RA/Crates/ExplodeCrateAction.cs index 95f389368c..325a5003c1 100644 --- a/OpenRA.Mods.RA/Crates/ExplodeCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/ExplodeCrateAction.cs @@ -1,34 +1,34 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class ExplodeCrateActionInfo : CrateActionInfo - { - [WeaponReference] - public string Weapon = null; - - public override object Create(ActorInitializer init) { return new ExplodeCrateAction(init.self, this); } - } - - class ExplodeCrateAction : CrateAction - { - public ExplodeCrateAction(Actor self, ExplodeCrateActionInfo info) - : base(self, info) {} - - public override void Activate(Actor collector) - { - Combat.DoExplosion(self, (info as ExplodeCrateActionInfo).Weapon, collector.CenterLocation, 0); - base.Activate(collector); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class ExplodeCrateActionInfo : CrateActionInfo + { + [WeaponReference] + public string Weapon = null; + + public override object Create(ActorInitializer init) { return new ExplodeCrateAction(init.self, this); } + } + + class ExplodeCrateAction : CrateAction + { + public ExplodeCrateAction(Actor self, ExplodeCrateActionInfo info) + : base(self, info) {} + + public override void Activate(Actor collector) + { + Combat.DoExplosion(self, (info as ExplodeCrateActionInfo).Weapon, collector.CenterLocation, 0); + base.Activate(collector); + } + } +} diff --git a/OpenRA.Mods.RA/Crates/GiveCashCrateAction.cs b/OpenRA.Mods.RA/Crates/GiveCashCrateAction.cs index 0a0216766b..2ada1c12b4 100644 --- a/OpenRA.Mods.RA/Crates/GiveCashCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/GiveCashCrateAction.cs @@ -1,36 +1,36 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class GiveCashCrateActionInfo : CrateActionInfo - { - public int Amount = 2000; - public override object Create(ActorInitializer init) { return new GiveCashCrateAction(init.self, this); } - } - - class GiveCashCrateAction : CrateAction - { - public GiveCashCrateAction(Actor self, GiveCashCrateActionInfo info) - : base(self, info) {} - - public override void Activate(Actor collector) - { - collector.World.AddFrameEndTask(w => - { - var amount = (info as GiveCashCrateActionInfo).Amount; - collector.Owner.PlayerActor.Trait().GiveCash(amount); - }); - base.Activate(collector); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class GiveCashCrateActionInfo : CrateActionInfo + { + public int Amount = 2000; + public override object Create(ActorInitializer init) { return new GiveCashCrateAction(init.self, this); } + } + + class GiveCashCrateAction : CrateAction + { + public GiveCashCrateAction(Actor self, GiveCashCrateActionInfo info) + : base(self, info) {} + + public override void Activate(Actor collector) + { + collector.World.AddFrameEndTask(w => + { + var amount = (info as GiveCashCrateActionInfo).Amount; + collector.Owner.PlayerActor.Trait().GiveCash(amount); + }); + base.Activate(collector); + } + } +} diff --git a/OpenRA.Mods.RA/Crates/GiveMcvCrateAction.cs b/OpenRA.Mods.RA/Crates/GiveMcvCrateAction.cs index bdfc8cfd70..a12f08db9e 100644 --- a/OpenRA.Mods.RA/Crates/GiveMcvCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/GiveMcvCrateAction.cs @@ -1,36 +1,36 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Crates -{ - class GiveMcvCrateActionInfo : GiveUnitCrateActionInfo - { - public int NoBaseSelectionShares = 1000; - public override object Create(ActorInitializer init) { return new GiveMcvCrateAction(init.self, this); } - } - - class GiveMcvCrateAction : GiveUnitCrateAction - { - public GiveMcvCrateAction(Actor self, GiveMcvCrateActionInfo info) - : base(self, info) { } - - public override int GetSelectionShares(Actor collector) - { - if (base.GetSelectionShares(collector) == 0) - return 0; // there's some other really good reason why we shouldn't give this. - - var hasBase = self.World.Queries.OwnedBy[collector.Owner].WithTrait().Any(); - return hasBase ? info.SelectionShares : (info as GiveMcvCrateActionInfo).NoBaseSelectionShares; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Crates +{ + class GiveMcvCrateActionInfo : GiveUnitCrateActionInfo + { + public int NoBaseSelectionShares = 1000; + public override object Create(ActorInitializer init) { return new GiveMcvCrateAction(init.self, this); } + } + + class GiveMcvCrateAction : GiveUnitCrateAction + { + public GiveMcvCrateAction(Actor self, GiveMcvCrateActionInfo info) + : base(self, info) { } + + public override int GetSelectionShares(Actor collector) + { + if (base.GetSelectionShares(collector) == 0) + return 0; // there's some other really good reason why we shouldn't give this. + + var hasBase = self.World.Queries.OwnedBy[collector.Owner].WithTrait().Any(); + return hasBase ? info.SelectionShares : (info as GiveMcvCrateActionInfo).NoBaseSelectionShares; + } + } +} diff --git a/OpenRA.Mods.RA/Crates/GiveUnitCrateAction.cs b/OpenRA.Mods.RA/Crates/GiveUnitCrateAction.cs index 50739dc723..df63f35753 100644 --- a/OpenRA.Mods.RA/Crates/GiveUnitCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/GiveUnitCrateAction.cs @@ -1,79 +1,79 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Crates -{ - class GiveUnitCrateActionInfo : CrateActionInfo - { - [ActorReference] - public readonly string Unit = null; - - public override object Create(ActorInitializer init) { return new GiveUnitCrateAction(init.self, this); } - } - - class GiveUnitCrateAction : CrateAction - { - GiveUnitCrateActionInfo Info; - public GiveUnitCrateAction(Actor self, GiveUnitCrateActionInfo info) - : base(self, info) { Info = info; } - - public override int GetSelectionShares(Actor collector) - { - var bi = Rules.Info[Info.Unit].Traits.Get(); - - // this unit is not buildable by the collector's country, so - // don't give them free ones either. - if (!bi.Owner.Contains(collector.Owner.Country.Race)) return 0; - - // avoid dumping tanks in the sea, and ships on dry land. - if (!GetSuitableCells(collector.Location).Any()) return 0; - - return base.GetSelectionShares(collector); - } - - public override void Activate(Actor collector) - { - var location = ChooseEmptyCellNear(collector); - if (location != null) - collector.World.AddFrameEndTask( - w => w.CreateActor(Info.Unit, new TypeDictionary - { - new LocationInit( location.Value ), - new OwnerInit( collector.Owner ) - })); - - base.Activate(collector); - } - - IEnumerable GetSuitableCells(int2 near) - { - var mi = Rules.Info[Info.Unit].Traits.GetOrDefault(); - for (var i = -1; i < 2; i++) - for (var j = -1; j < 2; j++) - if (mi.CanEnterCell(self.World, near + new int2(i, j), null, true)) - yield return near + new int2(i, j); - } - - int2? ChooseEmptyCellNear(Actor a) - { - var possibleCells = GetSuitableCells(a.Location).ToArray(); - if (possibleCells.Length == 0) - return null; - - return possibleCells.Random(self.World.SharedRandom); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Crates +{ + class GiveUnitCrateActionInfo : CrateActionInfo + { + [ActorReference] + public readonly string Unit = null; + + public override object Create(ActorInitializer init) { return new GiveUnitCrateAction(init.self, this); } + } + + class GiveUnitCrateAction : CrateAction + { + GiveUnitCrateActionInfo Info; + public GiveUnitCrateAction(Actor self, GiveUnitCrateActionInfo info) + : base(self, info) { Info = info; } + + public override int GetSelectionShares(Actor collector) + { + var bi = Rules.Info[Info.Unit].Traits.Get(); + + // this unit is not buildable by the collector's country, so + // don't give them free ones either. + if (!bi.Owner.Contains(collector.Owner.Country.Race)) return 0; + + // avoid dumping tanks in the sea, and ships on dry land. + if (!GetSuitableCells(collector.Location).Any()) return 0; + + return base.GetSelectionShares(collector); + } + + public override void Activate(Actor collector) + { + var location = ChooseEmptyCellNear(collector); + if (location != null) + collector.World.AddFrameEndTask( + w => w.CreateActor(Info.Unit, new TypeDictionary + { + new LocationInit( location.Value ), + new OwnerInit( collector.Owner ) + })); + + base.Activate(collector); + } + + IEnumerable GetSuitableCells(int2 near) + { + var mi = Rules.Info[Info.Unit].Traits.GetOrDefault(); + for (var i = -1; i < 2; i++) + for (var j = -1; j < 2; j++) + if (mi.CanEnterCell(self.World, near + new int2(i, j), null, true)) + yield return near + new int2(i, j); + } + + int2? ChooseEmptyCellNear(Actor a) + { + var possibleCells = GetSuitableCells(a.Location).ToArray(); + if (possibleCells.Length == 0) + return null; + + return possibleCells.Random(self.World.SharedRandom); + } + } +} diff --git a/OpenRA.Mods.RA/Crates/LevelUpCrateAction.cs b/OpenRA.Mods.RA/Crates/LevelUpCrateAction.cs index 5322062366..55c781502b 100644 --- a/OpenRA.Mods.RA/Crates/LevelUpCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/LevelUpCrateAction.cs @@ -1,35 +1,35 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.Mods.RA -{ - class LevelUpCrateActionInfo : CrateActionInfo - { - public override object Create(ActorInitializer init) { return new LevelUpCrateAction(init.self, this); } - } - - class LevelUpCrateAction : CrateAction - { - public LevelUpCrateAction(Actor self, LevelUpCrateActionInfo info) - : base(self,info) {} - - public override void Activate(Actor collector) - { - collector.World.AddFrameEndTask(w => - { - var gainsExperience = collector.TraitOrDefault(); - if (gainsExperience != null) - gainsExperience.GiveOneLevel(); - }); - - base.Activate(collector); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.Mods.RA +{ + class LevelUpCrateActionInfo : CrateActionInfo + { + public override object Create(ActorInitializer init) { return new LevelUpCrateAction(init.self, this); } + } + + class LevelUpCrateAction : CrateAction + { + public LevelUpCrateAction(Actor self, LevelUpCrateActionInfo info) + : base(self,info) {} + + public override void Activate(Actor collector) + { + collector.World.AddFrameEndTask(w => + { + var gainsExperience = collector.TraitOrDefault(); + if (gainsExperience != null) + gainsExperience.GiveOneLevel(); + }); + + base.Activate(collector); + } + } +} diff --git a/OpenRA.Mods.RA/Crates/ResetRadarCrateAction.cs b/OpenRA.Mods.RA/Crates/ResetRadarCrateAction.cs index edc3785fb4..604dbdfe32 100644 --- a/OpenRA.Mods.RA/Crates/ResetRadarCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/ResetRadarCrateAction.cs @@ -1,32 +1,32 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class HideMapCrateActionInfo : CrateActionInfo - { - public override object Create(ActorInitializer init) { return new HideMapCrateAction(init.self, this); } - } - - class HideMapCrateAction : CrateAction - { - public HideMapCrateAction(Actor self, HideMapCrateActionInfo info) - : base(self, info) {} - - public override void Activate(Actor collector) - { - base.Activate(collector); - if (collector.Owner == collector.World.LocalPlayer) - collector.World.WorldActor.Trait().ResetExploration(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class HideMapCrateActionInfo : CrateActionInfo + { + public override object Create(ActorInitializer init) { return new HideMapCrateAction(init.self, this); } + } + + class HideMapCrateAction : CrateAction + { + public HideMapCrateAction(Actor self, HideMapCrateActionInfo info) + : base(self, info) {} + + public override void Activate(Actor collector) + { + base.Activate(collector); + if (collector.Owner == collector.World.LocalPlayer) + collector.World.WorldActor.Trait().ResetExploration(); + } + } +} diff --git a/OpenRA.Mods.RA/Crates/RevealMapCrateAction.cs b/OpenRA.Mods.RA/Crates/RevealMapCrateAction.cs index 0f85985322..772696f2c4 100644 --- a/OpenRA.Mods.RA/Crates/RevealMapCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/RevealMapCrateAction.cs @@ -1,20 +1,20 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - +#endregion + using System.Linq; using OpenRA.Traits; namespace OpenRA.Mods.RA { class RevealMapCrateActionInfo : CrateActionInfo - { + { public readonly bool IncludeAllies = false; public override object Create(ActorInitializer init) { return new RevealMapCrateAction(init.self, this); } } @@ -22,22 +22,22 @@ namespace OpenRA.Mods.RA class RevealMapCrateAction : CrateAction { public RevealMapCrateAction(Actor self, RevealMapCrateActionInfo info) - : base(self, info) {} - - bool ShouldReveal(Player collectingPlayer) - { - if ((info as RevealMapCrateActionInfo).IncludeAllies) - return collectingPlayer.World.LocalPlayer != null && - collectingPlayer.Stances[collectingPlayer.World.LocalPlayer] == Stance.Ally; - - return collectingPlayer == collectingPlayer.World.LocalPlayer; + : base(self, info) {} + + bool ShouldReveal(Player collectingPlayer) + { + if ((info as RevealMapCrateActionInfo).IncludeAllies) + return collectingPlayer.World.LocalPlayer != null && + collectingPlayer.Stances[collectingPlayer.World.LocalPlayer] == Stance.Ally; + + return collectingPlayer == collectingPlayer.World.LocalPlayer; } public override void Activate(Actor collector) { - base.Activate(collector); - - if (ShouldReveal( collector.Owner )) + base.Activate(collector); + + if (ShouldReveal( collector.Owner )) collector.World.WorldActor.Trait().ExploreAll(collector.World); } } diff --git a/OpenRA.Mods.RA/Crates/SupportPowerCrateAction.cs b/OpenRA.Mods.RA/Crates/SupportPowerCrateAction.cs index 42b8476aa3..bdcb8ffd44 100644 --- a/OpenRA.Mods.RA/Crates/SupportPowerCrateAction.cs +++ b/OpenRA.Mods.RA/Crates/SupportPowerCrateAction.cs @@ -1,40 +1,40 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.RA.Crates -{ - class SupportPowerCrateActionInfo : CrateActionInfo - { - [ActorReference] - public readonly string Proxy = null; - public override object Create(ActorInitializer init) { return new SupportPowerCrateAction(init.self, this); } - } - - class SupportPowerCrateAction : CrateAction - { - SupportPowerCrateActionInfo Info; - public SupportPowerCrateAction(Actor self, SupportPowerCrateActionInfo info) - : base(self, info) { Info = info; } - - // The free unit crate requires same race, and the actor to be at least ITeleportable. - // We want neither of these properties for crate power proxies. - public override void Activate(Actor collector) - { - collector.World.AddFrameEndTask(w => w.CreateActor(Info.Proxy, new TypeDictionary - { - new OwnerInit( collector.Owner ) - })); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.RA.Crates +{ + class SupportPowerCrateActionInfo : CrateActionInfo + { + [ActorReference] + public readonly string Proxy = null; + public override object Create(ActorInitializer init) { return new SupportPowerCrateAction(init.self, this); } + } + + class SupportPowerCrateAction : CrateAction + { + SupportPowerCrateActionInfo Info; + public SupportPowerCrateAction(Actor self, SupportPowerCrateActionInfo info) + : base(self, info) { Info = info; } + + // The free unit crate requires same race, and the actor to be at least ITeleportable. + // We want neither of these properties for crate power proxies. + public override void Activate(Actor collector) + { + collector.World.AddFrameEndTask(w => w.CreateActor(Info.Proxy, new TypeDictionary + { + new OwnerInit( collector.Owner ) + })); + } + } +} diff --git a/OpenRA.Mods.RA/CreateMPPlayers.cs b/OpenRA.Mods.RA/CreateMPPlayers.cs index db7a416109..7f885afaba 100644 --- a/OpenRA.Mods.RA/CreateMPPlayers.cs +++ b/OpenRA.Mods.RA/CreateMPPlayers.cs @@ -1,16 +1,16 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Network; +#endregion + +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Network; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -20,53 +20,53 @@ namespace OpenRA.Mods.RA public class CreateMPPlayers : ICreatePlayers { public void CreatePlayers(World w) - { - var playerIndex = 0; - var mapPlayerIndex = -1; // todo: unhack this, but people still rely on it. - - // create the unplayable map players -- neutral, shellmap, scripted, etc. - foreach (var kv in w.Map.Players.Where(p => !p.Value.Playable)) - { - var player = new Player(w, kv.Value, mapPlayerIndex--); - w.AddPlayer(player); - if (kv.Value.OwnsWorld) - w.WorldActor.Owner = player; - } - - // create the players which are bound through slots. - foreach (var slot in w.LobbyInfo.Slots) - { - var client = w.LobbyInfo.Clients.FirstOrDefault(c => c.Slot == slot.Index && slot.MapPlayer != null); - if (client != null) - { - /* spawn a real player in this slot. */ - var player = new Player(w, client, w.Map.Players[slot.MapPlayer], playerIndex++); - w.AddPlayer(player); - if (client.Index == Game.LocalClientId) - w.SetLocalPlayer(player.Index); // bind this one to the local player. - } - else if (slot.Bot != null && slot.MapPlayer != null) - { - /* spawn a bot in this slot, "owned" by the host */ - - /* pick a random color for the bot */ - var hue = (byte)w.SharedRandom.Next(256); - w.Map.Players[slot.MapPlayer].ColorRamp = new ColorRamp(hue, 255, 180, 25); - - /* todo: pick a random name from the pool */ - - var player = new Player(w, w.Map.Players[slot.MapPlayer], playerIndex++); - w.AddPlayer(player); - - /* activate the bot option that's selected! */ - if (Game.IsHost) - player.PlayerActor.TraitsImplementing() - .Single(b => b.Info.Name == slot.Bot) - .Activate(player); - - /* a bit of a hack */ - player.IsBot = true; - } + { + var playerIndex = 0; + var mapPlayerIndex = -1; // todo: unhack this, but people still rely on it. + + // create the unplayable map players -- neutral, shellmap, scripted, etc. + foreach (var kv in w.Map.Players.Where(p => !p.Value.Playable)) + { + var player = new Player(w, kv.Value, mapPlayerIndex--); + w.AddPlayer(player); + if (kv.Value.OwnsWorld) + w.WorldActor.Owner = player; + } + + // create the players which are bound through slots. + foreach (var slot in w.LobbyInfo.Slots) + { + var client = w.LobbyInfo.Clients.FirstOrDefault(c => c.Slot == slot.Index && slot.MapPlayer != null); + if (client != null) + { + /* spawn a real player in this slot. */ + var player = new Player(w, client, w.Map.Players[slot.MapPlayer], playerIndex++); + w.AddPlayer(player); + if (client.Index == Game.LocalClientId) + w.SetLocalPlayer(player.Index); // bind this one to the local player. + } + else if (slot.Bot != null && slot.MapPlayer != null) + { + /* spawn a bot in this slot, "owned" by the host */ + + /* pick a random color for the bot */ + var hue = (byte)w.SharedRandom.Next(256); + w.Map.Players[slot.MapPlayer].ColorRamp = new ColorRamp(hue, 255, 180, 25); + + /* todo: pick a random name from the pool */ + + var player = new Player(w, w.Map.Players[slot.MapPlayer], playerIndex++); + w.AddPlayer(player); + + /* activate the bot option that's selected! */ + if (Game.IsHost) + player.PlayerActor.TraitsImplementing() + .Single(b => b.Info.Name == slot.Bot) + .Activate(player); + + /* a bit of a hack */ + player.IsBot = true; + } } foreach (var p in w.players.Values) @@ -75,39 +75,39 @@ namespace OpenRA.Mods.RA if (!p.Stances.ContainsKey(q)) p.Stances[q] = ChooseInitialStance(p, q); } - } - - static Stance ChooseInitialStance(Player p, Player q) - { - if (p == q) return Stance.Ally; - var pc = GetClientForPlayer(p); - var qc = GetClientForPlayer(q); - - if (p.World.LobbyInfo.Slots.Count > 0) - { - if (p.World.LobbyInfo.Slots[pc.Slot].Spectator) return Stance.Ally; - if (p.World.LobbyInfo.Slots[qc.Slot].Spectator) return Stance.Ally; - } - - if (p.PlayerRef.Allies.Contains(q.InternalName)) - return Stance.Ally; - if (p.PlayerRef.Enemies.Contains(q.InternalName)) - return Stance.Enemy; - - // Hack: All map players are neutral wrt everyone else - if (p.Index < 0 || q.Index < 0) return Stance.Neutral; - - if (p.IsBot ^ q.IsBot) - return Stance.Enemy; // bots and humans hate each other - - - return pc.Team != 0 && pc.Team == qc.Team - ? Stance.Ally : Stance.Enemy; - } - - static Session.Client GetClientForPlayer(Player p) - { - return p.World.LobbyInfo.ClientWithIndex(p.ClientIndex); + } + + static Stance ChooseInitialStance(Player p, Player q) + { + if (p == q) return Stance.Ally; + var pc = GetClientForPlayer(p); + var qc = GetClientForPlayer(q); + + if (p.World.LobbyInfo.Slots.Count > 0) + { + if (p.World.LobbyInfo.Slots[pc.Slot].Spectator) return Stance.Ally; + if (p.World.LobbyInfo.Slots[qc.Slot].Spectator) return Stance.Ally; + } + + if (p.PlayerRef.Allies.Contains(q.InternalName)) + return Stance.Ally; + if (p.PlayerRef.Enemies.Contains(q.InternalName)) + return Stance.Enemy; + + // Hack: All map players are neutral wrt everyone else + if (p.Index < 0 || q.Index < 0) return Stance.Neutral; + + if (p.IsBot ^ q.IsBot) + return Stance.Enemy; // bots and humans hate each other + + + return pc.Team != 0 && pc.Team == qc.Team + ? Stance.Ally : Stance.Enemy; + } + + static Session.Client GetClientForPlayer(Player p) + { + return p.World.LobbyInfo.ClientWithIndex(p.ClientIndex); } } } diff --git a/OpenRA.Mods.RA/DefaultShellmapScript.cs b/OpenRA.Mods.RA/DefaultShellmapScript.cs index 370d404c6b..72e98b807f 100755 --- a/OpenRA.Mods.RA/DefaultShellmapScript.cs +++ b/OpenRA.Mods.RA/DefaultShellmapScript.cs @@ -1,17 +1,17 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.FileFormats; -using OpenRA.Mods.RA.Air; +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Air; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -20,27 +20,27 @@ namespace OpenRA.Mods.RA class DefaultShellmapScript: IWorldLoaded, ITick { - Dictionary Actors; + Dictionary Actors; private static int2 ViewportOrigin; public void WorldLoaded(World w) - { + { var b = w.Map.Bounds; ViewportOrigin = new int2(b.Left + b.Width/2, b.Top + b.Height/2); - Game.MoveViewport(ViewportOrigin); + Game.MoveViewport(ViewportOrigin); Actors = w.WorldActor.Trait().Actors; Sound.SoundVolumeModifier = 0.25f; } - int ticks = 0; + int ticks = 0; float speed = 4f; - public void Tick(Actor self) - { - var loc = new float2( - (float)(System.Math.Sin((ticks + 45) % (360f * speed) * (Math.PI / 180) * 1f / speed) * 15f + ViewportOrigin.X), - (float)(System.Math.Cos((ticks + 45) % (360f * speed) * (Math.PI / 180) * 1f / speed) * 10f + ViewportOrigin.Y)); - + public void Tick(Actor self) + { + var loc = new float2( + (float)(System.Math.Sin((ticks + 45) % (360f * speed) * (Math.PI / 180) * 1f / speed) * 15f + ViewportOrigin.X), + (float)(System.Math.Cos((ticks + 45) % (360f * speed) * (Math.PI / 180) * 1f / speed) * 10f + ViewportOrigin.Y)); + Game.MoveViewport(loc); if (ticks == 250) @@ -49,21 +49,21 @@ namespace OpenRA.Mods.RA { Pair.New(Actors["ca1"], new int2(90, 70)), Pair.New(Actors["ca2"], new int2(92, 71)) - }, Actors["pdox"], -1, false); + }, Actors["pdox"], -1, false); } - - if (ticks == 100) - Actors["mslo1"].Trait().Activate(Actors["mslo1"], new Order(){ TargetLocation = new int2(98, 52) }); - if (ticks == 140) + + if (ticks == 100) + Actors["mslo1"].Trait().Activate(Actors["mslo1"], new Order(){ TargetLocation = new int2(98, 52) }); + if (ticks == 140) Actors["mslo2"].Trait().Activate(Actors["mslo2"], new Order(){ TargetLocation = new int2(95, 54) }); - if (ticks == 180) + if (ticks == 180) Actors["mslo3"].Trait().Activate(Actors["mslo3"], new Order(){ TargetLocation = new int2(95, 49) }); - if (ticks == 430) - { - Actors["mig1"].Trait().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true); - Actors["mig2"].Trait().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true); + if (ticks == 430) + { + Actors["mig1"].Trait().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true); + Actors["mig2"].Trait().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true); Actors["mig3"].Trait().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true); } diff --git a/OpenRA.Mods.RA/DemoTruck.cs b/OpenRA.Mods.RA/DemoTruck.cs index e2f8a59055..000c934124 100644 --- a/OpenRA.Mods.RA/DemoTruck.cs +++ b/OpenRA.Mods.RA/DemoTruck.cs @@ -1,52 +1,52 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class DemoTruckInfo : TraitInfo { } - - class DemoTruck : Chronoshiftable, INotifyDamage - { - // Explode on chronoshift - public override bool Teleport(Actor self, int2 targetLocation, int duration, bool killCargo, Actor chronosphere) - { - Detonate(self, chronosphere); - return false; - } - - // Fire primary on death - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageState == DamageState.Dead) - Detonate(self, e.Attacker); - } - - public void Detonate(Actor self, Actor detonatedBy) - { - var move = self.TraitOrDefault(); - var info = self.Info.Traits.Get(); - var altitude = move != null ? move.Altitude : 0; - - self.World.AddFrameEndTask( w => - { - if (self.Destroyed) return; - Combat.DoExplosion(self, info.PrimaryWeapon, self.CenterLocation, altitude); - - // Remove from world - self.Kill(self); - detonatedBy.Owner.Kills++; - self.Owner.Deaths++; - self.Destroy(); - } ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class DemoTruckInfo : TraitInfo { } + + class DemoTruck : Chronoshiftable, INotifyDamage + { + // Explode on chronoshift + public override bool Teleport(Actor self, int2 targetLocation, int duration, bool killCargo, Actor chronosphere) + { + Detonate(self, chronosphere); + return false; + } + + // Fire primary on death + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageState == DamageState.Dead) + Detonate(self, e.Attacker); + } + + public void Detonate(Actor self, Actor detonatedBy) + { + var move = self.TraitOrDefault(); + var info = self.Info.Traits.Get(); + var altitude = move != null ? move.Altitude : 0; + + self.World.AddFrameEndTask( w => + { + if (self.Destroyed) return; + Combat.DoExplosion(self, info.PrimaryWeapon, self.CenterLocation, altitude); + + // Remove from world + self.Kill(self); + detonatedBy.Owner.Kills++; + self.Owner.Deaths++; + self.Destroy(); + } ); + } + } +} diff --git a/OpenRA.Mods.RA/DetectCloaked.cs b/OpenRA.Mods.RA/DetectCloaked.cs index 75abb6ab5b..9933f40000 100644 --- a/OpenRA.Mods.RA/DetectCloaked.cs +++ b/OpenRA.Mods.RA/DetectCloaked.cs @@ -1,21 +1,21 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class DetectCloakedInfo : TraitInfo - { - public readonly int Range = 5; - } - - class DetectCloaked {} -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class DetectCloakedInfo : TraitInfo + { + public readonly int Range = 5; + } + + class DetectCloaked {} +} diff --git a/OpenRA.Mods.RA/Effects/Bullet.cs b/OpenRA.Mods.RA/Effects/Bullet.cs index c3d6dc91ae..f16215494a 100755 --- a/OpenRA.Mods.RA/Effects/Bullet.cs +++ b/OpenRA.Mods.RA/Effects/Bullet.cs @@ -1,155 +1,155 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Effects; -using OpenRA.GameRules; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - public class BulletInfo : IProjectileInfo - { - public readonly int Speed = 1; - public readonly string Trail = null; - public readonly float Inaccuracy = 0; // pixels at maximum range - public readonly string Image = null; - public readonly bool High = false; - public readonly int RangeLimit = 0; - public readonly int Arm = 0; - public readonly bool Shadow = false; - public readonly bool Proximity = false; - public readonly float Angle = 0; - - public IEffect Create(ProjectileArgs args) { return new Bullet( this, args ); } - } - - public class Bullet : IEffect - { - readonly BulletInfo Info; - readonly ProjectileArgs Args; - - int t = 0; - Animation anim; - - const int BaseBulletSpeed = 100; /* pixels / 40ms frame */ - - public Bullet(BulletInfo info, ProjectileArgs args) - { - Info = info; - Args = args; - - if (info.Inaccuracy > 0) - { - var factor = ((Args.dest - Args.src).Length / Game.CellSize) / args.weapon.Range; - Args.dest += (info.Inaccuracy * factor * args.firedBy.World.SharedRandom.Gauss2D(2)).ToInt2(); - } - - if (Info.Image != null) - { - anim = new Animation(Info.Image, GetEffectiveFacing); - anim.PlayRepeating("idle"); - } - } - - int TotalTime() { return (Args.dest - Args.src).Length * BaseBulletSpeed / Info.Speed; } - - float GetAltitude() - { - var at = (float)t / TotalTime(); - return (Args.dest - Args.src).Length * Info.Angle * 4 * at * (1 - at); - } - - int GetEffectiveFacing() - { - var at = (float)t / TotalTime(); - var attitude = Info.Angle * (1 - 2 * at); - - var rawFacing = Traits.Util.GetFacing(Args.dest - Args.src, 0); - var u = (rawFacing % 128) / 128f; - var scale = 512 * u * (1 - u); - - return (int)(rawFacing < 128 - ? rawFacing - scale * attitude - : rawFacing + scale * attitude); - } - - public void Tick( World world ) - { - t += 40; - - if (anim != null) anim.Tick(); - - if (t > TotalTime()) Explode( world ); - - if (Info.Trail != null) - { - var at = (float)t / TotalTime(); - var altitude = float2.Lerp(Args.srcAltitude, Args.destAltitude, at); - var pos = float2.Lerp(Args.src, Args.dest, at) - new float2(0, altitude); - - var highPos = (Info.High || Info.Angle > 0) - ? (pos - new float2(0, GetAltitude())) - : pos; - - world.AddFrameEndTask(w => w.Add( - new Smoke(w, highPos.ToInt2(), Info.Trail))); - } - - if (!Info.High) // check for hitting a wall - { - var at = (float)t / TotalTime(); - var pos = float2.Lerp(Args.src, Args.dest, at); - var cell = Traits.Util.CellContaining(pos); - - if (world.WorldActor.Trait().GetUnitsAt(cell).Any( - a => a.HasTrait())) - { - Args.dest = pos.ToInt2(); - Explode(world); - } - } - } - - const float height = .1f; - - public IEnumerable Render() - { - if (anim != null) - { - var at = (float)t / TotalTime(); - - var altitude = float2.Lerp(Args.srcAltitude, Args.destAltitude, at); - var pos = float2.Lerp(Args.src, Args.dest, at) - new float2(0, altitude); - - if (Info.High || Info.Angle > 0) - { - if (Info.Shadow) - yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow", (int)pos.Y); - - var highPos = pos - new float2(0, GetAltitude()); - - yield return new Renderable(anim.Image, highPos - .5f * anim.Image.size, Args.firedBy.Owner.Palette, (int)pos.Y); - } - else - yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, - Args.weapon.Underwater ? "shadow" : Args.firedBy.Owner.Palette, (int)pos.Y); - } - } - - void Explode( World world ) - { - world.AddFrameEndTask(w => w.Remove(this)); - Combat.DoImpacts(Args); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Effects; +using OpenRA.GameRules; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + public class BulletInfo : IProjectileInfo + { + public readonly int Speed = 1; + public readonly string Trail = null; + public readonly float Inaccuracy = 0; // pixels at maximum range + public readonly string Image = null; + public readonly bool High = false; + public readonly int RangeLimit = 0; + public readonly int Arm = 0; + public readonly bool Shadow = false; + public readonly bool Proximity = false; + public readonly float Angle = 0; + + public IEffect Create(ProjectileArgs args) { return new Bullet( this, args ); } + } + + public class Bullet : IEffect + { + readonly BulletInfo Info; + readonly ProjectileArgs Args; + + int t = 0; + Animation anim; + + const int BaseBulletSpeed = 100; /* pixels / 40ms frame */ + + public Bullet(BulletInfo info, ProjectileArgs args) + { + Info = info; + Args = args; + + if (info.Inaccuracy > 0) + { + var factor = ((Args.dest - Args.src).Length / Game.CellSize) / args.weapon.Range; + Args.dest += (info.Inaccuracy * factor * args.firedBy.World.SharedRandom.Gauss2D(2)).ToInt2(); + } + + if (Info.Image != null) + { + anim = new Animation(Info.Image, GetEffectiveFacing); + anim.PlayRepeating("idle"); + } + } + + int TotalTime() { return (Args.dest - Args.src).Length * BaseBulletSpeed / Info.Speed; } + + float GetAltitude() + { + var at = (float)t / TotalTime(); + return (Args.dest - Args.src).Length * Info.Angle * 4 * at * (1 - at); + } + + int GetEffectiveFacing() + { + var at = (float)t / TotalTime(); + var attitude = Info.Angle * (1 - 2 * at); + + var rawFacing = Traits.Util.GetFacing(Args.dest - Args.src, 0); + var u = (rawFacing % 128) / 128f; + var scale = 512 * u * (1 - u); + + return (int)(rawFacing < 128 + ? rawFacing - scale * attitude + : rawFacing + scale * attitude); + } + + public void Tick( World world ) + { + t += 40; + + if (anim != null) anim.Tick(); + + if (t > TotalTime()) Explode( world ); + + if (Info.Trail != null) + { + var at = (float)t / TotalTime(); + var altitude = float2.Lerp(Args.srcAltitude, Args.destAltitude, at); + var pos = float2.Lerp(Args.src, Args.dest, at) - new float2(0, altitude); + + var highPos = (Info.High || Info.Angle > 0) + ? (pos - new float2(0, GetAltitude())) + : pos; + + world.AddFrameEndTask(w => w.Add( + new Smoke(w, highPos.ToInt2(), Info.Trail))); + } + + if (!Info.High) // check for hitting a wall + { + var at = (float)t / TotalTime(); + var pos = float2.Lerp(Args.src, Args.dest, at); + var cell = Traits.Util.CellContaining(pos); + + if (world.WorldActor.Trait().GetUnitsAt(cell).Any( + a => a.HasTrait())) + { + Args.dest = pos.ToInt2(); + Explode(world); + } + } + } + + const float height = .1f; + + public IEnumerable Render() + { + if (anim != null) + { + var at = (float)t / TotalTime(); + + var altitude = float2.Lerp(Args.srcAltitude, Args.destAltitude, at); + var pos = float2.Lerp(Args.src, Args.dest, at) - new float2(0, altitude); + + if (Info.High || Info.Angle > 0) + { + if (Info.Shadow) + yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow", (int)pos.Y); + + var highPos = pos - new float2(0, GetAltitude()); + + yield return new Renderable(anim.Image, highPos - .5f * anim.Image.size, Args.firedBy.Owner.Palette, (int)pos.Y); + } + else + yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, + Args.weapon.Underwater ? "shadow" : Args.firedBy.Owner.Palette, (int)pos.Y); + } + } + + void Explode( World world ) + { + world.AddFrameEndTask(w => w.Remove(this)); + Combat.DoImpacts(Args); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/Contrail.cs b/OpenRA.Mods.RA/Effects/Contrail.cs index a6daf72a11..3688c90e2f 100755 --- a/OpenRA.Mods.RA/Effects/Contrail.cs +++ b/OpenRA.Mods.RA/Effects/Contrail.cs @@ -1,93 +1,93 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using OpenRA.FileFormats; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class ContrailInfo : ITraitInfo - { - public readonly int[] ContrailOffset = {0, 0}; - - public readonly int TrailLength = 20; - public readonly bool UsePlayerColor = true; - - public object Create(ActorInitializer init) { return new Contrail(init.self, this); } - } - - class Contrail : ITick, IPostRender - { - private ContrailInfo Info = null; - - private List positions = new List(); - - private Turret ContrailTurret = null; - - private int TrailLength = 0; - private Color TrailColor = Color.White; - - public Contrail(Actor self, ContrailInfo info) - { - Info = info; - - ContrailTurret = new Turret(Info.ContrailOffset); - - TrailLength = Info.TrailLength; - - if (Info.UsePlayerColor) - { - var ownerColor = Color.FromArgb(255, self.Owner.ColorRamp.GetColor(0)); - TrailColor = PlayerColorRemap.ColorLerp(0.5f, ownerColor, Color.White); - } - } - - public void Tick(Actor self) - { - var facing = self.Trait(); - var altitude = new float2(0, self.Trait().Altitude); - - float2 pos = self.CenterLocation - Combat.GetTurretPosition(self, facing, ContrailTurret) - altitude; - - positions.Add(pos); - - if (positions.Count >= TrailLength) - { - positions.RemoveAt(0); - } - } - - public void RenderAfterWorld(WorldRenderer wr, Actor self) - { - Color trailStart = TrailColor; - Color trailEnd = Color.FromArgb(trailStart.A - 255 / TrailLength, trailStart.R, - trailStart.G, trailStart.B); - - for (int i = positions.Count - 1; i >= 1; --i) - { - var conPos = positions[i]; - var nextPos = positions[i - 1]; - - if (self.World.LocalShroud.IsVisible(OpenRA.Traits.Util.CellContaining(conPos)) || - self.World.LocalShroud.IsVisible(OpenRA.Traits.Util.CellContaining(nextPos))) - { - Game.Renderer.LineRenderer.DrawLine(conPos, nextPos, trailStart, trailEnd); - - trailStart = trailEnd; - trailEnd = Color.FromArgb(trailStart.A - 255 / positions.Count, trailStart.R, - trailStart.G, trailStart.B); - } - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class ContrailInfo : ITraitInfo + { + public readonly int[] ContrailOffset = {0, 0}; + + public readonly int TrailLength = 20; + public readonly bool UsePlayerColor = true; + + public object Create(ActorInitializer init) { return new Contrail(init.self, this); } + } + + class Contrail : ITick, IPostRender + { + private ContrailInfo Info = null; + + private List positions = new List(); + + private Turret ContrailTurret = null; + + private int TrailLength = 0; + private Color TrailColor = Color.White; + + public Contrail(Actor self, ContrailInfo info) + { + Info = info; + + ContrailTurret = new Turret(Info.ContrailOffset); + + TrailLength = Info.TrailLength; + + if (Info.UsePlayerColor) + { + var ownerColor = Color.FromArgb(255, self.Owner.ColorRamp.GetColor(0)); + TrailColor = PlayerColorRemap.ColorLerp(0.5f, ownerColor, Color.White); + } + } + + public void Tick(Actor self) + { + var facing = self.Trait(); + var altitude = new float2(0, self.Trait().Altitude); + + float2 pos = self.CenterLocation - Combat.GetTurretPosition(self, facing, ContrailTurret) - altitude; + + positions.Add(pos); + + if (positions.Count >= TrailLength) + { + positions.RemoveAt(0); + } + } + + public void RenderAfterWorld(WorldRenderer wr, Actor self) + { + Color trailStart = TrailColor; + Color trailEnd = Color.FromArgb(trailStart.A - 255 / TrailLength, trailStart.R, + trailStart.G, trailStart.B); + + for (int i = positions.Count - 1; i >= 1; --i) + { + var conPos = positions[i]; + var nextPos = positions[i - 1]; + + if (self.World.LocalShroud.IsVisible(OpenRA.Traits.Util.CellContaining(conPos)) || + self.World.LocalShroud.IsVisible(OpenRA.Traits.Util.CellContaining(nextPos))) + { + Game.Renderer.LineRenderer.DrawLine(conPos, nextPos, trailStart, trailEnd); + + trailStart = trailEnd; + trailEnd = Color.FromArgb(trailStart.A - 255 / positions.Count, trailStart.R, + trailStart.G, trailStart.B); + } + } + } + } +} diff --git a/OpenRA.Mods.RA/Effects/Corpse.cs b/OpenRA.Mods.RA/Effects/Corpse.cs index 7ddf359b72..fa31f1066c 100644 --- a/OpenRA.Mods.RA/Effects/Corpse.cs +++ b/OpenRA.Mods.RA/Effects/Corpse.cs @@ -1,41 +1,41 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - public class Corpse : IEffect - { - readonly Animation anim; - readonly float2 pos; - readonly Player owner; - - public Corpse(Actor fromActor, int death) - { - anim = new Animation(fromActor.TraitOrDefault().GetImage(fromActor)); - anim.PlayThen("die{0}".F(death + 1), - () => fromActor.World.AddFrameEndTask(w => w.Remove(this))); - - pos = fromActor.CenterLocation; - owner = fromActor.Owner; - } - - public void Tick( World world ) { anim.Tick(); } - - public IEnumerable Render() - { - yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, owner.Palette, (int)pos.Y); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + public class Corpse : IEffect + { + readonly Animation anim; + readonly float2 pos; + readonly Player owner; + + public Corpse(Actor fromActor, int death) + { + anim = new Animation(fromActor.TraitOrDefault().GetImage(fromActor)); + anim.PlayThen("die{0}".F(death + 1), + () => fromActor.World.AddFrameEndTask(w => w.Remove(this))); + + pos = fromActor.CenterLocation; + owner = fromActor.Owner; + } + + public void Tick( World world ) { anim.Tick(); } + + public IEnumerable Render() + { + yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, owner.Palette, (int)pos.Y); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/CrateEffect.cs b/OpenRA.Mods.RA/Effects/CrateEffect.cs index 72e7254f7b..4533a0999e 100644 --- a/OpenRA.Mods.RA/Effects/CrateEffect.cs +++ b/OpenRA.Mods.RA/Effects/CrateEffect.cs @@ -1,49 +1,49 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - class CrateEffect : IEffect - { - Actor a; - Animation anim = new Animation("crate-effects"); - float2 offset = new float2(-4,0); - - public CrateEffect(Actor a, string seq, int2 offset) - : this(a, seq) - { - this.offset = offset; - } - - public CrateEffect(Actor a, string seq) - { - this.a = a; - anim.PlayThen(seq, - () => a.World.AddFrameEndTask(w => w.Remove(this))); - } - - public void Tick( World world ) - { - anim.Tick(); - } - - public IEnumerable Render() - { - if (a.IsInWorld) - yield return new Renderable(anim.Image, - a.CenterLocation - .5f * anim.Image.size + offset, "effect", (int)a.CenterLocation.Y); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + class CrateEffect : IEffect + { + Actor a; + Animation anim = new Animation("crate-effects"); + float2 offset = new float2(-4,0); + + public CrateEffect(Actor a, string seq, int2 offset) + : this(a, seq) + { + this.offset = offset; + } + + public CrateEffect(Actor a, string seq) + { + this.a = a; + anim.PlayThen(seq, + () => a.World.AddFrameEndTask(w => w.Remove(this))); + } + + public void Tick( World world ) + { + anim.Tick(); + } + + public IEnumerable Render() + { + if (a.IsInWorld) + yield return new Renderable(anim.Image, + a.CenterLocation - .5f * anim.Image.size + offset, "effect", (int)a.CenterLocation.Y); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/Explosion.cs b/OpenRA.Mods.RA/Effects/Explosion.cs index ce2abd2a78..c7d0704547 100644 --- a/OpenRA.Mods.RA/Effects/Explosion.cs +++ b/OpenRA.Mods.RA/Effects/Explosion.cs @@ -1,44 +1,44 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - public class Explosion : IEffect - { - Animation anim; - int2 pos; - int altitude; - - public Explosion(World world, int2 pixelPos, string style, bool isWater, int altitude) - { - this.pos = pixelPos; - this.altitude = altitude; - anim = new Animation("explosion"); - anim.PlayThen(style, - () => world.AddFrameEndTask(w => w.Remove(this))); - } - - public void Tick( World world ) { anim.Tick(); } - - public IEnumerable Render() - { - yield return new Renderable(anim.Image, - pos - .5f * anim.Image.size - new int2(0,altitude), - "effect", (int)pos.Y - altitude); - } - - public Player Owner { get { return null; } } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + public class Explosion : IEffect + { + Animation anim; + int2 pos; + int altitude; + + public Explosion(World world, int2 pixelPos, string style, bool isWater, int altitude) + { + this.pos = pixelPos; + this.altitude = altitude; + anim = new Animation("explosion"); + anim.PlayThen(style, + () => world.AddFrameEndTask(w => w.Remove(this))); + } + + public void Tick( World world ) { anim.Tick(); } + + public IEnumerable Render() + { + yield return new Renderable(anim.Image, + pos - .5f * anim.Image.size - new int2(0,altitude), + "effect", (int)pos.Y - altitude); + } + + public Player Owner { get { return null; } } + } +} diff --git a/OpenRA.Mods.RA/Effects/GpsSatellite.cs b/OpenRA.Mods.RA/Effects/GpsSatellite.cs index 25736ab9ad..a41550be4b 100644 --- a/OpenRA.Mods.RA/Effects/GpsSatellite.cs +++ b/OpenRA.Mods.RA/Effects/GpsSatellite.cs @@ -1,44 +1,44 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - class GpsSatellite : IEffect - { - readonly float heightPerTick = 10; - float2 offset; - Animation anim = new Animation("sputnik"); - - public GpsSatellite(float2 offset) - { - this.offset = offset; - anim.PlayRepeating("idle"); - } - - public void Tick( World world ) - { - anim.Tick(); - offset.Y -= heightPerTick; - - if (offset.Y < 0) - world.AddFrameEndTask(w => w.Remove(this)); - } - - public IEnumerable Render() - { - yield return new Renderable(anim.Image,offset, "effect", (int)offset.Y); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + class GpsSatellite : IEffect + { + readonly float heightPerTick = 10; + float2 offset; + Animation anim = new Animation("sputnik"); + + public GpsSatellite(float2 offset) + { + this.offset = offset; + anim.PlayRepeating("idle"); + } + + public void Tick( World world ) + { + anim.Tick(); + offset.Y -= heightPerTick; + + if (offset.Y < 0) + world.AddFrameEndTask(w => w.Remove(this)); + } + + public IEnumerable Render() + { + yield return new Renderable(anim.Image,offset, "effect", (int)offset.Y); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/GravityBomb.cs b/OpenRA.Mods.RA/Effects/GravityBomb.cs index 5f3424a91c..6d18e17823 100755 --- a/OpenRA.Mods.RA/Effects/GravityBomb.cs +++ b/OpenRA.Mods.RA/Effects/GravityBomb.cs @@ -1,60 +1,60 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.GameRules; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - public class GravityBombInfo : IProjectileInfo - { - public readonly string Image = null; - public IEffect Create(ProjectileArgs args) { return new GravityBomb(this, args); } - } - - public class GravityBomb : IEffect - { - Animation anim; - int altitude; - ProjectileArgs Args; - - public GravityBomb(GravityBombInfo info, ProjectileArgs args) - { - Args = args; - altitude = args.srcAltitude; - - anim = new Animation(info.Image); - if (anim.HasSequence("open")) - anim.PlayThen("open", () => anim.PlayRepeating("idle")); - else - anim.PlayRepeating("idle"); - } - - public void Tick(World world) - { - if (--altitude <= Args.destAltitude) - { - world.AddFrameEndTask(w => w.Remove(this)); - Combat.DoImpacts(Args); - } - - anim.Tick(); - } - - public IEnumerable Render() - { - yield return new Renderable(anim.Image, - Args.dest - new int2(0, altitude) - .5f * anim.Image.size, "effect", Args.dest.Y); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.GameRules; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + public class GravityBombInfo : IProjectileInfo + { + public readonly string Image = null; + public IEffect Create(ProjectileArgs args) { return new GravityBomb(this, args); } + } + + public class GravityBomb : IEffect + { + Animation anim; + int altitude; + ProjectileArgs Args; + + public GravityBomb(GravityBombInfo info, ProjectileArgs args) + { + Args = args; + altitude = args.srcAltitude; + + anim = new Animation(info.Image); + if (anim.HasSequence("open")) + anim.PlayThen("open", () => anim.PlayRepeating("idle")); + else + anim.PlayRepeating("idle"); + } + + public void Tick(World world) + { + if (--altitude <= Args.destAltitude) + { + world.AddFrameEndTask(w => w.Remove(this)); + Combat.DoImpacts(Args); + } + + anim.Tick(); + } + + public IEnumerable Render() + { + yield return new Renderable(anim.Image, + Args.dest - new int2(0, altitude) - .5f * anim.Image.size, "effect", Args.dest.Y); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/InvulnEffect.cs b/OpenRA.Mods.RA/Effects/InvulnEffect.cs index 242038bb59..ba316c839b 100644 --- a/OpenRA.Mods.RA/Effects/InvulnEffect.cs +++ b/OpenRA.Mods.RA/Effects/InvulnEffect.cs @@ -1,43 +1,43 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - class InvulnEffect : IEffect - { - Actor a; - IronCurtainable b; - - public InvulnEffect(Actor a) - { - this.a = a; - this.b = a.Trait(); - } - - public void Tick( World world ) - { - if (a.Destroyed || a.IsDead() || b.GetDamageModifier(null, null) > 0) - world.AddFrameEndTask(w => w.Remove(this)); - } - - public IEnumerable Render() - { - if (a.Destroyed) // Tick will clean up - yield break; - - foreach (var r in a.Render()) - yield return r.WithPalette("invuln"); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + class InvulnEffect : IEffect + { + Actor a; + IronCurtainable b; + + public InvulnEffect(Actor a) + { + this.a = a; + this.b = a.Trait(); + } + + public void Tick( World world ) + { + if (a.Destroyed || a.IsDead() || b.GetDamageModifier(null, null) > 0) + world.AddFrameEndTask(w => w.Remove(this)); + } + + public IEnumerable Render() + { + if (a.Destroyed) // Tick will clean up + yield break; + + foreach (var r in a.Render()) + yield return r.WithPalette("invuln"); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/LaserZap.cs b/OpenRA.Mods.RA/Effects/LaserZap.cs index c8fcb863b5..7e09a001e4 100755 --- a/OpenRA.Mods.RA/Effects/LaserZap.cs +++ b/OpenRA.Mods.RA/Effects/LaserZap.cs @@ -1,77 +1,77 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using OpenRA.Effects; -using OpenRA.GameRules; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - class LaserZapInfo : IProjectileInfo - { - public readonly int BeamRadius = 1; - public readonly bool UsePlayerColor = false; - - public IEffect Create(ProjectileArgs args) - { - Color c = UsePlayerColor ? args.firedBy.Owner.ColorRamp.GetColor(0) : Color.Red; - return new LaserZap(args, BeamRadius, c); - } - } - - class LaserZap : IEffect - { - ProjectileArgs args; - readonly int radius; - int timeUntilRemove = 10; // # of frames - int totalTime = 10; - Color color; - bool doneDamage = false; - - public LaserZap(ProjectileArgs args, int radius, Color color) - { - this.args = args; - this.color = color; - this.radius = radius; - } - - public void Tick(World world) - { - if (timeUntilRemove <= 0) - world.AddFrameEndTask(w => w.Remove(this)); - --timeUntilRemove; - - if (!doneDamage) - { - if (args.target.IsValid) - args.dest = args.target.CenterLocation; - - Combat.DoImpacts(args); - doneDamage = true; - } - } - - public IEnumerable Render() - { - int alpha = (int)((1-(float)(totalTime-timeUntilRemove)/totalTime)*255); - Color rc = Color.FromArgb(alpha,color); - - float2 unit = 1.0f/(args.src - args.dest).Length*(args.src - args.dest).ToFloat2(); - float2 norm = new float2(-unit.Y, unit.X); - - for (int i = -radius; i < radius; i++) - Game.Renderer.LineRenderer.DrawLine(args.src + i * norm, args.dest + i * norm, rc, rc); - - yield break; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using OpenRA.Effects; +using OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + class LaserZapInfo : IProjectileInfo + { + public readonly int BeamRadius = 1; + public readonly bool UsePlayerColor = false; + + public IEffect Create(ProjectileArgs args) + { + Color c = UsePlayerColor ? args.firedBy.Owner.ColorRamp.GetColor(0) : Color.Red; + return new LaserZap(args, BeamRadius, c); + } + } + + class LaserZap : IEffect + { + ProjectileArgs args; + readonly int radius; + int timeUntilRemove = 10; // # of frames + int totalTime = 10; + Color color; + bool doneDamage = false; + + public LaserZap(ProjectileArgs args, int radius, Color color) + { + this.args = args; + this.color = color; + this.radius = radius; + } + + public void Tick(World world) + { + if (timeUntilRemove <= 0) + world.AddFrameEndTask(w => w.Remove(this)); + --timeUntilRemove; + + if (!doneDamage) + { + if (args.target.IsValid) + args.dest = args.target.CenterLocation; + + Combat.DoImpacts(args); + doneDamage = true; + } + } + + public IEnumerable Render() + { + int alpha = (int)((1-(float)(totalTime-timeUntilRemove)/totalTime)*255); + Color rc = Color.FromArgb(alpha,color); + + float2 unit = 1.0f/(args.src - args.dest).Length*(args.src - args.dest).ToFloat2(); + float2 norm = new float2(-unit.Y, unit.X); + + for (int i = -radius; i < radius; i++) + Game.Renderer.LineRenderer.DrawLine(args.src + i * norm, args.dest + i * norm, rc, rc); + + yield break; + } + } +} diff --git a/OpenRA.Mods.RA/Effects/Missile.cs b/OpenRA.Mods.RA/Effects/Missile.cs index 1c69037007..7a55890154 100755 --- a/OpenRA.Mods.RA/Effects/Missile.cs +++ b/OpenRA.Mods.RA/Effects/Missile.cs @@ -1,139 +1,139 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Effects; -using OpenRA.GameRules; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - class MissileInfo : IProjectileInfo - { - public readonly int Speed = 1; - public readonly int Arm = 0; - public readonly bool High = false; - public readonly bool Shadow = true; - public readonly bool Proximity = false; - public readonly string Trail = null; - public readonly float Inaccuracy = 0; - public readonly string Image = null; - public readonly int ROT = 5; - public readonly int RangeLimit = 0; - public readonly bool TurboBoost = false; - - public IEffect Create(ProjectileArgs args) { return new Missile( this, args ); } - } - - class Missile : IEffect - { - readonly MissileInfo Info; - readonly ProjectileArgs Args; - - int2 offset; - public int2 SubPxPosition; - public int2 PxPosition { get { return new int2( SubPxPosition.X / 1024, SubPxPosition.Y / 1024 ); } } - - readonly Animation anim; - int Facing; - int t; - int Altitude; - - public Missile(MissileInfo info, ProjectileArgs args) - { - Info = info; - Args = args; - - SubPxPosition = 1024*Args.src; - Altitude = Args.srcAltitude; - Facing = Args.facing; - - if (info.Inaccuracy > 0) - offset = (info.Inaccuracy * args.firedBy.World.SharedRandom.Gauss2D(2)).ToInt2(); - - if (Info.Image != null) - { - anim = new Animation(Info.Image, () => Facing); - anim.PlayRepeating("idle"); - } - } - - // In pixels - const int MissileCloseEnough = 7; - - - public void Tick( World world ) - { - t += 40; - - // In pixels - var dist = Args.target.CenterLocation + offset - PxPosition; - - var targetAltitude = 0; - if (Args.target.IsValid && Args.target.IsActor && Args.target.Actor.HasTrait()) - targetAltitude = Args.target.Actor.Trait().Altitude; - - Altitude += Math.Sign(targetAltitude - Altitude); - - Facing = Traits.Util.TickFacing(Facing, - Traits.Util.GetFacing(dist, Facing), - Info.ROT); - - anim.Tick(); - - if (dist.LengthSquared < MissileCloseEnough * MissileCloseEnough || !Args.target.IsValid ) - Explode(world); - - // TODO: Replace this with a lookup table - var dir = (-float2.FromAngle((float)(Facing / 128f * Math.PI))*1024).ToInt2(); - - var move = Info.Speed * dir; - if (targetAltitude > 0 && Info.TurboBoost) - move = (move * 3) / 2; - move = move / 5; - - SubPxPosition += move; - - if (Info.Trail != null) - { - var sp = (SubPxPosition - (move * 3) / 2) / 1024 - new int2(0, Altitude); - world.AddFrameEndTask(w => w.Add(new Smoke(w, sp, Info.Trail))); - } - - if (Info.RangeLimit != 0 && t > Info.RangeLimit * 40) - Explode(world); - - if (!Info.High) // check for hitting a wall - { - var cell = Traits.Util.CellContaining(PxPosition); - if (world.WorldActor.Trait().GetUnitsAt(cell).Any( - a => a.HasTrait())) - Explode(world); - } - } - - void Explode(World world) - { - world.AddFrameEndTask(w => w.Remove(this)); - Args.dest = PxPosition; - if (t > Info.Arm * 40) /* don't blow up in our launcher's face! */ - Combat.DoImpacts(Args); - } - - public IEnumerable Render() - { - yield return new Renderable(anim.Image,PxPosition.ToFloat2() - 0.5f * anim.Image.size - new float2(0, Altitude), - Args.weapon.Underwater ? "shadow" : "effect", PxPosition.Y); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Effects; +using OpenRA.GameRules; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + class MissileInfo : IProjectileInfo + { + public readonly int Speed = 1; + public readonly int Arm = 0; + public readonly bool High = false; + public readonly bool Shadow = true; + public readonly bool Proximity = false; + public readonly string Trail = null; + public readonly float Inaccuracy = 0; + public readonly string Image = null; + public readonly int ROT = 5; + public readonly int RangeLimit = 0; + public readonly bool TurboBoost = false; + + public IEffect Create(ProjectileArgs args) { return new Missile( this, args ); } + } + + class Missile : IEffect + { + readonly MissileInfo Info; + readonly ProjectileArgs Args; + + int2 offset; + public int2 SubPxPosition; + public int2 PxPosition { get { return new int2( SubPxPosition.X / 1024, SubPxPosition.Y / 1024 ); } } + + readonly Animation anim; + int Facing; + int t; + int Altitude; + + public Missile(MissileInfo info, ProjectileArgs args) + { + Info = info; + Args = args; + + SubPxPosition = 1024*Args.src; + Altitude = Args.srcAltitude; + Facing = Args.facing; + + if (info.Inaccuracy > 0) + offset = (info.Inaccuracy * args.firedBy.World.SharedRandom.Gauss2D(2)).ToInt2(); + + if (Info.Image != null) + { + anim = new Animation(Info.Image, () => Facing); + anim.PlayRepeating("idle"); + } + } + + // In pixels + const int MissileCloseEnough = 7; + + + public void Tick( World world ) + { + t += 40; + + // In pixels + var dist = Args.target.CenterLocation + offset - PxPosition; + + var targetAltitude = 0; + if (Args.target.IsValid && Args.target.IsActor && Args.target.Actor.HasTrait()) + targetAltitude = Args.target.Actor.Trait().Altitude; + + Altitude += Math.Sign(targetAltitude - Altitude); + + Facing = Traits.Util.TickFacing(Facing, + Traits.Util.GetFacing(dist, Facing), + Info.ROT); + + anim.Tick(); + + if (dist.LengthSquared < MissileCloseEnough * MissileCloseEnough || !Args.target.IsValid ) + Explode(world); + + // TODO: Replace this with a lookup table + var dir = (-float2.FromAngle((float)(Facing / 128f * Math.PI))*1024).ToInt2(); + + var move = Info.Speed * dir; + if (targetAltitude > 0 && Info.TurboBoost) + move = (move * 3) / 2; + move = move / 5; + + SubPxPosition += move; + + if (Info.Trail != null) + { + var sp = (SubPxPosition - (move * 3) / 2) / 1024 - new int2(0, Altitude); + world.AddFrameEndTask(w => w.Add(new Smoke(w, sp, Info.Trail))); + } + + if (Info.RangeLimit != 0 && t > Info.RangeLimit * 40) + Explode(world); + + if (!Info.High) // check for hitting a wall + { + var cell = Traits.Util.CellContaining(PxPosition); + if (world.WorldActor.Trait().GetUnitsAt(cell).Any( + a => a.HasTrait())) + Explode(world); + } + } + + void Explode(World world) + { + world.AddFrameEndTask(w => w.Remove(this)); + Args.dest = PxPosition; + if (t > Info.Arm * 40) /* don't blow up in our launcher's face! */ + Combat.DoImpacts(Args); + } + + public IEnumerable Render() + { + yield return new Renderable(anim.Image,PxPosition.ToFloat2() - 0.5f * anim.Image.size - new float2(0, Altitude), + Args.weapon.Underwater ? "shadow" : "effect", PxPosition.Y); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/NukeLaunch.cs b/OpenRA.Mods.RA/Effects/NukeLaunch.cs index ef3a9757fc..93eed7b0c6 100755 --- a/OpenRA.Mods.RA/Effects/NukeLaunch.cs +++ b/OpenRA.Mods.RA/Effects/NukeLaunch.cs @@ -1,89 +1,89 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - public class NukeLaunch : IEffect - { - readonly Player firedBy; - Animation anim; - int2 pos; - int2 targetLocation; - int altitude; - bool goingUp = true; - string weapon; - - public NukeLaunch(Player firedBy, Actor silo, string weapon, int2 spawnOffset, int2 targetLocation) - { - this.firedBy = firedBy; - this.targetLocation = targetLocation; - this.weapon = weapon; - anim = new Animation(weapon); - anim.PlayRepeating("up"); - - if (silo == null) - { - altitude = firedBy.World.Map.Bounds.Height*Game.CellSize; - StartDescent(firedBy.World); - } - else - pos = silo.CenterLocation + spawnOffset; - } - - void StartDescent(World world) - { - pos = OpenRA.Traits.Util.CenterOfCell(targetLocation); - anim.PlayRepeating("down"); - goingUp = false; - } - - public void Tick(World world) - { - anim.Tick(); - - if (goingUp) - { - altitude += 10; - if (altitude >= world.Map.Bounds.Height*Game.CellSize) - StartDescent(world); - } - else - { - altitude -= 10; - if (altitude <= 0) - { - // Trigger screen desaturate effect - foreach (var a in world.Queries.WithTrait()) - a.Trait.Enable(); - - Explode(world); - } - } - } - - void Explode(World world) - { - world.AddFrameEndTask(w => w.Remove(this)); - Combat.DoExplosion(firedBy.PlayerActor, weapon, pos, 0); - world.WorldActor.Trait().AddEffect(20, pos, 5); - } - - public IEnumerable Render() - { - yield return new Renderable(anim.Image, pos - 0.5f * anim.Image.size - new float2(0, altitude), - "effect", (int)pos.Y); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + public class NukeLaunch : IEffect + { + readonly Player firedBy; + Animation anim; + int2 pos; + int2 targetLocation; + int altitude; + bool goingUp = true; + string weapon; + + public NukeLaunch(Player firedBy, Actor silo, string weapon, int2 spawnOffset, int2 targetLocation) + { + this.firedBy = firedBy; + this.targetLocation = targetLocation; + this.weapon = weapon; + anim = new Animation(weapon); + anim.PlayRepeating("up"); + + if (silo == null) + { + altitude = firedBy.World.Map.Bounds.Height*Game.CellSize; + StartDescent(firedBy.World); + } + else + pos = silo.CenterLocation + spawnOffset; + } + + void StartDescent(World world) + { + pos = OpenRA.Traits.Util.CenterOfCell(targetLocation); + anim.PlayRepeating("down"); + goingUp = false; + } + + public void Tick(World world) + { + anim.Tick(); + + if (goingUp) + { + altitude += 10; + if (altitude >= world.Map.Bounds.Height*Game.CellSize) + StartDescent(world); + } + else + { + altitude -= 10; + if (altitude <= 0) + { + // Trigger screen desaturate effect + foreach (var a in world.Queries.WithTrait()) + a.Trait.Enable(); + + Explode(world); + } + } + } + + void Explode(World world) + { + world.AddFrameEndTask(w => w.Remove(this)); + Combat.DoExplosion(firedBy.PlayerActor, weapon, pos, 0); + world.WorldActor.Trait().AddEffect(20, pos, 5); + } + + public IEnumerable Render() + { + yield return new Renderable(anim.Image, pos - 0.5f * anim.Image.size - new float2(0, altitude), + "effect", (int)pos.Y); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/Parachute.cs b/OpenRA.Mods.RA/Effects/Parachute.cs index bf30eda4ab..283c05aee1 100644 --- a/OpenRA.Mods.RA/Effects/Parachute.cs +++ b/OpenRA.Mods.RA/Effects/Parachute.cs @@ -1,74 +1,74 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - public class Parachute : IEffect - { - readonly Animation anim; - readonly Animation paraAnim; - readonly float2 location; - - readonly Actor cargo; - readonly Player owner; - - float altitude; - const float fallRate = .3f; - - public Parachute(Player owner, string image, float2 location, int altitude, Actor cargo) - { - this.location = location; - this.altitude = altitude; - this.cargo = cargo; - this.owner = owner; - - anim = new Animation(image); - if (anim.HasSequence("idle")) - anim.PlayFetchIndex("idle", () => 0); - else - anim.PlayFetchIndex("stand", () => 0); - anim.Tick(); - - paraAnim = new Animation("parach"); - paraAnim.PlayThen("open", () => paraAnim.PlayRepeating("idle")); - } - - public void Tick(World world) - { - paraAnim.Tick(); - - altitude -= fallRate; - - if (altitude <= 0) - world.AddFrameEndTask(w => - { - w.Remove(this); - var loc = Traits.Util.CellContaining(location); - cargo.CancelActivity(); - cargo.Trait().SetPosition(cargo, loc); - w.Add(cargo); - }); - } - - public IEnumerable Render() - { - var pos = location - new float2(0, altitude); - yield return new Renderable(anim.Image, location - .5f * anim.Image.size, "shadow", 0); - yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, owner.Palette, 2); - yield return new Renderable(paraAnim.Image, pos - .5f * paraAnim.Image.size, owner.Palette, 3); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + public class Parachute : IEffect + { + readonly Animation anim; + readonly Animation paraAnim; + readonly float2 location; + + readonly Actor cargo; + readonly Player owner; + + float altitude; + const float fallRate = .3f; + + public Parachute(Player owner, string image, float2 location, int altitude, Actor cargo) + { + this.location = location; + this.altitude = altitude; + this.cargo = cargo; + this.owner = owner; + + anim = new Animation(image); + if (anim.HasSequence("idle")) + anim.PlayFetchIndex("idle", () => 0); + else + anim.PlayFetchIndex("stand", () => 0); + anim.Tick(); + + paraAnim = new Animation("parach"); + paraAnim.PlayThen("open", () => paraAnim.PlayRepeating("idle")); + } + + public void Tick(World world) + { + paraAnim.Tick(); + + altitude -= fallRate; + + if (altitude <= 0) + world.AddFrameEndTask(w => + { + w.Remove(this); + var loc = Traits.Util.CellContaining(location); + cargo.CancelActivity(); + cargo.Trait().SetPosition(cargo, loc); + w.Add(cargo); + }); + } + + public IEnumerable Render() + { + var pos = location - new float2(0, altitude); + yield return new Renderable(anim.Image, location - .5f * anim.Image.size, "shadow", 0); + yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, owner.Palette, 2); + yield return new Renderable(paraAnim.Image, pos - .5f * paraAnim.Image.size, owner.Palette, 3); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/RallyPoint.cs b/OpenRA.Mods.RA/Effects/RallyPoint.cs index b9644e5c98..1f90699f0c 100755 --- a/OpenRA.Mods.RA/Effects/RallyPoint.cs +++ b/OpenRA.Mods.RA/Effects/RallyPoint.cs @@ -1,65 +1,65 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Mods.RA; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - class RallyPoint : IEffect - { - Actor building; - RA.RallyPoint rp; - public Animation flag = new Animation("rallypoint"); - public Animation circles = new Animation("rallypoint"); - - public RallyPoint(Actor building) - { - this.building = building; - rp = building.Trait(); - flag.PlayRepeating("flag"); - circles.Play("circles"); - } - - int2 cachedLocation; - public void Tick( World world ) - { - flag.Tick(); - circles.Tick(); - if (cachedLocation != rp.rallyPoint) - { - cachedLocation = rp.rallyPoint; - circles.Play("circles"); - } - - if (!building.IsInWorld || building.IsDead()) - world.AddFrameEndTask(w => w.Remove(this)); - } - - public IEnumerable Render() - { - if (building.IsInWorld && building.Owner == building.World.LocalPlayer && building.World.Selection.Actors.Contains(building)) - { - var pos = Traits.Util.CenterOfCell(rp.rallyPoint); - yield return new Renderable(circles.Image, - pos - .5f * circles.Image.size, - building.Owner.Palette, (int)pos.Y); - - yield return new Renderable(flag.Image, - pos + new float2(-1,-17), - building.Owner.Palette, (int)pos.Y); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Mods.RA; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + class RallyPoint : IEffect + { + Actor building; + RA.RallyPoint rp; + public Animation flag = new Animation("rallypoint"); + public Animation circles = new Animation("rallypoint"); + + public RallyPoint(Actor building) + { + this.building = building; + rp = building.Trait(); + flag.PlayRepeating("flag"); + circles.Play("circles"); + } + + int2 cachedLocation; + public void Tick( World world ) + { + flag.Tick(); + circles.Tick(); + if (cachedLocation != rp.rallyPoint) + { + cachedLocation = rp.rallyPoint; + circles.Play("circles"); + } + + if (!building.IsInWorld || building.IsDead()) + world.AddFrameEndTask(w => w.Remove(this)); + } + + public IEnumerable Render() + { + if (building.IsInWorld && building.Owner == building.World.LocalPlayer && building.World.Selection.Actors.Contains(building)) + { + var pos = Traits.Util.CenterOfCell(rp.rallyPoint); + yield return new Renderable(circles.Image, + pos - .5f * circles.Image.size, + building.Owner.Palette, (int)pos.Y); + + yield return new Renderable(flag.Image, + pos + new float2(-1,-17), + building.Owner.Palette, (int)pos.Y); + } + } + } +} diff --git a/OpenRA.Mods.RA/Effects/RepairIndicator.cs b/OpenRA.Mods.RA/Effects/RepairIndicator.cs index 86a1441a40..df0d73afff 100755 --- a/OpenRA.Mods.RA/Effects/RepairIndicator.cs +++ b/OpenRA.Mods.RA/Effects/RepairIndicator.cs @@ -1,44 +1,44 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - class RepairIndicator : IEffect - { - int framesLeft; - Actor a; - Animation anim = new Animation("select"); - - public RepairIndicator(Actor a) - { - this.a = a; anim.PlayRepeating("repair"); - framesLeft = (int)(a.Info.Traits.Get().RepairRate * 25 * 60 / 2); - } - - public void Tick( World world ) - { - if (--framesLeft == 0 || !a.IsInWorld || a.IsDead()) - world.AddFrameEndTask(w => w.Remove(this)); - } - - public IEnumerable Render() - { - if (a.IsInWorld) - yield return new Renderable(anim.Image, - a.CenterLocation - .5f * anim.Image.size, "chrome", (int)a.CenterLocation.Y); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + class RepairIndicator : IEffect + { + int framesLeft; + Actor a; + Animation anim = new Animation("select"); + + public RepairIndicator(Actor a) + { + this.a = a; anim.PlayRepeating("repair"); + framesLeft = (int)(a.Info.Traits.Get().RepairRate * 25 * 60 / 2); + } + + public void Tick( World world ) + { + if (--framesLeft == 0 || !a.IsInWorld || a.IsDead()) + world.AddFrameEndTask(w => w.Remove(this)); + } + + public IEnumerable Render() + { + if (a.IsInWorld) + yield return new Renderable(anim.Image, + a.CenterLocation - .5f * anim.Image.size, "chrome", (int)a.CenterLocation.Y); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/SatelliteLaunch.cs b/OpenRA.Mods.RA/Effects/SatelliteLaunch.cs index ee99372750..5377624465 100644 --- a/OpenRA.Mods.RA/Effects/SatelliteLaunch.cs +++ b/OpenRA.Mods.RA/Effects/SatelliteLaunch.cs @@ -1,48 +1,48 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - class SatelliteLaunch : IEffect - { - int frame = 0; - Actor a; - Animation doors = new Animation("atek"); - float2 doorOffset = new float2(-4,0); - - public SatelliteLaunch(Actor a) - { - this.a = a; - doors.PlayThen("active", - () => a.World.AddFrameEndTask(w => w.Remove(this))); - } - - public void Tick( World world ) - { - doors.Tick(); - - if (++frame == 19) - { - world.AddFrameEndTask(w => w.Add(new GpsSatellite(a.CenterLocation - .5f * doors.Image.size + doorOffset))); - } - } - - public IEnumerable Render() - { - yield return new Renderable(doors.Image, - a.CenterLocation - .5f * doors.Image.size + doorOffset, "effect", (int)doorOffset.Y); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + class SatelliteLaunch : IEffect + { + int frame = 0; + Actor a; + Animation doors = new Animation("atek"); + float2 doorOffset = new float2(-4,0); + + public SatelliteLaunch(Actor a) + { + this.a = a; + doors.PlayThen("active", + () => a.World.AddFrameEndTask(w => w.Remove(this))); + } + + public void Tick( World world ) + { + doors.Tick(); + + if (++frame == 19) + { + world.AddFrameEndTask(w => w.Add(new GpsSatellite(a.CenterLocation - .5f * doors.Image.size + doorOffset))); + } + } + + public IEnumerable Render() + { + yield return new Renderable(doors.Image, + a.CenterLocation - .5f * doors.Image.size + doorOffset, "effect", (int)doorOffset.Y); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/Smoke.cs b/OpenRA.Mods.RA/Effects/Smoke.cs index ccb9d3fc4a..cdffcba482 100644 --- a/OpenRA.Mods.RA/Effects/Smoke.cs +++ b/OpenRA.Mods.RA/Effects/Smoke.cs @@ -1,41 +1,41 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Effects; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - public class Smoke : IEffect - { - readonly int2 pos; - readonly Animation anim; - - public Smoke(World world, int2 pos, string trail) - { - this.pos = pos; - anim = new Animation(trail); - anim.PlayThen("idle", - () => world.AddFrameEndTask(w => w.Remove(this))); - } - - public void Tick( World world ) - { - anim.Tick(); - } - - public IEnumerable Render() - { - yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "effect", (int)pos.Y); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + public class Smoke : IEffect + { + readonly int2 pos; + readonly Animation anim; + + public Smoke(World world, int2 pos, string trail) + { + this.pos = pos; + anim = new Animation(trail); + anim.PlayThen("idle", + () => world.AddFrameEndTask(w => w.Remove(this))); + } + + public void Tick( World world ) + { + anim.Tick(); + } + + public IEnumerable Render() + { + yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "effect", (int)pos.Y); + } + } +} diff --git a/OpenRA.Mods.RA/Effects/TeslaZap.cs b/OpenRA.Mods.RA/Effects/TeslaZap.cs index b214e35e43..d7f25ddb4c 100755 --- a/OpenRA.Mods.RA/Effects/TeslaZap.cs +++ b/OpenRA.Mods.RA/Effects/TeslaZap.cs @@ -1,127 +1,127 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Effects; -using OpenRA.GameRules; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Effects -{ - class TeslaZapInfo : IProjectileInfo - { - public IEffect Create(ProjectileArgs args) { return new TeslaZap( this, args ); } - } - - class TeslaZap : IEffect - { - readonly ProjectileArgs Args; - int timeUntilRemove = 2; // # of frames - bool doneDamage = false; - - const int numZaps = 3; - - readonly List renderables = new List(); - - public TeslaZap(TeslaZapInfo info, ProjectileArgs args) - { - Args = args; - var bright = SequenceProvider.GetSequence("litning", "bright"); - var dim = SequenceProvider.GetSequence("litning", "dim"); - - for (var n = 0; n < numZaps; n++) - renderables.AddRange(DrawZapWandering(args.src, args.dest, n == numZaps - 1 ? bright : dim)); - } - - public void Tick( World world ) - { - if( timeUntilRemove <= 0 ) - world.AddFrameEndTask( w => w.Remove( this ) ); - --timeUntilRemove; - - if (!doneDamage) - { - if (Args.target.IsValid) - Args.dest = Args.target.CenterLocation; - - Combat.DoImpacts(Args); - doneDamage = true; - } - } - - public IEnumerable Render() { return renderables; } - - static IEnumerable DrawZapWandering(int2 from, int2 to, Sequence s) - { - var z = float2.Zero; /* hack */ - var dist = to - from; - var norm = (1f / dist.Length) * new float2(-dist.Y, dist.X); - - var renderables = new List(); - if (Game.CosmeticRandom.Next(2) != 0) - { - var p1 = from + (1 / 3f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; - var p2 = from + (2 / 3f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; - - renderables.AddRange(DrawZap(from, p1, s, out p1)); - renderables.AddRange(DrawZap(p1, p2, s, out p2)); - renderables.AddRange(DrawZap(p2, to, s, out z)); - } - else - { - var p1 = from + (1 / 2f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; - - renderables.AddRange(DrawZap(from, p1, s, out p1)); - renderables.AddRange(DrawZap(p1, to, s, out z)); - } - - return renderables; - } - - static IEnumerable DrawZap(float2 from, float2 to, Sequence s, out float2 p) - { - var dist = to - from; - var q = new float2(-dist.Y, dist.X); - var c = -float2.Dot(from, q); - var rs = new List(); - var z = from; - - while ((to - z).X > 5 || (to - z).X < -5 || (to - z).Y > 5 || (to - z).Y < -5) - { - var step = steps.Where(t => (to - (z + new float2(t[0],t[1]))).LengthSquared < (to - z).LengthSquared ) - .OrderBy(t => Math.Abs(float2.Dot(z + new float2(t[0], t[1]), q) + c)).First(); - - rs.Add(new Renderable(s.GetSprite(step[4]), z + new float2(step[2], step[3]), "effect", (int)from.Y)); - z += new float2(step[0], step[1]); - if( rs.Count >= 1000 ) - break; - } - - p = z; - - return rs; - } - - static int[][] steps = new [] - { - new int[] { 8, 8, -8, -8, 0 }, - new int[] { -8, -8, -16, -16, 0 }, - new int[] { 8, 0, -8, -8, 1 }, - new int[] { -8, 0, -16, -8, 1 }, - new int[] { 0, 8, -8, -8, 2 }, - new int[] { 0, -8, -8, -16, 2 }, - new int[] { -8, 8, -16, -8, 3 }, - new int[] { 8, -8, -8, -16, 3 } - }; - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Effects; +using OpenRA.GameRules; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Effects +{ + class TeslaZapInfo : IProjectileInfo + { + public IEffect Create(ProjectileArgs args) { return new TeslaZap( this, args ); } + } + + class TeslaZap : IEffect + { + readonly ProjectileArgs Args; + int timeUntilRemove = 2; // # of frames + bool doneDamage = false; + + const int numZaps = 3; + + readonly List renderables = new List(); + + public TeslaZap(TeslaZapInfo info, ProjectileArgs args) + { + Args = args; + var bright = SequenceProvider.GetSequence("litning", "bright"); + var dim = SequenceProvider.GetSequence("litning", "dim"); + + for (var n = 0; n < numZaps; n++) + renderables.AddRange(DrawZapWandering(args.src, args.dest, n == numZaps - 1 ? bright : dim)); + } + + public void Tick( World world ) + { + if( timeUntilRemove <= 0 ) + world.AddFrameEndTask( w => w.Remove( this ) ); + --timeUntilRemove; + + if (!doneDamage) + { + if (Args.target.IsValid) + Args.dest = Args.target.CenterLocation; + + Combat.DoImpacts(Args); + doneDamage = true; + } + } + + public IEnumerable Render() { return renderables; } + + static IEnumerable DrawZapWandering(int2 from, int2 to, Sequence s) + { + var z = float2.Zero; /* hack */ + var dist = to - from; + var norm = (1f / dist.Length) * new float2(-dist.Y, dist.X); + + var renderables = new List(); + if (Game.CosmeticRandom.Next(2) != 0) + { + var p1 = from + (1 / 3f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; + var p2 = from + (2 / 3f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; + + renderables.AddRange(DrawZap(from, p1, s, out p1)); + renderables.AddRange(DrawZap(p1, p2, s, out p2)); + renderables.AddRange(DrawZap(p2, to, s, out z)); + } + else + { + var p1 = from + (1 / 2f) * dist.ToFloat2() + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; + + renderables.AddRange(DrawZap(from, p1, s, out p1)); + renderables.AddRange(DrawZap(p1, to, s, out z)); + } + + return renderables; + } + + static IEnumerable DrawZap(float2 from, float2 to, Sequence s, out float2 p) + { + var dist = to - from; + var q = new float2(-dist.Y, dist.X); + var c = -float2.Dot(from, q); + var rs = new List(); + var z = from; + + while ((to - z).X > 5 || (to - z).X < -5 || (to - z).Y > 5 || (to - z).Y < -5) + { + var step = steps.Where(t => (to - (z + new float2(t[0],t[1]))).LengthSquared < (to - z).LengthSquared ) + .OrderBy(t => Math.Abs(float2.Dot(z + new float2(t[0], t[1]), q) + c)).First(); + + rs.Add(new Renderable(s.GetSprite(step[4]), z + new float2(step[2], step[3]), "effect", (int)from.Y)); + z += new float2(step[0], step[1]); + if( rs.Count >= 1000 ) + break; + } + + p = z; + + return rs; + } + + static int[][] steps = new [] + { + new int[] { 8, 8, -8, -8, 0 }, + new int[] { -8, -8, -16, -16, 0 }, + new int[] { 8, 0, -8, -8, 1 }, + new int[] { -8, 0, -16, -8, 1 }, + new int[] { 0, 8, -8, -8, 2 }, + new int[] { 0, -8, -8, -16, 2 }, + new int[] { -8, 8, -16, -8, 3 }, + new int[] { 8, -8, -8, -16, 3 } + }; + } +} diff --git a/OpenRA.Mods.RA/EmitInfantryOnSell.cs b/OpenRA.Mods.RA/EmitInfantryOnSell.cs index aa74300ec3..a93bcd19ec 100644 --- a/OpenRA.Mods.RA/EmitInfantryOnSell.cs +++ b/OpenRA.Mods.RA/EmitInfantryOnSell.cs @@ -1,68 +1,68 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class EmitInfantryOnSellInfo : TraitInfo - { - public readonly float ValueFraction = .4f; - public readonly float MinHpFraction = .3f; - - [ActorReference] - public readonly string[] ActorTypes = { "e1" }; - } - - class EmitInfantryOnSell : INotifySold, INotifyDamage - { - public void Selling(Actor self) { } - - void Emit(Actor self) - { - var info = self.Info.Traits.Get(); - var csv = self.Info.Traits.GetOrDefault(); - var valued = self.Info.Traits.GetOrDefault(); - var cost = csv != null ? csv.Value : (valued != null ? valued.Cost : 0); - - var health = self.TraitOrDefault(); - var hpFraction = (health == null) ? 1f : health.HPFraction; - var dudesValue = (int)(hpFraction * info.ValueFraction * cost); - var eligibleLocations = FootprintUtils.Tiles(self).ToList(); - var actorTypes = info.ActorTypes.Select(a => new { Name = a, Cost = Rules.Info[a].Traits.Get().Cost }).ToArray(); - - while (eligibleLocations.Count > 0 && actorTypes.Any(a => a.Cost <= dudesValue)) - { - var at = actorTypes.Where(a => a.Cost <= dudesValue).Random(self.World.SharedRandom); - var loc = eligibleLocations.Random(self.World.SharedRandom); - - eligibleLocations.Remove(loc); - dudesValue -= at.Cost; - - self.World.AddFrameEndTask(w => w.CreateActor(at.Name, new TypeDictionary - { - new LocationInit( loc ), - new OwnerInit( self.Owner ), - })); - } - } - - public void Sold(Actor self) { Emit(self); } - - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageStateChanged && e.DamageState == DamageState.Dead) - Emit(self); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class EmitInfantryOnSellInfo : TraitInfo + { + public readonly float ValueFraction = .4f; + public readonly float MinHpFraction = .3f; + + [ActorReference] + public readonly string[] ActorTypes = { "e1" }; + } + + class EmitInfantryOnSell : INotifySold, INotifyDamage + { + public void Selling(Actor self) { } + + void Emit(Actor self) + { + var info = self.Info.Traits.Get(); + var csv = self.Info.Traits.GetOrDefault(); + var valued = self.Info.Traits.GetOrDefault(); + var cost = csv != null ? csv.Value : (valued != null ? valued.Cost : 0); + + var health = self.TraitOrDefault(); + var hpFraction = (health == null) ? 1f : health.HPFraction; + var dudesValue = (int)(hpFraction * info.ValueFraction * cost); + var eligibleLocations = FootprintUtils.Tiles(self).ToList(); + var actorTypes = info.ActorTypes.Select(a => new { Name = a, Cost = Rules.Info[a].Traits.Get().Cost }).ToArray(); + + while (eligibleLocations.Count > 0 && actorTypes.Any(a => a.Cost <= dudesValue)) + { + var at = actorTypes.Where(a => a.Cost <= dudesValue).Random(self.World.SharedRandom); + var loc = eligibleLocations.Random(self.World.SharedRandom); + + eligibleLocations.Remove(loc); + dudesValue -= at.Cost; + + self.World.AddFrameEndTask(w => w.CreateActor(at.Name, new TypeDictionary + { + new LocationInit( loc ), + new OwnerInit( self.Owner ), + })); + } + } + + public void Sold(Actor self) { Emit(self); } + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageStateChanged && e.DamageState == DamageState.Dead) + Emit(self); + } + } +} diff --git a/OpenRA.Mods.RA/EngineerCapture.cs b/OpenRA.Mods.RA/EngineerCapture.cs index 02b684d618..2ed257ffd3 100644 --- a/OpenRA.Mods.RA/EngineerCapture.cs +++ b/OpenRA.Mods.RA/EngineerCapture.cs @@ -1,57 +1,57 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class EngineerCaptureInfo : TraitInfo {} - class EngineerCapture : IIssueOrder, IResolveOrder, IOrderVoice - { - public IEnumerable Orders - { - get - { - yield return new EnterOrderTargeter( "CaptureBuilding", 5, true, false, - _ => true, target => target.Info.Traits.Get().Capturable ); - } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "CaptureBuilding" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - return null; - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - return (order.OrderString == "CaptureBuilding") ? "Attack" : null; - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "CaptureBuilding") - { - self.SetTargetLine(Target.FromOrder(order), Color.Red); - - self.CancelActivity(); - self.QueueActivity(new Enter(order.TargetActor)); - self.QueueActivity(new CaptureBuilding(order.TargetActor)); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class EngineerCaptureInfo : TraitInfo {} + class EngineerCapture : IIssueOrder, IResolveOrder, IOrderVoice + { + public IEnumerable Orders + { + get + { + yield return new EnterOrderTargeter( "CaptureBuilding", 5, true, false, + _ => true, target => target.Info.Traits.Get().Capturable ); + } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "CaptureBuilding" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + return null; + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return (order.OrderString == "CaptureBuilding") ? "Attack" : null; + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "CaptureBuilding") + { + self.SetTargetLine(Target.FromOrder(order), Color.Red); + + self.CancelActivity(); + self.QueueActivity(new Enter(order.TargetActor)); + self.QueueActivity(new CaptureBuilding(order.TargetActor)); + } + } + } +} diff --git a/OpenRA.Mods.RA/EngineerRepair.cs b/OpenRA.Mods.RA/EngineerRepair.cs index 86732c3783..a2ee23443d 100644 --- a/OpenRA.Mods.RA/EngineerRepair.cs +++ b/OpenRA.Mods.RA/EngineerRepair.cs @@ -1,18 +1,18 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Orders; +#endregion + +using System.Collections.Generic; +using System.Drawing; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Orders; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -21,19 +21,19 @@ namespace OpenRA.Mods.RA class EngineerRepair : IIssueOrder, IResolveOrder, IOrderVoice { - public IEnumerable Orders - { - get { yield return new EngineerRepairOrderTargeter(); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "EngineerRepair" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - return null; - } - + public IEnumerable Orders + { + get { yield return new EngineerRepairOrderTargeter(); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "EngineerRepair" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + return null; + } + public string VoicePhraseForOrder(Actor self, Order order) { return (order.OrderString == "EngineerRepair" @@ -48,30 +48,30 @@ namespace OpenRA.Mods.RA self.SetTargetLine(Target.FromOrder(order), Color.Yellow); self.CancelActivity(); - self.QueueActivity(new Enter(order.TargetActor)); + self.QueueActivity(new Enter(order.TargetActor)); self.QueueActivity(new RepairBuilding(order.TargetActor)); } - } - - class EngineerRepairOrderTargeter : UnitTraitOrderTargeter - { - public EngineerRepairOrderTargeter() - : base( "EngineerRepair", 6, "goldwrench", false, true ) - { - } - - public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - if( !base.CanTargetActor( self, target, forceAttack, forceMove, forceQueued, ref cursor ) ) return false; + } + + class EngineerRepairOrderTargeter : UnitTraitOrderTargeter + { + public EngineerRepairOrderTargeter() + : base( "EngineerRepair", 6, "goldwrench", false, true ) + { + } + + public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + if( !base.CanTargetActor( self, target, forceAttack, forceMove, forceQueued, ref cursor ) ) return false; if (!target.HasTrait()) return false; - - IsQueued = forceQueued; - - if( target.GetDamageState() == DamageState.Undamaged ) - cursor = "goldwrench-blocked"; - return true; - } - } + + IsQueued = forceQueued; + + if( target.GetDamageState() == DamageState.Undamaged ) + cursor = "goldwrench-blocked"; + return true; + } + } } } diff --git a/OpenRA.Mods.RA/Explodes.cs b/OpenRA.Mods.RA/Explodes.cs index f6589aa735..b05c112fbc 100644 --- a/OpenRA.Mods.RA/Explodes.cs +++ b/OpenRA.Mods.RA/Explodes.cs @@ -1,48 +1,48 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class ExplodesInfo : TraitInfo - { - [WeaponReference] - public readonly string Weapon = "UnitExplode"; - [WeaponReference] - public readonly string EmptyWeapon = "UnitExplode"; - } - - class Explodes : INotifyDamage - { - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageState == DamageState.Dead) - { - var weapon = ChooseWeaponForExplosion(self); - if (weapon != null) - { - var move = self.TraitOrDefault(); - var altitude = move != null ? move.Altitude : 0; - Combat.DoExplosion(e.Attacker, weapon, self.CenterLocation, altitude); - } - } - } - - string ChooseWeaponForExplosion(Actor self) - { - var shouldExplode = self.TraitsImplementing().All(a => a.ShouldExplode(self)); - - var info = self.Info.Traits.Get(); - return shouldExplode ? info.Weapon : info.EmptyWeapon; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class ExplodesInfo : TraitInfo + { + [WeaponReference] + public readonly string Weapon = "UnitExplode"; + [WeaponReference] + public readonly string EmptyWeapon = "UnitExplode"; + } + + class Explodes : INotifyDamage + { + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageState == DamageState.Dead) + { + var weapon = ChooseWeaponForExplosion(self); + if (weapon != null) + { + var move = self.TraitOrDefault(); + var altitude = move != null ? move.Altitude : 0; + Combat.DoExplosion(e.Attacker, weapon, self.CenterLocation, altitude); + } + } + } + + string ChooseWeaponForExplosion(Actor self) + { + var shouldExplode = self.TraitsImplementing().All(a => a.ShouldExplode(self)); + + var info = self.Info.Traits.Get(); + return shouldExplode ? info.Weapon : info.EmptyWeapon; + } + } +} diff --git a/OpenRA.Mods.RA/Fake.cs b/OpenRA.Mods.RA/Fake.cs index c658e8b272..6e739315ff 100644 --- a/OpenRA.Mods.RA/Fake.cs +++ b/OpenRA.Mods.RA/Fake.cs @@ -1,22 +1,22 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class FakeInfo : TraitInfo { } - - class Fake : ITags - { - public IEnumerable GetTags() { yield return TagType.Fake; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class FakeInfo : TraitInfo { } + + class Fake : ITags + { + public IEnumerable GetTags() { yield return TagType.Fake; } + } +} diff --git a/OpenRA.Mods.RA/FreeActor.cs b/OpenRA.Mods.RA/FreeActor.cs index c1a78da3d1..3409d49dd6 100644 --- a/OpenRA.Mods.RA/FreeActor.cs +++ b/OpenRA.Mods.RA/FreeActor.cs @@ -1,46 +1,46 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class FreeActorInfo : ITraitInfo - { - [ActorReference] - public readonly string Actor = null; - public readonly string InitialActivity = null; - public readonly int2 SpawnOffset = int2.Zero; - public readonly int Facing = 0; - - public object Create( ActorInitializer init ) { return new FreeActor(init.self, this); } - } - - public class FreeActor - { - public FreeActor(Actor self, FreeActorInfo info) - { - self.World.AddFrameEndTask( - w => - { - var a = w.CreateActor(info.Actor, new TypeDictionary - { - new LocationInit( self.Location + info.SpawnOffset ), - new OwnerInit( self.Owner ), - new FacingInit( info.Facing ), - }); - - if (info.InitialActivity != null) - a.QueueActivity(Game.CreateObject(info.InitialActivity)); - }); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class FreeActorInfo : ITraitInfo + { + [ActorReference] + public readonly string Actor = null; + public readonly string InitialActivity = null; + public readonly int2 SpawnOffset = int2.Zero; + public readonly int Facing = 0; + + public object Create( ActorInitializer init ) { return new FreeActor(init.self, this); } + } + + public class FreeActor + { + public FreeActor(Actor self, FreeActorInfo info) + { + self.World.AddFrameEndTask( + w => + { + var a = w.CreateActor(info.Actor, new TypeDictionary + { + new LocationInit( self.Location + info.SpawnOffset ), + new OwnerInit( self.Owner ), + new FacingInit( info.Facing ), + }); + + if (info.InitialActivity != null) + a.QueueActivity(Game.CreateObject(info.InitialActivity)); + }); + } + } +} diff --git a/OpenRA.Mods.RA/GainsExperience.cs b/OpenRA.Mods.RA/GainsExperience.cs index e493b259a3..b7afad9050 100644 --- a/OpenRA.Mods.RA/GainsExperience.cs +++ b/OpenRA.Mods.RA/GainsExperience.cs @@ -1,101 +1,101 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.GameRules; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Effects; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class GainsExperienceInfo : ITraitInfo, ITraitPrerequisite - { - public readonly float[] CostThreshold = { 2, 4, 8, 16 }; - public readonly float[] FirepowerModifier = { 1.1f, 1.15f, 1.2f, 1.5f }; - public readonly float[] ArmorModifier = { 1.1f, 1.2f, 1.3f, 1.5f }; - public readonly decimal[] SpeedModifier = { 1.1m, 1.15m, 1.2m, 1.5m }; - public object Create(ActorInitializer init) { return new GainsExperience(init.self, this); } - } - - public class GainsExperience : IFirepowerModifier, ISpeedModifier, IDamageModifier, IRenderModifier, ISync - { - readonly Actor self; - readonly int[] Levels; - readonly GainsExperienceInfo Info; - readonly Animation RankAnim; - - public GainsExperience(Actor self, GainsExperienceInfo info) - { - this.self = self; - this.Info = info; - var cost = self.Info.Traits.Get().Cost; - Levels = Info.CostThreshold.Select(t => (int)(t * cost)).ToArray(); - RankAnim = new Animation("rank"); - RankAnim.PlayFetchIndex("rank", () => Level - 1); - } - - [Sync] - int Experience = 0; - [Sync] - int Level = 0; - - public void GiveOneLevel() - { - if (Level < Levels.Count()) - GiveExperience(Levels[Level] - Experience); - } - - public void GiveExperience(int amount) - { - Experience += amount; - - while (Level < Levels.Count() && Experience >= Levels[Level]) - { - Level++; - -// Game.Debug("{0} became Level {1}".F(self.Info.Name, Level)); - var eva = self.World.WorldActor.Info.Traits.Get(); - Sound.PlayToPlayer(self.Owner, eva.LevelUp, self.CenterLocation); - self.World.AddFrameEndTask(w => w.Add(new CrateEffect(self, "levelup", new int2(0,-24)))); - } - } - - public float GetDamageModifier(Actor attacker, WarheadInfo warhead) - { - return Level > 0 ? 1 / Info.ArmorModifier[Level - 1] : 1; - } - - public float GetFirepowerModifier() - { - return Level > 0 ? Info.FirepowerModifier[Level - 1] : 1; - } - - public decimal GetSpeedModifier() - { - return Level > 0 ? Info.SpeedModifier[Level - 1] : 1m; - } - - public IEnumerable ModifyRender(Actor self, IEnumerable rs) - { - foreach (var r in rs) - yield return r; - - if (self.Owner == self.World.LocalPlayer && Level > 0) - { - RankAnim.Tick(); // hack - var bounds = self.GetBounds(false); - yield return new Renderable(RankAnim.Image, - new float2(bounds.Right - 6, bounds.Bottom - 8), "effect", (int)self.CenterLocation.Y); - } - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.GameRules; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Effects; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class GainsExperienceInfo : ITraitInfo, ITraitPrerequisite + { + public readonly float[] CostThreshold = { 2, 4, 8, 16 }; + public readonly float[] FirepowerModifier = { 1.1f, 1.15f, 1.2f, 1.5f }; + public readonly float[] ArmorModifier = { 1.1f, 1.2f, 1.3f, 1.5f }; + public readonly decimal[] SpeedModifier = { 1.1m, 1.15m, 1.2m, 1.5m }; + public object Create(ActorInitializer init) { return new GainsExperience(init.self, this); } + } + + public class GainsExperience : IFirepowerModifier, ISpeedModifier, IDamageModifier, IRenderModifier, ISync + { + readonly Actor self; + readonly int[] Levels; + readonly GainsExperienceInfo Info; + readonly Animation RankAnim; + + public GainsExperience(Actor self, GainsExperienceInfo info) + { + this.self = self; + this.Info = info; + var cost = self.Info.Traits.Get().Cost; + Levels = Info.CostThreshold.Select(t => (int)(t * cost)).ToArray(); + RankAnim = new Animation("rank"); + RankAnim.PlayFetchIndex("rank", () => Level - 1); + } + + [Sync] + int Experience = 0; + [Sync] + int Level = 0; + + public void GiveOneLevel() + { + if (Level < Levels.Count()) + GiveExperience(Levels[Level] - Experience); + } + + public void GiveExperience(int amount) + { + Experience += amount; + + while (Level < Levels.Count() && Experience >= Levels[Level]) + { + Level++; + +// Game.Debug("{0} became Level {1}".F(self.Info.Name, Level)); + var eva = self.World.WorldActor.Info.Traits.Get(); + Sound.PlayToPlayer(self.Owner, eva.LevelUp, self.CenterLocation); + self.World.AddFrameEndTask(w => w.Add(new CrateEffect(self, "levelup", new int2(0,-24)))); + } + } + + public float GetDamageModifier(Actor attacker, WarheadInfo warhead) + { + return Level > 0 ? 1 / Info.ArmorModifier[Level - 1] : 1; + } + + public float GetFirepowerModifier() + { + return Level > 0 ? Info.FirepowerModifier[Level - 1] : 1; + } + + public decimal GetSpeedModifier() + { + return Level > 0 ? Info.SpeedModifier[Level - 1] : 1m; + } + + public IEnumerable ModifyRender(Actor self, IEnumerable rs) + { + foreach (var r in rs) + yield return r; + + if (self.Owner == self.World.LocalPlayer && Level > 0) + { + RankAnim.Tick(); // hack + var bounds = self.GetBounds(false); + yield return new Renderable(RankAnim.Image, + new float2(bounds.Right - 6, bounds.Bottom - 8), "effect", (int)self.CenterLocation.Y); + } + } + } } diff --git a/OpenRA.Mods.RA/GivesExperience.cs b/OpenRA.Mods.RA/GivesExperience.cs index 4ad7bb1b22..e6081056a5 100644 --- a/OpenRA.Mods.RA/GivesExperience.cs +++ b/OpenRA.Mods.RA/GivesExperience.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion diff --git a/OpenRA.Mods.RA/HackyAI.cs b/OpenRA.Mods.RA/HackyAI.cs index d36e1d940d..aaadc5ade1 100644 --- a/OpenRA.Mods.RA/HackyAI.cs +++ b/OpenRA.Mods.RA/HackyAI.cs @@ -1,524 +1,524 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; -using XRandom = OpenRA.Thirdparty.Random; - - -//TODO: -// [y] never give harvesters orders -// maybe move rally points when a rally point gets blocked (by units or buildings) -// Don't send attack forces to your own spawn point -// effectively clear the area around the production buildings' spawn points. -// don't spam the build unit button, only queue one unit then wait for the backoff period. -// just make the build unit action only occur once every second. -// build defense buildings - -// later: -// don't build units randomly, have a method to it. -// explore spawn points methodically -// once you find a player, attack the player instead of spawn points. - -namespace OpenRA.Mods.RA -{ - class HackyAIInfo : IBotInfo, ITraitInfo - { - [FieldLoader.Load] - public readonly string Name = "Unnamed Bot"; - - [FieldLoader.Load] - public readonly int SquadSize = 8; - - string IBotInfo.Name { get { return this.Name; } } - - [FieldLoader.LoadUsing("LoadUnits")] - public readonly Dictionary UnitsToBuild = null; - - [FieldLoader.LoadUsing("LoadBuildings")] - public readonly Dictionary BuildingFractions = null; - - static object LoadUnits(MiniYaml y) - { - Dictionary ret = new Dictionary(); - foreach (var t in y.NodesDict["UnitsToBuild"].Nodes) - ret.Add(t.Key, (float)FieldLoader.GetValue("units", typeof(float), t.Value.Value)); - return ret; - } - - static object LoadBuildings(MiniYaml y) - { - Dictionary ret = new Dictionary(); - foreach (var t in y.NodesDict["BuildingFractions"].Nodes) - ret.Add(t.Key, (float)FieldLoader.GetValue("units", typeof(float), t.Value.Value)); - return ret; - } - - public object Create(ActorInitializer init) { return new HackyAI(this); } - } - - /* a pile of hacks, which control a local player on the host. */ - - class HackyAI : ITick, IBot - { - bool enabled; - int ticks; - Player p; - PowerManager playerPower; - - int2 baseCenter; - XRandom random = new XRandom(); //we do not use the synced random number generator. - BaseBuilder[] builders; - - World world { get { return p.PlayerActor.World; } } - IBotInfo IBot.Info { get { return this.Info; } } - - readonly HackyAIInfo Info; - public HackyAI(HackyAIInfo Info) - { - this.Info = Info; - } - - enum BuildState - { - ChooseItem, - WaitForProduction, - WaitForFeedback, - } - - const int MaxBaseDistance = 15; - - public static void BotDebug(string s, params object[] args) - { - if (Game.Settings.Debug.BotDebug) - Game.Debug(s, args); - } - - /* called by the host's player creation code */ - public void Activate(Player p) - { - this.p = p; - enabled = true; - playerPower = p.PlayerActor.Trait(); - builders = new BaseBuilder[] { - new BaseBuilder( this, "Building", ChooseBuildingToBuild ), - new BaseBuilder( this, "Defense", ChooseDefenseToBuild ) }; - } - - int GetPowerProvidedBy(ActorInfo building) - { - var bi = building.Traits.GetOrDefault(); - if (bi == null) return 0; - return bi.Power; - } - - ActorInfo ChooseRandomUnitToBuild(ProductionQueue queue) - { - var buildableThings = queue.BuildableItems(); - if (buildableThings.Count() == 0) return null; - return buildableThings.ElementAtOrDefault(random.Next(buildableThings.Count())); - } - - bool HasAdequatePower() - { - /* note: CNC `fact` provides a small amount of power. don't get jammed because of that. */ - return playerPower.PowerProvided > 50 && - playerPower.PowerProvided > playerPower.PowerDrained * 1.2; - } - - ActorInfo ChooseBuildingToBuild(ProductionQueue queue) - { - var buildableThings = queue.BuildableItems(); - - if (!HasAdequatePower()) /* try to maintain 20% excess power */ - { - /* find the best thing we can build which produces power */ - return buildableThings.Where(a => GetPowerProvidedBy(a) > 0) - .OrderByDescending(a => GetPowerProvidedBy(a)).FirstOrDefault(); - } - - var myBuildings = p.World.Queries.OwnedBy[p].WithTrait() - .Select(a => a.Actor.Info.Name).ToArray(); - - - foreach (var frac in Info.BuildingFractions) - if (buildableThings.Any(b => b.Name == frac.Key)) - if (myBuildings.Count(a => a == frac.Key) < frac.Value * myBuildings.Length) - return Rules.Info[frac.Key]; - - return null; - } - - ActorInfo ChooseDefenseToBuild(ProductionQueue queue) - { - if (!HasAdequatePower()) - return null; - - var buildableThings = queue.BuildableItems(); - - var myBuildings = p.World.Queries.OwnedBy[p].WithTrait() - .Select(a => a.Actor.Info.Name).ToArray(); - - foreach (var frac in Info.BuildingFractions) - if (buildableThings.Any(b => b.Name == frac.Key)) - if (myBuildings.Count(a => a == frac.Key) < frac.Value * myBuildings.Length) - return Rules.Info[frac.Key]; - - return null; - } - - IEnumerable Neighbours(int2 c) - { - /* only return 4-neighbors for now, maybe add 8s later. */ - yield return c; - yield return new int2(c.X - 1, c.Y); - yield return new int2(c.X + 1, c.Y); - yield return new int2(c.X, c.Y - 1); - yield return new int2(c.X, c.Y + 1); - } - - IEnumerable ExpandFootprint(IEnumerable cells) - { - var result = new Dictionary(); - foreach (var c in cells.SelectMany(c => Neighbours(c))) - result[c] = true; - return result.Keys; - } - - bool NoBuildingsUnder(IEnumerable cells) - { - var bi = world.WorldActor.Trait(); - return cells.All(c => bi.GetBuildingAt(c) == null); - } - - int2? ChooseBuildLocation(ProductionItem item) - { - var bi = Rules.Info[item.Item].Traits.Get(); - - for (var k = 0; k < MaxBaseDistance; k++) - foreach (var t in world.FindTilesInCircle(baseCenter, k)) - if (world.CanPlaceBuilding(item.Item, bi, t, null)) - if (bi.IsCloseEnoughToBase(world, p, item.Item, t)) - if (NoBuildingsUnder(ExpandFootprint( - FootprintUtils.Tiles( item.Item, bi, t )))) - return t; - - return null; // i don't know where to put it. - } - - const int feedbackTime = 30; // ticks; = a bit over 1s. must be >= netlag. - - public void Tick(Actor self) - { - if (!enabled) - return; - - ticks++; - - if (ticks == 10) - { - DeployMcv(self); - } - - if (ticks % feedbackTime == 0) - { - //about once every second, perform unintelligent cleanup tasks. - //e.g. ClearAreaAroundSpawnPoints(); - //e.g. start repairing damaged buildings. - BuildRandom("Vehicle"); - BuildRandom("Infantry"); - BuildRandom("Plane"); - } - - AssignRolesToIdleUnits(self); - SetRallyPointsForNewProductionBuildings(self); - - foreach (var b in builders) - b.Tick(); - } - - //hacks etc sigh mess. - //A bunch of hardcoded lists to keep track of which units are doing what. - List unitsHangingAroundTheBase = new List(); - List attackForce = new List(); - - //Units that the ai already knows about. Any unit not on this list needs to be given a role. - List activeUnits = new List(); - - //This is purely to identify production buildings that don't have a rally point set. - List activeProductionBuildings = new List(); - - bool IsHumanPlayer(Player p) { return !p.IsBot && !p.NonCombatant; } - - bool HasHumanPlayers() - { - return p.World.players.Any(a => !a.Value.IsBot && !a.Value.NonCombatant); - } - - int2? ChooseEnemyTarget() - { - // Criteria for picking an enemy: - // 1. not ourself. - // 2. human. - // 3. not dead. - - var possibleTargets = world.WorldActor.Trait().Start - .Where(kv => kv.Key != p && (!HasHumanPlayers() || IsHumanPlayer(kv.Key)) - && p.WinState == WinState.Undefined) - .Select(kv => kv.Value); - - return possibleTargets.Any() ? possibleTargets.Random(random) : (int2?)null; - } - - void AssignRolesToIdleUnits(Actor self) - { - //HACK: trim these lists -- we really shouldn't be hanging onto all this state - //when it's invalidated so easily, but that's Matthew/Alli's problem. - activeUnits.RemoveAll(a => a.Destroyed); - unitsHangingAroundTheBase.RemoveAll(a => a.Destroyed); - attackForce.RemoveAll(a => a.Destroyed); - activeProductionBuildings.RemoveAll(a => a.Destroyed); - - // don't select harvesters. - var newUnits = self.World.Queries.OwnedBy[p] - .Where(a => a.HasTrait() && a.Info != Rules.Info["harv"] - && !activeUnits.Contains(a)).ToArray(); - - foreach (var a in newUnits) - { - BotDebug("AI: Found a newly built unit"); - unitsHangingAroundTheBase.Add(a); - activeUnits.Add(a); - } - - /* Create an attack force when we have enough units around our base. */ - // (don't bother leaving any behind for defense.) - if (unitsHangingAroundTheBase.Count >= Info.SquadSize) - { - BotDebug("Launch an attack."); - - var attackTarget = ChooseEnemyTarget(); - if (attackTarget == null) - return; - - foreach (var a in unitsHangingAroundTheBase) - if (TryToAttackMove(a, attackTarget.Value)) - attackForce.Add(a); - - unitsHangingAroundTheBase.Clear(); - } - } - - void SetRallyPointsForNewProductionBuildings(Actor self) - { - var newProdBuildings = self.World.Queries.OwnedBy[p] - .Where(a => (a.TraitOrDefault() != null - && !activeProductionBuildings.Contains(a) - )).ToArray(); - - foreach (var a in newProdBuildings) - { - activeProductionBuildings.Add(a); - int2 newRallyPoint = ChooseRallyLocationNear(a.Location); - newRallyPoint.X += 4; - newRallyPoint.Y += 4; - world.IssueOrder(new Order("SetRallyPoint", a, false) { TargetLocation = newRallyPoint }); - } - } - - //won't work for shipyards... - int2 ChooseRallyLocationNear(int2 startPos) - { - Random r = new Random(); - foreach (var t in world.FindTilesInCircle(startPos, 8)) - if (world.IsCellBuildable(t, false) && t != startPos && r.Next(64) == 0) - return t; - - return startPos; // i don't know where to put it. - } - - int2? ChooseDestinationNear(Actor a, int2 desiredMoveTarget) - { - if (!a.HasTrait()) - return null; - - int2 xy; - int loopCount = 0; //avoid infinite loops. - int range = 2; - do - { - //loop until we find a valid move location - xy = new int2(desiredMoveTarget.X + random.Next(-range, range), desiredMoveTarget.Y + random.Next(-range, range)); - loopCount++; - range = Math.Max(range, loopCount / 2); - if (loopCount > 10) return null; - } while (!a.Trait().CanEnterCell(xy) && xy != a.Location); - - return xy; - } - - //try very hard to find a valid move destination near the target. - //(Don't accept a move onto the subject's current position. maybe this is already not allowed? ) - bool TryToMove(Actor a, int2 desiredMoveTarget) - { - var xy = ChooseDestinationNear(a, desiredMoveTarget); - if (xy == null) - return false; - world.IssueOrder(new Order("Move", a, false) { TargetLocation = xy.Value }); - return true; - } - - //try very hard to find a valid move destination near the target. - //(Don't accept a move onto the subject's current position. maybe this is already not allowed? ) - bool TryToAttackMove(Actor a, int2 desiredMoveTarget) - { - var xy = ChooseDestinationNear(a, desiredMoveTarget); - if (xy == null) - return false; - world.IssueOrder(new Order("AttackMove", a, false) { TargetLocation = xy.Value }); - return true; - } - - void DeployMcv(Actor self) - { - /* find our mcv and deploy it */ - var mcv = self.World.Queries.OwnedBy[p] - .FirstOrDefault(a => a.Info == Rules.Info["mcv"]); - - if (mcv != null) - { - baseCenter = mcv.Location; - world.IssueOrder(new Order("DeployTransform", mcv, false)); - } - else - BotDebug("AI: Can't find the MCV."); - } - - //Build a random unit of the given type. Not going to be needed once there is actual AI... - private void BuildRandom(string category) - { - // Pick a free queue - var queue = world.Queries.WithTrait() - .Where(a => a.Actor.Owner == p && - a.Trait.Info.Type == category && - a.Trait.CurrentItem() == null) - .Select(a => a.Trait) - .FirstOrDefault(); - - if (queue == null) - return; - - var unit = ChooseRandomUnitToBuild(queue); - Boolean found = false; - if (unit != null) - { - foreach (var un in Info.UnitsToBuild) - { - if (un.Key == unit.Name) - { - found = true; - break; - } - } - - if (found == true) - { - world.IssueOrder(Order.StartProduction(queue.self, unit.Name, 1)); - } - } - } - - class BaseBuilder - { - BuildState state = BuildState.WaitForFeedback; - string category; - HackyAI ai; - int lastThinkTick; - Func chooseItem; - - public BaseBuilder(HackyAI ai, string category, Func chooseItem) - { - this.ai = ai; - this.category = category; - this.chooseItem = chooseItem; - } - - public void Tick() - { - // Pick a free queue - var queue = ai.world.Queries.WithTrait() - .Where(a => a.Actor.Owner == ai.p && a.Trait.Info.Type == category) - .Select(a => a.Trait) - .FirstOrDefault(); - - if (queue == null) - return; - - var currentBuilding = queue.CurrentItem(); - switch (state) - { - case BuildState.ChooseItem: - { - var item = chooseItem(queue); - if (item == null) - { - state = BuildState.WaitForFeedback; - lastThinkTick = ai.ticks; - } - else - { - BotDebug("AI: Starting production of {0}".F(item.Name)); - state = BuildState.WaitForProduction; - ai.world.IssueOrder(Order.StartProduction(queue.self, item.Name, 1)); - } - } - break; - - case BuildState.WaitForProduction: - if (currentBuilding == null) return; /* let it happen.. */ - - else if (currentBuilding.Paused) - ai.world.IssueOrder(Order.PauseProduction(queue.self, currentBuilding.Item, false)); - else if (currentBuilding.Done) - { - state = BuildState.WaitForFeedback; - lastThinkTick = ai.ticks; - - /* place the building */ - var location = ai.ChooseBuildLocation(currentBuilding); - if (location == null) - { - BotDebug("AI: Nowhere to place {0}".F(currentBuilding.Item)); - ai.world.IssueOrder(Order.CancelProduction(queue.self, currentBuilding.Item, 1)); - } - else - { - ai.world.IssueOrder(new Order("PlaceBuilding", ai.p.PlayerActor, false) - { - TargetLocation = location.Value, - TargetString = currentBuilding.Item - }); - } - } - break; - - case BuildState.WaitForFeedback: - if (ai.ticks - lastThinkTick > feedbackTime) - state = BuildState.ChooseItem; - break; - } - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; +using XRandom = OpenRA.Thirdparty.Random; + + +//TODO: +// [y] never give harvesters orders +// maybe move rally points when a rally point gets blocked (by units or buildings) +// Don't send attack forces to your own spawn point +// effectively clear the area around the production buildings' spawn points. +// don't spam the build unit button, only queue one unit then wait for the backoff period. +// just make the build unit action only occur once every second. +// build defense buildings + +// later: +// don't build units randomly, have a method to it. +// explore spawn points methodically +// once you find a player, attack the player instead of spawn points. + +namespace OpenRA.Mods.RA +{ + class HackyAIInfo : IBotInfo, ITraitInfo + { + [FieldLoader.Load] + public readonly string Name = "Unnamed Bot"; + + [FieldLoader.Load] + public readonly int SquadSize = 8; + + string IBotInfo.Name { get { return this.Name; } } + + [FieldLoader.LoadUsing("LoadUnits")] + public readonly Dictionary UnitsToBuild = null; + + [FieldLoader.LoadUsing("LoadBuildings")] + public readonly Dictionary BuildingFractions = null; + + static object LoadUnits(MiniYaml y) + { + Dictionary ret = new Dictionary(); + foreach (var t in y.NodesDict["UnitsToBuild"].Nodes) + ret.Add(t.Key, (float)FieldLoader.GetValue("units", typeof(float), t.Value.Value)); + return ret; + } + + static object LoadBuildings(MiniYaml y) + { + Dictionary ret = new Dictionary(); + foreach (var t in y.NodesDict["BuildingFractions"].Nodes) + ret.Add(t.Key, (float)FieldLoader.GetValue("units", typeof(float), t.Value.Value)); + return ret; + } + + public object Create(ActorInitializer init) { return new HackyAI(this); } + } + + /* a pile of hacks, which control a local player on the host. */ + + class HackyAI : ITick, IBot + { + bool enabled; + int ticks; + Player p; + PowerManager playerPower; + + int2 baseCenter; + XRandom random = new XRandom(); //we do not use the synced random number generator. + BaseBuilder[] builders; + + World world { get { return p.PlayerActor.World; } } + IBotInfo IBot.Info { get { return this.Info; } } + + readonly HackyAIInfo Info; + public HackyAI(HackyAIInfo Info) + { + this.Info = Info; + } + + enum BuildState + { + ChooseItem, + WaitForProduction, + WaitForFeedback, + } + + const int MaxBaseDistance = 15; + + public static void BotDebug(string s, params object[] args) + { + if (Game.Settings.Debug.BotDebug) + Game.Debug(s, args); + } + + /* called by the host's player creation code */ + public void Activate(Player p) + { + this.p = p; + enabled = true; + playerPower = p.PlayerActor.Trait(); + builders = new BaseBuilder[] { + new BaseBuilder( this, "Building", ChooseBuildingToBuild ), + new BaseBuilder( this, "Defense", ChooseDefenseToBuild ) }; + } + + int GetPowerProvidedBy(ActorInfo building) + { + var bi = building.Traits.GetOrDefault(); + if (bi == null) return 0; + return bi.Power; + } + + ActorInfo ChooseRandomUnitToBuild(ProductionQueue queue) + { + var buildableThings = queue.BuildableItems(); + if (buildableThings.Count() == 0) return null; + return buildableThings.ElementAtOrDefault(random.Next(buildableThings.Count())); + } + + bool HasAdequatePower() + { + /* note: CNC `fact` provides a small amount of power. don't get jammed because of that. */ + return playerPower.PowerProvided > 50 && + playerPower.PowerProvided > playerPower.PowerDrained * 1.2; + } + + ActorInfo ChooseBuildingToBuild(ProductionQueue queue) + { + var buildableThings = queue.BuildableItems(); + + if (!HasAdequatePower()) /* try to maintain 20% excess power */ + { + /* find the best thing we can build which produces power */ + return buildableThings.Where(a => GetPowerProvidedBy(a) > 0) + .OrderByDescending(a => GetPowerProvidedBy(a)).FirstOrDefault(); + } + + var myBuildings = p.World.Queries.OwnedBy[p].WithTrait() + .Select(a => a.Actor.Info.Name).ToArray(); + + + foreach (var frac in Info.BuildingFractions) + if (buildableThings.Any(b => b.Name == frac.Key)) + if (myBuildings.Count(a => a == frac.Key) < frac.Value * myBuildings.Length) + return Rules.Info[frac.Key]; + + return null; + } + + ActorInfo ChooseDefenseToBuild(ProductionQueue queue) + { + if (!HasAdequatePower()) + return null; + + var buildableThings = queue.BuildableItems(); + + var myBuildings = p.World.Queries.OwnedBy[p].WithTrait() + .Select(a => a.Actor.Info.Name).ToArray(); + + foreach (var frac in Info.BuildingFractions) + if (buildableThings.Any(b => b.Name == frac.Key)) + if (myBuildings.Count(a => a == frac.Key) < frac.Value * myBuildings.Length) + return Rules.Info[frac.Key]; + + return null; + } + + IEnumerable Neighbours(int2 c) + { + /* only return 4-neighbors for now, maybe add 8s later. */ + yield return c; + yield return new int2(c.X - 1, c.Y); + yield return new int2(c.X + 1, c.Y); + yield return new int2(c.X, c.Y - 1); + yield return new int2(c.X, c.Y + 1); + } + + IEnumerable ExpandFootprint(IEnumerable cells) + { + var result = new Dictionary(); + foreach (var c in cells.SelectMany(c => Neighbours(c))) + result[c] = true; + return result.Keys; + } + + bool NoBuildingsUnder(IEnumerable cells) + { + var bi = world.WorldActor.Trait(); + return cells.All(c => bi.GetBuildingAt(c) == null); + } + + int2? ChooseBuildLocation(ProductionItem item) + { + var bi = Rules.Info[item.Item].Traits.Get(); + + for (var k = 0; k < MaxBaseDistance; k++) + foreach (var t in world.FindTilesInCircle(baseCenter, k)) + if (world.CanPlaceBuilding(item.Item, bi, t, null)) + if (bi.IsCloseEnoughToBase(world, p, item.Item, t)) + if (NoBuildingsUnder(ExpandFootprint( + FootprintUtils.Tiles( item.Item, bi, t )))) + return t; + + return null; // i don't know where to put it. + } + + const int feedbackTime = 30; // ticks; = a bit over 1s. must be >= netlag. + + public void Tick(Actor self) + { + if (!enabled) + return; + + ticks++; + + if (ticks == 10) + { + DeployMcv(self); + } + + if (ticks % feedbackTime == 0) + { + //about once every second, perform unintelligent cleanup tasks. + //e.g. ClearAreaAroundSpawnPoints(); + //e.g. start repairing damaged buildings. + BuildRandom("Vehicle"); + BuildRandom("Infantry"); + BuildRandom("Plane"); + } + + AssignRolesToIdleUnits(self); + SetRallyPointsForNewProductionBuildings(self); + + foreach (var b in builders) + b.Tick(); + } + + //hacks etc sigh mess. + //A bunch of hardcoded lists to keep track of which units are doing what. + List unitsHangingAroundTheBase = new List(); + List attackForce = new List(); + + //Units that the ai already knows about. Any unit not on this list needs to be given a role. + List activeUnits = new List(); + + //This is purely to identify production buildings that don't have a rally point set. + List activeProductionBuildings = new List(); + + bool IsHumanPlayer(Player p) { return !p.IsBot && !p.NonCombatant; } + + bool HasHumanPlayers() + { + return p.World.players.Any(a => !a.Value.IsBot && !a.Value.NonCombatant); + } + + int2? ChooseEnemyTarget() + { + // Criteria for picking an enemy: + // 1. not ourself. + // 2. human. + // 3. not dead. + + var possibleTargets = world.WorldActor.Trait().Start + .Where(kv => kv.Key != p && (!HasHumanPlayers() || IsHumanPlayer(kv.Key)) + && p.WinState == WinState.Undefined) + .Select(kv => kv.Value); + + return possibleTargets.Any() ? possibleTargets.Random(random) : (int2?)null; + } + + void AssignRolesToIdleUnits(Actor self) + { + //HACK: trim these lists -- we really shouldn't be hanging onto all this state + //when it's invalidated so easily, but that's Matthew/Alli's problem. + activeUnits.RemoveAll(a => a.Destroyed); + unitsHangingAroundTheBase.RemoveAll(a => a.Destroyed); + attackForce.RemoveAll(a => a.Destroyed); + activeProductionBuildings.RemoveAll(a => a.Destroyed); + + // don't select harvesters. + var newUnits = self.World.Queries.OwnedBy[p] + .Where(a => a.HasTrait() && a.Info != Rules.Info["harv"] + && !activeUnits.Contains(a)).ToArray(); + + foreach (var a in newUnits) + { + BotDebug("AI: Found a newly built unit"); + unitsHangingAroundTheBase.Add(a); + activeUnits.Add(a); + } + + /* Create an attack force when we have enough units around our base. */ + // (don't bother leaving any behind for defense.) + if (unitsHangingAroundTheBase.Count >= Info.SquadSize) + { + BotDebug("Launch an attack."); + + var attackTarget = ChooseEnemyTarget(); + if (attackTarget == null) + return; + + foreach (var a in unitsHangingAroundTheBase) + if (TryToAttackMove(a, attackTarget.Value)) + attackForce.Add(a); + + unitsHangingAroundTheBase.Clear(); + } + } + + void SetRallyPointsForNewProductionBuildings(Actor self) + { + var newProdBuildings = self.World.Queries.OwnedBy[p] + .Where(a => (a.TraitOrDefault() != null + && !activeProductionBuildings.Contains(a) + )).ToArray(); + + foreach (var a in newProdBuildings) + { + activeProductionBuildings.Add(a); + int2 newRallyPoint = ChooseRallyLocationNear(a.Location); + newRallyPoint.X += 4; + newRallyPoint.Y += 4; + world.IssueOrder(new Order("SetRallyPoint", a, false) { TargetLocation = newRallyPoint }); + } + } + + //won't work for shipyards... + int2 ChooseRallyLocationNear(int2 startPos) + { + Random r = new Random(); + foreach (var t in world.FindTilesInCircle(startPos, 8)) + if (world.IsCellBuildable(t, false) && t != startPos && r.Next(64) == 0) + return t; + + return startPos; // i don't know where to put it. + } + + int2? ChooseDestinationNear(Actor a, int2 desiredMoveTarget) + { + if (!a.HasTrait()) + return null; + + int2 xy; + int loopCount = 0; //avoid infinite loops. + int range = 2; + do + { + //loop until we find a valid move location + xy = new int2(desiredMoveTarget.X + random.Next(-range, range), desiredMoveTarget.Y + random.Next(-range, range)); + loopCount++; + range = Math.Max(range, loopCount / 2); + if (loopCount > 10) return null; + } while (!a.Trait().CanEnterCell(xy) && xy != a.Location); + + return xy; + } + + //try very hard to find a valid move destination near the target. + //(Don't accept a move onto the subject's current position. maybe this is already not allowed? ) + bool TryToMove(Actor a, int2 desiredMoveTarget) + { + var xy = ChooseDestinationNear(a, desiredMoveTarget); + if (xy == null) + return false; + world.IssueOrder(new Order("Move", a, false) { TargetLocation = xy.Value }); + return true; + } + + //try very hard to find a valid move destination near the target. + //(Don't accept a move onto the subject's current position. maybe this is already not allowed? ) + bool TryToAttackMove(Actor a, int2 desiredMoveTarget) + { + var xy = ChooseDestinationNear(a, desiredMoveTarget); + if (xy == null) + return false; + world.IssueOrder(new Order("AttackMove", a, false) { TargetLocation = xy.Value }); + return true; + } + + void DeployMcv(Actor self) + { + /* find our mcv and deploy it */ + var mcv = self.World.Queries.OwnedBy[p] + .FirstOrDefault(a => a.Info == Rules.Info["mcv"]); + + if (mcv != null) + { + baseCenter = mcv.Location; + world.IssueOrder(new Order("DeployTransform", mcv, false)); + } + else + BotDebug("AI: Can't find the MCV."); + } + + //Build a random unit of the given type. Not going to be needed once there is actual AI... + private void BuildRandom(string category) + { + // Pick a free queue + var queue = world.Queries.WithTrait() + .Where(a => a.Actor.Owner == p && + a.Trait.Info.Type == category && + a.Trait.CurrentItem() == null) + .Select(a => a.Trait) + .FirstOrDefault(); + + if (queue == null) + return; + + var unit = ChooseRandomUnitToBuild(queue); + Boolean found = false; + if (unit != null) + { + foreach (var un in Info.UnitsToBuild) + { + if (un.Key == unit.Name) + { + found = true; + break; + } + } + + if (found == true) + { + world.IssueOrder(Order.StartProduction(queue.self, unit.Name, 1)); + } + } + } + + class BaseBuilder + { + BuildState state = BuildState.WaitForFeedback; + string category; + HackyAI ai; + int lastThinkTick; + Func chooseItem; + + public BaseBuilder(HackyAI ai, string category, Func chooseItem) + { + this.ai = ai; + this.category = category; + this.chooseItem = chooseItem; + } + + public void Tick() + { + // Pick a free queue + var queue = ai.world.Queries.WithTrait() + .Where(a => a.Actor.Owner == ai.p && a.Trait.Info.Type == category) + .Select(a => a.Trait) + .FirstOrDefault(); + + if (queue == null) + return; + + var currentBuilding = queue.CurrentItem(); + switch (state) + { + case BuildState.ChooseItem: + { + var item = chooseItem(queue); + if (item == null) + { + state = BuildState.WaitForFeedback; + lastThinkTick = ai.ticks; + } + else + { + BotDebug("AI: Starting production of {0}".F(item.Name)); + state = BuildState.WaitForProduction; + ai.world.IssueOrder(Order.StartProduction(queue.self, item.Name, 1)); + } + } + break; + + case BuildState.WaitForProduction: + if (currentBuilding == null) return; /* let it happen.. */ + + else if (currentBuilding.Paused) + ai.world.IssueOrder(Order.PauseProduction(queue.self, currentBuilding.Item, false)); + else if (currentBuilding.Done) + { + state = BuildState.WaitForFeedback; + lastThinkTick = ai.ticks; + + /* place the building */ + var location = ai.ChooseBuildLocation(currentBuilding); + if (location == null) + { + BotDebug("AI: Nowhere to place {0}".F(currentBuilding.Item)); + ai.world.IssueOrder(Order.CancelProduction(queue.self, currentBuilding.Item, 1)); + } + else + { + ai.world.IssueOrder(new Order("PlaceBuilding", ai.p.PlayerActor, false) + { + TargetLocation = location.Value, + TargetString = currentBuilding.Item + }); + } + } + break; + + case BuildState.WaitForFeedback: + if (ai.ticks - lastThinkTick > feedbackTime) + state = BuildState.ChooseItem; + break; + } + } + } + } +} diff --git a/OpenRA.Mods.RA/Harvester.cs b/OpenRA.Mods.RA/Harvester.cs index 1e8be34a1c..41b52caef3 100644 --- a/OpenRA.Mods.RA/Harvester.cs +++ b/OpenRA.Mods.RA/Harvester.cs @@ -1,36 +1,36 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Move; -using OpenRA.Mods.RA.Orders; +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Move; +using OpenRA.Mods.RA.Orders; using OpenRA.Traits; namespace OpenRA.Mods.RA { public class HarvesterInfo : ITraitInfo { - public readonly int Capacity = 28; + public readonly int Capacity = 28; public readonly int UnloadTicksPerBale = 4; public readonly int PipCount = 7; - public readonly string[] Resources = { }; + public readonly string[] Resources = { }; public readonly decimal FullyLoadedSpeed = .85m; public object Create(ActorInitializer init) { return new Harvester(init.self, this); } } public class Harvester : IIssueOrder, IResolveOrder, IPips, - IRenderModifier, IExplodeModifier, IOrderVoice, + IRenderModifier, IExplodeModifier, IOrderVoice, ISpeedModifier, ISync { Dictionary contents = new Dictionary(); @@ -43,12 +43,12 @@ namespace OpenRA.Mods.RA [Sync] public int2 LastHarvestedCell = int2.Zero; - - [Sync] - public int ContentValue { get { return contents.Sum(c => c.Key.ValuePerUnit*c.Value); } } - - [Sync] - int currentUnloadTicks; + + [Sync] + public int ContentValue { get { return contents.Sum(c => c.Key.ValuePerUnit*c.Value); } } + + [Sync] + int currentUnloadTicks; readonly HarvesterInfo Info; public Harvester(Actor self, HarvesterInfo info) @@ -67,10 +67,10 @@ namespace OpenRA.Mods.RA var refs = self.World.Queries.OwnedBy[self.Owner] .Where(x => x != ignore && x.HasTrait()) .ToList(); - var mi = self.Info.Traits.Get(); - var path = self.World.WorldActor.Trait().FindPath( - PathSearch.FromPoints(self.World, mi, - refs.Select(r => r.Location + r.Trait().DeliverOffset), + var mi = self.Info.Traits.Get(); + var path = self.World.WorldActor.Trait().FindPath( + PathSearch.FromPoints(self.World, mi, + refs.Select(r => r.Location + r.Trait().DeliverOffset), self.Location, false)); path.Reverse(); if (path.Count != 0) @@ -87,66 +87,66 @@ namespace OpenRA.Mods.RA if (!contents.ContainsKey(type.info)) contents[type.info] = 1; else contents[type.info]++; } - - // Returns true when unloading is complete - public bool TickUnload(Actor self, Actor proc) - { - if (!proc.IsInWorld) - return false; // fail to deliver if there is no proc. - - // Wait until the next bale is ready - if (--currentUnloadTicks > 0) - return false; - - if (contents.Keys.Count > 0) - { - var type = contents.First().Key; - var iao = proc.Trait(); - if (!iao.CanGiveOre(type.ValuePerUnit)) - return false; - - iao.GiveOre(type.ValuePerUnit); - if (--contents[type] == 0) - contents.Remove(type); - - currentUnloadTicks = Info.UnloadTicksPerBale; - } - - return contents.Count == 0; - } - - public IEnumerable Orders - { - get - { - yield return new EnterOrderTargeter( "Deliver", 5, false, true, _ => true, _ => !IsEmpty ); - yield return new HarvestOrderTargeter(); - } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "Deliver" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - if( order.OrderID == "Harvest" ) - return new Order(order.OrderID, self, queued) { TargetLocation = Util.CellContaining(target.CenterLocation) }; - - return null; - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - return (order.OrderString == "Harvest" || (order.OrderString == "Deliver" && !IsEmpty)) ? "Move" : null; + + // Returns true when unloading is complete + public bool TickUnload(Actor self, Actor proc) + { + if (!proc.IsInWorld) + return false; // fail to deliver if there is no proc. + + // Wait until the next bale is ready + if (--currentUnloadTicks > 0) + return false; + + if (contents.Keys.Count > 0) + { + var type = contents.First().Key; + var iao = proc.Trait(); + if (!iao.CanGiveOre(type.ValuePerUnit)) + return false; + + iao.GiveOre(type.ValuePerUnit); + if (--contents[type] == 0) + contents.Remove(type); + + currentUnloadTicks = Info.UnloadTicksPerBale; + } + + return contents.Count == 0; + } + + public IEnumerable Orders + { + get + { + yield return new EnterOrderTargeter( "Deliver", 5, false, true, _ => true, _ => !IsEmpty ); + yield return new HarvestOrderTargeter(); + } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "Deliver" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + if( order.OrderID == "Harvest" ) + return new Order(order.OrderID, self, queued) { TargetLocation = Util.CellContaining(target.CenterLocation) }; + + return null; + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return (order.OrderString == "Harvest" || (order.OrderString == "Deliver" && !IsEmpty)) ? "Move" : null; } public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "Harvest") { - self.SetTargetLine(Target.FromOrder(order), Color.Red); - - var mobile = self.Trait(); + self.SetTargetLine(Target.FromOrder(order), Color.Red); + + var mobile = self.Trait(); self.CancelActivity(); self.QueueActivity(mobile.MoveTo(order.TargetLocation, 0)); self.QueueActivity(new Harvest()); @@ -155,12 +155,12 @@ namespace OpenRA.Mods.RA { if (order.TargetActor != LinkedProc) LinkedProc = order.TargetActor; - - if (IsEmpty) - return; - - self.SetTargetLine(Target.FromOrder(order), Color.Green); - + + if (IsEmpty) + return; + + self.SetTargetLine(Target.FromOrder(order), Color.Green); + self.CancelActivity(); self.QueueActivity(new DeliverResources()); } @@ -177,67 +177,67 @@ namespace OpenRA.Mods.RA return; ChooseNewProc(self, proc); - } - - PipType GetPipAt(int i) - { - var n = i * Info.Capacity / Info.PipCount; - - foreach (var rt in contents) - if (n < rt.Value) - return rt.Key.PipColor; - else - n -= rt.Value; - - return PipType.Transparent; + } + + PipType GetPipAt(int i) + { + var n = i * Info.Capacity / Info.PipCount; + + foreach (var rt in contents) + if (n < rt.Value) + return rt.Key.PipColor; + else + n -= rt.Value; + + return PipType.Transparent; } public IEnumerable GetPips(Actor self) { - int numPips = Info.PipCount; - - for (int i = 0; i < numPips; i++) + int numPips = Info.PipCount; + + for (int i = 0; i < numPips; i++) yield return GetPipAt(i); } public IEnumerable ModifyRender(Actor self, IEnumerable r) { return Visible ? r : new Renderable[] { }; - } - - public bool ShouldExplode(Actor self) { return !IsEmpty; } - - public decimal GetSpeedModifier() - { - return 1m - ( 1m - Info.FullyLoadedSpeed ) * contents.Values.Sum() / Info.Capacity; - } - - class HarvestOrderTargeter : IOrderTargeter - { - public string OrderID { get { return "Harvest";}} - public int OrderPriority { get { return 10; } } - - public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - return false; - } - - public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - // Don't leak info about resources under the shroud - if (!self.World.LocalShroud.IsExplored(location)) return false; - - var res = self.World.WorldActor.Trait().GetResource( location ); - var info = self.Info.Traits.Get(); - - if( res == null ) return false; - if( !info.Resources.Contains( res.info.Name ) ) return false; - cursor = "attackmove"; - IsQueued = forceQueued; - - return true; - } - public bool IsQueued { get; protected set; } - } + } + + public bool ShouldExplode(Actor self) { return !IsEmpty; } + + public decimal GetSpeedModifier() + { + return 1m - ( 1m - Info.FullyLoadedSpeed ) * contents.Values.Sum() / Info.Capacity; + } + + class HarvestOrderTargeter : IOrderTargeter + { + public string OrderID { get { return "Harvest";}} + public int OrderPriority { get { return 10; } } + + public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + return false; + } + + public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + // Don't leak info about resources under the shroud + if (!self.World.LocalShroud.IsExplored(location)) return false; + + var res = self.World.WorldActor.Trait().GetResource( location ); + var info = self.Info.Traits.Get(); + + if( res == null ) return false; + if( !info.Resources.Contains( res.info.Name ) ) return false; + cursor = "attackmove"; + IsQueued = forceQueued; + + return true; + } + public bool IsQueued { get; protected set; } + } } } diff --git a/OpenRA.Mods.RA/Husk.cs b/OpenRA.Mods.RA/Husk.cs index a44d1acff1..8801be4920 100644 --- a/OpenRA.Mods.RA/Husk.cs +++ b/OpenRA.Mods.RA/Husk.cs @@ -1,43 +1,43 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Traits; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.RA -{ - class HuskInfo : ITraitInfo - { - public object Create( ActorInitializer init ) { return new Husk( init ); } - } - - class Husk : IOccupySpace, IFacing, ISync - { - [Sync] - int2 location; - - [Sync] - public int Facing { get; set; } - public int ROT { get { return 0; } } - public int InitialFacing { get { return 128; } } - - public Husk(ActorInitializer init) - { - this.location = init.Get(); - this.Facing = init.Contains() ? init.Get() : 128; - } - - public int2 TopLeft { get { return location; } } - - public IEnumerable> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); } - public int2 PxPosition { get { return Util.CenterOfCell( location ); } } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Traits; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.RA +{ + class HuskInfo : ITraitInfo + { + public object Create( ActorInitializer init ) { return new Husk( init ); } + } + + class Husk : IOccupySpace, IFacing, ISync + { + [Sync] + int2 location; + + [Sync] + public int Facing { get; set; } + public int ROT { get { return 0; } } + public int InitialFacing { get { return 128; } } + + public Husk(ActorInitializer init) + { + this.location = init.Get(); + this.Facing = init.Contains() ? init.Get() : 128; + } + + public int2 TopLeft { get { return location; } } + + public IEnumerable> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); } + public int2 PxPosition { get { return Util.CenterOfCell( location ); } } + } +} diff --git a/OpenRA.Mods.RA/IdleAnimation.cs b/OpenRA.Mods.RA/IdleAnimation.cs index 09ba0be23c..07dc39c91a 100644 --- a/OpenRA.Mods.RA/IdleAnimation.cs +++ b/OpenRA.Mods.RA/IdleAnimation.cs @@ -1,21 +1,21 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using OpenRA.Mods.RA.Render; +#endregion + +using OpenRA.Mods.RA.Render; using OpenRA.Traits; namespace OpenRA.Mods.RA { class IdleAnimationInfo : ITraitInfo, ITraitPrerequisite { - public readonly int MinIdleWaitTicks = 30; + public readonly int MinIdleWaitTicks = 30; public readonly int MaxIdleWaitTicks = 110; public readonly string[] Animations = {}; public object Create(ActorInitializer init) { return new IdleAnimation(this); } @@ -53,19 +53,19 @@ namespace OpenRA.Mods.RA else if (delay > 0 && --delay == 0) { - state = IdleState.Active; - var ri = self.TraitOrDefault(); - - if (ri.anim.HasSequence(sequence)) - { - ri.anim.PlayThen(sequence, - () => - { - state = IdleState.None; - ri.anim.PlayRepeating("stand"); - }); - } - else + state = IdleState.Active; + var ri = self.TraitOrDefault(); + + if (ri.anim.HasSequence(sequence)) + { + ri.anim.PlayThen(sequence, + () => + { + state = IdleState.None; + ri.anim.PlayRepeating("stand"); + }); + } + else state = IdleState.None; } } @@ -76,7 +76,7 @@ namespace OpenRA.Mods.RA return; state = IdleState.Waiting; - sequence = Info.Animations.Random(self.World.SharedRandom); + sequence = Info.Animations.Random(self.World.SharedRandom); delay = self.World.SharedRandom.Next(Info.MinIdleWaitTicks, Info.MaxIdleWaitTicks); } } diff --git a/OpenRA.Mods.RA/InfiltrateForSupportPower.cs b/OpenRA.Mods.RA/InfiltrateForSupportPower.cs index 0df30381b0..a6f183e056 100644 --- a/OpenRA.Mods.RA/InfiltrateForSupportPower.cs +++ b/OpenRA.Mods.RA/InfiltrateForSupportPower.cs @@ -1,40 +1,40 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.RA -{ - class InfiltrateForSupportPowerInfo : ITraitInfo - { - [ActorReference] - public readonly string Proxy = null; - public object Create(ActorInitializer init) { return new InfiltrateForSupportPower(this); } - } - - class InfiltrateForSupportPower : IAcceptSpy - { - InfiltrateForSupportPowerInfo Info; - public InfiltrateForSupportPower(InfiltrateForSupportPowerInfo info) - { - Info = info; - } - - public void OnInfiltrate(Actor self, Actor spy) - { - spy.World.AddFrameEndTask(w => w.CreateActor(Info.Proxy, new TypeDictionary - { - new OwnerInit( spy.Owner ) - })); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.RA +{ + class InfiltrateForSupportPowerInfo : ITraitInfo + { + [ActorReference] + public readonly string Proxy = null; + public object Create(ActorInitializer init) { return new InfiltrateForSupportPower(this); } + } + + class InfiltrateForSupportPower : IAcceptSpy + { + InfiltrateForSupportPowerInfo Info; + public InfiltrateForSupportPower(InfiltrateForSupportPowerInfo info) + { + Info = info; + } + + public void OnInfiltrate(Actor self, Actor spy) + { + spy.World.AddFrameEndTask(w => w.CreateActor(Info.Proxy, new TypeDictionary + { + new OwnerInit( spy.Owner ) + })); + } + } +} diff --git a/OpenRA.Mods.RA/InvisibleToOthers.cs b/OpenRA.Mods.RA/InvisibleToOthers.cs index 9bc9036b2d..9b2a0a1907 100644 --- a/OpenRA.Mods.RA/InvisibleToOthers.cs +++ b/OpenRA.Mods.RA/InvisibleToOthers.cs @@ -1,37 +1,37 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class InvisibleToOthersInfo : TraitInfo { } - - class InvisibleToOthers : IRenderModifier, IVisibilityModifier, IRadarColorModifier - { - public bool IsVisible(Actor self) - { - return self.World.LocalPlayer == null || self.Owner == self.World.LocalPlayer; - } - - public Color RadarColorOverride(Actor self) - { - return Color.FromArgb(128, self.Owner.ColorRamp.GetColor(0)); - } - - public IEnumerable ModifyRender(Actor self, IEnumerable r) - { - return self.World.LocalPlayer == self.Owner - ? r : new Renderable[] { }; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class InvisibleToOthersInfo : TraitInfo { } + + class InvisibleToOthers : IRenderModifier, IVisibilityModifier, IRadarColorModifier + { + public bool IsVisible(Actor self) + { + return self.World.LocalPlayer == null || self.Owner == self.World.LocalPlayer; + } + + public Color RadarColorOverride(Actor self) + { + return Color.FromArgb(128, self.Owner.ColorRamp.GetColor(0)); + } + + public IEnumerable ModifyRender(Actor self, IEnumerable r) + { + return self.World.LocalPlayer == self.Owner + ? r : new Renderable[] { }; + } + } +} diff --git a/OpenRA.Mods.RA/Invulnerable.cs b/OpenRA.Mods.RA/Invulnerable.cs index c8bf5103cb..c8ce3f2596 100644 --- a/OpenRA.Mods.RA/Invulnerable.cs +++ b/OpenRA.Mods.RA/Invulnerable.cs @@ -1,14 +1,14 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ #endregion -using OpenRA.GameRules; +using OpenRA.GameRules; using OpenRA.Traits; namespace OpenRA.Mods.RA diff --git a/OpenRA.Mods.RA/IronCurtainable.cs b/OpenRA.Mods.RA/IronCurtainable.cs index bad12881a6..47e5e25fe3 100644 --- a/OpenRA.Mods.RA/IronCurtainable.cs +++ b/OpenRA.Mods.RA/IronCurtainable.cs @@ -1,43 +1,43 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.GameRules; -using OpenRA.Mods.RA.Effects; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class IronCurtainableInfo : TraitInfo { } - - class IronCurtainable : IDamageModifier, ITick, ISync - { - [Sync] - int RemainingTicks = 0; - - public void Tick(Actor self) - { - if (RemainingTicks > 0) - RemainingTicks--; - } - - public float GetDamageModifier(Actor attacker, WarheadInfo warhead) - { - return (RemainingTicks > 0) ? 0.0f : 1.0f; - } - - public void Activate(Actor self, int duration) - { - if (RemainingTicks == 0) - self.World.AddFrameEndTask(w => w.Add(new InvulnEffect(self))); // do not stack the invuln effect - - RemainingTicks = duration; - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.GameRules; +using OpenRA.Mods.RA.Effects; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class IronCurtainableInfo : TraitInfo { } + + class IronCurtainable : IDamageModifier, ITick, ISync + { + [Sync] + int RemainingTicks = 0; + + public void Tick(Actor self) + { + if (RemainingTicks > 0) + RemainingTicks--; + } + + public float GetDamageModifier(Actor attacker, WarheadInfo warhead) + { + return (RemainingTicks > 0) ? 0.0f : 1.0f; + } + + public void Activate(Actor self, int duration) + { + if (RemainingTicks == 0) + self.World.AddFrameEndTask(w => w.Add(new InvulnEffect(self))); // do not stack the invuln effect + + RemainingTicks = duration; + } + } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/LeavesHusk.cs b/OpenRA.Mods.RA/LeavesHusk.cs index b5b3598b3a..3bc608c243 100644 --- a/OpenRA.Mods.RA/LeavesHusk.cs +++ b/OpenRA.Mods.RA/LeavesHusk.cs @@ -1,48 +1,48 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.RA -{ - class LeavesHuskInfo : TraitInfo - { - [ActorReference] - public readonly string HuskActor = null; - } - - class LeavesHusk : INotifyDamage - { - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageState == DamageState.Dead) - self.World.AddFrameEndTask(w => - { - var info = self.Info.Traits.Get(); - var td = new TypeDictionary - { - new LocationInit( self.Location ), - new OwnerInit( self.Owner ), - new SkipMakeAnimsInit() - }; - - if (self.HasTrait()) - td.Add(new FacingInit( self.Trait().Facing )); - - var husk = w.CreateActor(info.HuskActor, td); - var turreted = self.TraitOrDefault(); - if (turreted != null) - foreach (var p in husk.TraitsImplementing()) - p.InitialFacing = turreted.turretFacing; - }); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.RA +{ + class LeavesHuskInfo : TraitInfo + { + [ActorReference] + public readonly string HuskActor = null; + } + + class LeavesHusk : INotifyDamage + { + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageState == DamageState.Dead) + self.World.AddFrameEndTask(w => + { + var info = self.Info.Traits.Get(); + var td = new TypeDictionary + { + new LocationInit( self.Location ), + new OwnerInit( self.Owner ), + new SkipMakeAnimsInit() + }; + + if (self.HasTrait()) + td.Add(new FacingInit( self.Trait().Facing )); + + var husk = w.CreateActor(info.HuskActor, td); + var turreted = self.TraitOrDefault(); + if (turreted != null) + foreach (var p in husk.TraitsImplementing()) + p.InitialFacing = turreted.turretFacing; + }); + } + } +} diff --git a/OpenRA.Mods.RA/LightPaletteRotator.cs b/OpenRA.Mods.RA/LightPaletteRotator.cs index 891098be2a..f0e1534171 100644 --- a/OpenRA.Mods.RA/LightPaletteRotator.cs +++ b/OpenRA.Mods.RA/LightPaletteRotator.cs @@ -1,42 +1,42 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class LightPaletteRotatorInfo : TraitInfo { } - class LightPaletteRotator : ITick, IPaletteModifier - { - float t = 0; - public void Tick(Actor self) - { - t += .5f; - } - - public void AdjustPalette(Dictionary palettes) - { - var excludePalettes = new List(){"cursor", "chrome", "colorpicker"}; - foreach (var pal in palettes) - { - if (excludePalettes.Contains(pal.Key)) - continue; - - var rotate = (int)t % 18; - if (rotate > 9) - rotate = 18 - rotate; - - pal.Value.SetColor(0x67, pal.Value.GetColor(230+rotate)); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class LightPaletteRotatorInfo : TraitInfo { } + class LightPaletteRotator : ITick, IPaletteModifier + { + float t = 0; + public void Tick(Actor self) + { + t += .5f; + } + + public void AdjustPalette(Dictionary palettes) + { + var excludePalettes = new List(){"cursor", "chrome", "colorpicker"}; + foreach (var pal in palettes) + { + if (excludePalettes.Contains(pal.Key)) + continue; + + var rotate = (int)t % 18; + if (rotate > 9) + rotate = 18 - rotate; + + pal.Value.SetColor(0x67, pal.Value.GetColor(230+rotate)); + } + } + } +} diff --git a/OpenRA.Mods.RA/LimitedAmmo.cs b/OpenRA.Mods.RA/LimitedAmmo.cs index 4409703c49..6ee07ddc42 100644 --- a/OpenRA.Mods.RA/LimitedAmmo.cs +++ b/OpenRA.Mods.RA/LimitedAmmo.cs @@ -1,54 +1,54 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class LimitedAmmoInfo : ITraitInfo - { - public readonly int Ammo = 0; - public readonly int PipCount = 0; - - public object Create(ActorInitializer init) { return new LimitedAmmo(this); } - } - - public class LimitedAmmo : INotifyAttack, IPips, ISync - { - [Sync] - int ammo; - LimitedAmmoInfo Info; - - public LimitedAmmo(LimitedAmmoInfo info) - { - ammo = info.Ammo; - Info = info; - } - - public bool FullAmmo() { return ammo == Info.Ammo; } - public bool HasAmmo() { return ammo > 0; } - public bool GiveAmmo() - { - if (ammo >= Info.Ammo) return false; - ++ammo; - return true; - } - - public void Attacking(Actor self, Target target) { --ammo; } - - public IEnumerable GetPips(Actor self) - { - var pips = Info.PipCount != 0 ? Info.PipCount : Info.Ammo; - return Graphics.Util.MakeArray(pips, - i => (ammo * pips) / Info.Ammo > i ? PipType.Green : PipType.Transparent); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class LimitedAmmoInfo : ITraitInfo + { + public readonly int Ammo = 0; + public readonly int PipCount = 0; + + public object Create(ActorInitializer init) { return new LimitedAmmo(this); } + } + + public class LimitedAmmo : INotifyAttack, IPips, ISync + { + [Sync] + int ammo; + LimitedAmmoInfo Info; + + public LimitedAmmo(LimitedAmmoInfo info) + { + ammo = info.Ammo; + Info = info; + } + + public bool FullAmmo() { return ammo == Info.Ammo; } + public bool HasAmmo() { return ammo > 0; } + public bool GiveAmmo() + { + if (ammo >= Info.Ammo) return false; + ++ammo; + return true; + } + + public void Attacking(Actor self, Target target) { --ammo; } + + public IEnumerable GetPips(Actor self) + { + var pips = Info.PipCount != 0 ? Info.PipCount : Info.Ammo; + return Graphics.Util.MakeArray(pips, + i => (ammo * pips) / Info.Ammo > i ? PipType.Green : PipType.Transparent); + } + } +} diff --git a/OpenRA.Mods.RA/MPStartLocations.cs b/OpenRA.Mods.RA/MPStartLocations.cs index eec0bd460f..ed7ffe3727 100755 --- a/OpenRA.Mods.RA/MPStartLocations.cs +++ b/OpenRA.Mods.RA/MPStartLocations.cs @@ -1,18 +1,18 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Network; +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Network; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -32,21 +32,21 @@ namespace OpenRA.Mods.RA .Select(c => world.Map.SpawnPoints.ElementAt(c.SpawnPoint - 1)).ToList(); var available = world.Map.SpawnPoints.Except(taken).ToList(); - // Set spawn - foreach (var slot in world.LobbyInfo.Slots) - { - if (slot.Spectator) - continue; // Skip spectator slots - var client = world.LobbyInfo.Clients.FirstOrDefault(c => c.Slot == slot.Index); - var player = FindPlayerInSlot(world, slot); - - if (player == null) continue; - - var spid = (client == null || client.SpawnPoint == 0) - ? ChooseSpawnPoint(world, available, taken) - : world.Map.SpawnPoints.ElementAt(client.SpawnPoint - 1); - - Start.Add(player, spid); + // Set spawn + foreach (var slot in world.LobbyInfo.Slots) + { + if (slot.Spectator) + continue; // Skip spectator slots + var client = world.LobbyInfo.Clients.FirstOrDefault(c => c.Slot == slot.Index); + var player = FindPlayerInSlot(world, slot); + + if (player == null) continue; + + var spid = (client == null || client.SpawnPoint == 0) + ? ChooseSpawnPoint(world, available, taken) + : world.Map.SpawnPoints.ElementAt(client.SpawnPoint - 1); + + Start.Add(player, spid); } // Explore allied shroud @@ -58,11 +58,11 @@ namespace OpenRA.Mods.RA // Set viewport if (world.LocalPlayer != null && Start.ContainsKey(world.LocalPlayer)) Game.viewport.Center(Start[world.LocalPlayer]); - } - - static Player FindPlayerInSlot(World world, Session.Slot slot) - { - return world.players.Values.FirstOrDefault(p => p.PlayerRef.Name == slot.MapPlayer); + } + + static Player FindPlayerInSlot(World world, Session.Slot slot) + { + return world.players.Values.FirstOrDefault(p => p.PlayerRef.Name == slot.MapPlayer); } static int2 ChooseSpawnPoint(World world, List available, List taken) diff --git a/OpenRA.Mods.RA/Mine.cs b/OpenRA.Mods.RA/Mine.cs index 8e0492bbe0..61966ce878 100644 --- a/OpenRA.Mods.RA/Mine.cs +++ b/OpenRA.Mods.RA/Mine.cs @@ -1,64 +1,64 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Mods.RA.Activities; -using OpenRA.Traits; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.RA -{ - class MineInfo : ITraitInfo - { - public readonly string[] CrushClasses = { }; - [WeaponReference] - public readonly string Weapon = "ATMine"; - public readonly bool AvoidFriendly = true; - - public object Create(ActorInitializer init) { return new Mine(init, this); } - } - - class Mine : ICrushable, IOccupySpace, ISync - { - readonly Actor self; - readonly MineInfo info; - [Sync] - readonly int2 location; - - public Mine(ActorInitializer init, MineInfo info) - { - this.self = init.self; - this.info = info; - this.location = init.Get(); - } - - public void OnCrush(Actor crusher) - { - if (crusher.HasTrait() && crusher.Owner == self.Owner) - return; - - var info = self.Info.Traits.Get(); - Combat.DoExplosion(self, info.Weapon, crusher.CenterLocation, 0); - self.QueueActivity(new RemoveSelf()); - } - - // TODO: Re-implement friendly-mine avoidance - public IEnumerable CrushClasses { get { return info.CrushClasses; } } - - public int2 TopLeft { get { return location; } } - - public IEnumerable> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); } - public int2 PxPosition { get { return Util.CenterOfCell( location ); } } - } - - /* tag trait for stuff that shouldnt trigger mines */ - class MineImmuneInfo : TraitInfo { } - class MineImmune { } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.RA +{ + class MineInfo : ITraitInfo + { + public readonly string[] CrushClasses = { }; + [WeaponReference] + public readonly string Weapon = "ATMine"; + public readonly bool AvoidFriendly = true; + + public object Create(ActorInitializer init) { return new Mine(init, this); } + } + + class Mine : ICrushable, IOccupySpace, ISync + { + readonly Actor self; + readonly MineInfo info; + [Sync] + readonly int2 location; + + public Mine(ActorInitializer init, MineInfo info) + { + this.self = init.self; + this.info = info; + this.location = init.Get(); + } + + public void OnCrush(Actor crusher) + { + if (crusher.HasTrait() && crusher.Owner == self.Owner) + return; + + var info = self.Info.Traits.Get(); + Combat.DoExplosion(self, info.Weapon, crusher.CenterLocation, 0); + self.QueueActivity(new RemoveSelf()); + } + + // TODO: Re-implement friendly-mine avoidance + public IEnumerable CrushClasses { get { return info.CrushClasses; } } + + public int2 TopLeft { get { return location; } } + + public IEnumerable> OccupiedCells() { yield return Pair.New(TopLeft, SubCell.FullCell); } + public int2 PxPosition { get { return Util.CenterOfCell( location ); } } + } + + /* tag trait for stuff that shouldnt trigger mines */ + class MineImmuneInfo : TraitInfo { } + class MineImmune { } +} diff --git a/OpenRA.Mods.RA/Minelayer.cs b/OpenRA.Mods.RA/Minelayer.cs index 0fcb0137e9..09f0fdc570 100644 --- a/OpenRA.Mods.RA/Minelayer.cs +++ b/OpenRA.Mods.RA/Minelayer.cs @@ -1,174 +1,174 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Activities; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class MinelayerInfo : TraitInfo - { - [ActorReference] - public readonly string Mine = "minv"; - public readonly float MinefieldDepth = 1.5f; - [ActorReference] - public readonly string[] RearmBuildings = { "fix" }; - } - - class Minelayer : IIssueOrder, IResolveOrder, IPostRenderSelection, ISync - { - /* [Sync] when sync can cope with arrays! */ - public int2[] minefield = null; - [Sync] int2 minefieldStart; - - public IEnumerable Orders - { - get { yield return new BeginMinefieldOrderTargeter(); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order is BeginMinefieldOrderTargeter ) - { - var start = Traits.Util.CellContaining( target.CenterLocation ); - self.World.OrderGenerator = new MinefieldOrderGenerator( self, start ); - return new Order("BeginMinefield", self, false) { TargetLocation = start }; - } - return null; - } - - public void ResolveOrder(Actor self, Order order) - { - if( order.OrderString == "BeginMinefield" ) - minefieldStart = order.TargetLocation; - - if (order.OrderString == "PlaceMinefield") - { - var movement = self.Trait(); - - minefield = GetMinefieldCells(minefieldStart, order.TargetLocation, - self.Info.Traits.Get().MinefieldDepth) - .Where(p => movement.CanEnterCell(p)).ToArray(); - - self.CancelActivity(); - self.QueueActivity(new LayMines()); - } - } - - static IEnumerable GetMinefieldCells(int2 start, int2 end, float depth) - { - var mins = int2.Min(start, end); - var maxs = int2.Max(start, end); - - /* todo: proper endcaps, if anyone cares (which won't happen unless depth is large) */ - - var p = end - start; - var q = new float2(p.Y, -p.X); - q = (start != end) ? (1 / q.Length) * q : new float2(1, 0); - var c = -float2.Dot(q, start); - - /* return all points such that |ax + by + c| < depth */ - - for (var i = mins.X; i <= maxs.X; i++) - for (var j = mins.Y; j <= maxs.Y; j++) - if (Math.Abs(q.X * i + q.Y * j + c) < depth) - yield return new int2(i, j); - } - - class MinefieldOrderGenerator : IOrderGenerator - { - readonly Actor minelayer; - readonly int2 minefieldStart; - - public MinefieldOrderGenerator(Actor self, int2 xy ) { minelayer = self; minefieldStart = xy; } - - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Left) - { - world.CancelInputMode(); - yield break; - } - - var underCursor = world.FindUnitsAtMouse(mi.Location) - .OrderByDescending(a => a.Info.Traits.Contains() - ? a.Info.Traits.Get().Priority : int.MinValue) - .FirstOrDefault(); - - if( mi.Button == MouseButton.Right && underCursor == null ) - { - minelayer.World.CancelInputMode(); - yield return new Order("PlaceMinefield", minelayer, false) { TargetLocation = xy }; - } - } - - public void Tick(World world) - { - if (!minelayer.IsInWorld || minelayer.IsDead()) - world.CancelInputMode(); - } - - int2 lastMousePos; - public void RenderAfterWorld(WorldRenderer wr, World world) - { - if (!minelayer.IsInWorld) - return; - - var movement = minelayer.Trait(); - var minefield = GetMinefieldCells(minefieldStart, lastMousePos, - minelayer.Info.Traits.Get().MinefieldDepth) - .Where(p => movement.CanEnterCell(p)).ToArray(); - - wr.DrawLocus(Color.Cyan, minefield); - } - - public void RenderBeforeWorld(WorldRenderer wr, World world) { } - - public string GetCursor(World world, int2 xy, MouseInput mi) { lastMousePos = xy; return "ability"; } /* todo */ - } - - public void RenderAfterWorld(WorldRenderer wr, Actor self) - { - if (self.Owner != self.World.LocalPlayer) - return; - - if (minefield != null) - wr.DrawLocus(Color.Cyan, minefield); - } - - class BeginMinefieldOrderTargeter : IOrderTargeter - { - public string OrderID { get { return "BeginMinefield"; } } - public int OrderPriority { get { return 5; } } - - public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - return false; - } - - public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - if (!self.World.Map.IsInMap(location)) - return false; - - cursor = "ability"; - IsQueued = forceQueued; - - return ( actorsAtLocation.Count == 0 && forceAttack ); - } - public bool IsQueued { get; protected set; } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class MinelayerInfo : TraitInfo + { + [ActorReference] + public readonly string Mine = "minv"; + public readonly float MinefieldDepth = 1.5f; + [ActorReference] + public readonly string[] RearmBuildings = { "fix" }; + } + + class Minelayer : IIssueOrder, IResolveOrder, IPostRenderSelection, ISync + { + /* [Sync] when sync can cope with arrays! */ + public int2[] minefield = null; + [Sync] int2 minefieldStart; + + public IEnumerable Orders + { + get { yield return new BeginMinefieldOrderTargeter(); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order is BeginMinefieldOrderTargeter ) + { + var start = Traits.Util.CellContaining( target.CenterLocation ); + self.World.OrderGenerator = new MinefieldOrderGenerator( self, start ); + return new Order("BeginMinefield", self, false) { TargetLocation = start }; + } + return null; + } + + public void ResolveOrder(Actor self, Order order) + { + if( order.OrderString == "BeginMinefield" ) + minefieldStart = order.TargetLocation; + + if (order.OrderString == "PlaceMinefield") + { + var movement = self.Trait(); + + minefield = GetMinefieldCells(minefieldStart, order.TargetLocation, + self.Info.Traits.Get().MinefieldDepth) + .Where(p => movement.CanEnterCell(p)).ToArray(); + + self.CancelActivity(); + self.QueueActivity(new LayMines()); + } + } + + static IEnumerable GetMinefieldCells(int2 start, int2 end, float depth) + { + var mins = int2.Min(start, end); + var maxs = int2.Max(start, end); + + /* todo: proper endcaps, if anyone cares (which won't happen unless depth is large) */ + + var p = end - start; + var q = new float2(p.Y, -p.X); + q = (start != end) ? (1 / q.Length) * q : new float2(1, 0); + var c = -float2.Dot(q, start); + + /* return all points such that |ax + by + c| < depth */ + + for (var i = mins.X; i <= maxs.X; i++) + for (var j = mins.Y; j <= maxs.Y; j++) + if (Math.Abs(q.X * i + q.Y * j + c) < depth) + yield return new int2(i, j); + } + + class MinefieldOrderGenerator : IOrderGenerator + { + readonly Actor minelayer; + readonly int2 minefieldStart; + + public MinefieldOrderGenerator(Actor self, int2 xy ) { minelayer = self; minefieldStart = xy; } + + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Left) + { + world.CancelInputMode(); + yield break; + } + + var underCursor = world.FindUnitsAtMouse(mi.Location) + .OrderByDescending(a => a.Info.Traits.Contains() + ? a.Info.Traits.Get().Priority : int.MinValue) + .FirstOrDefault(); + + if( mi.Button == MouseButton.Right && underCursor == null ) + { + minelayer.World.CancelInputMode(); + yield return new Order("PlaceMinefield", minelayer, false) { TargetLocation = xy }; + } + } + + public void Tick(World world) + { + if (!minelayer.IsInWorld || minelayer.IsDead()) + world.CancelInputMode(); + } + + int2 lastMousePos; + public void RenderAfterWorld(WorldRenderer wr, World world) + { + if (!minelayer.IsInWorld) + return; + + var movement = minelayer.Trait(); + var minefield = GetMinefieldCells(minefieldStart, lastMousePos, + minelayer.Info.Traits.Get().MinefieldDepth) + .Where(p => movement.CanEnterCell(p)).ToArray(); + + wr.DrawLocus(Color.Cyan, minefield); + } + + public void RenderBeforeWorld(WorldRenderer wr, World world) { } + + public string GetCursor(World world, int2 xy, MouseInput mi) { lastMousePos = xy; return "ability"; } /* todo */ + } + + public void RenderAfterWorld(WorldRenderer wr, Actor self) + { + if (self.Owner != self.World.LocalPlayer) + return; + + if (minefield != null) + wr.DrawLocus(Color.Cyan, minefield); + } + + class BeginMinefieldOrderTargeter : IOrderTargeter + { + public string OrderID { get { return "BeginMinefield"; } } + public int OrderPriority { get { return 5; } } + + public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + return false; + } + + public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + if (!self.World.Map.IsInMap(location)) + return false; + + cursor = "ability"; + IsQueued = forceQueued; + + return ( actorsAtLocation.Count == 0 && forceAttack ); + } + public bool IsQueued { get; protected set; } + } + } +} diff --git a/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs b/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs index 6355647d13..a0bb074099 100644 --- a/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs +++ b/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs @@ -1,34 +1,34 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class FrozenUnderFogInfo : TraitInfo {} - - class FrozenUnderFog : IRenderModifier, IVisibilityModifier - { - public bool IsVisible(Actor self) - { - return Shroud.GetVisOrigins(self).Any(o => self.World.LocalShroud.IsVisible(o)); - } - - Renderable[] cache = { }; - public IEnumerable ModifyRender(Actor self, IEnumerable r) - { - if (IsVisible(self)) - cache = r.ToArray(); - return cache; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class FrozenUnderFogInfo : TraitInfo {} + + class FrozenUnderFog : IRenderModifier, IVisibilityModifier + { + public bool IsVisible(Actor self) + { + return Shroud.GetVisOrigins(self).Any(o => self.World.LocalShroud.IsVisible(o)); + } + + Renderable[] cache = { }; + public IEnumerable ModifyRender(Actor self, IEnumerable r) + { + if (IsVisible(self)) + cache = r.ToArray(); + return cache; + } + } +} diff --git a/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs b/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs index 7d620b8316..d1bdd7583a 100644 --- a/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs +++ b/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs @@ -1,32 +1,32 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class HiddenUnderFogInfo : TraitInfo {} - - class HiddenUnderFog : IRenderModifier, IVisibilityModifier - { - public bool IsVisible(Actor self) - { - return Shroud.GetVisOrigins(self).Any(o => self.World.LocalShroud.IsVisible(o)); - } - - static Renderable[] Nothing = { }; - public IEnumerable ModifyRender(Actor self, IEnumerable r) - { - return IsVisible(self) ? r : Nothing; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class HiddenUnderFogInfo : TraitInfo {} + + class HiddenUnderFog : IRenderModifier, IVisibilityModifier + { + public bool IsVisible(Actor self) + { + return Shroud.GetVisOrigins(self).Any(o => self.World.LocalShroud.IsVisible(o)); + } + + static Renderable[] Nothing = { }; + public IEnumerable ModifyRender(Actor self, IEnumerable r) + { + return IsVisible(self) ? r : Nothing; + } + } +} diff --git a/OpenRA.Mods.RA/Move/Drag.cs b/OpenRA.Mods.RA/Move/Drag.cs index 8c042bc947..7633dfc64d 100755 --- a/OpenRA.Mods.RA/Move/Drag.cs +++ b/OpenRA.Mods.RA/Move/Drag.cs @@ -1,16 +1,16 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Traits; - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Traits; + namespace OpenRA.Mods.RA.Move { public class Drag : IActivity @@ -30,32 +30,32 @@ namespace OpenRA.Mods.RA.Move int ticks = 0; public IActivity Tick( Actor self ) - { + { var mobile = self.Trait(); - mobile.PxPosition = int2.Lerp(startLocation, endLocation, ticks, length - 1); + mobile.PxPosition = int2.Lerp(startLocation, endLocation, ticks, length - 1); if (++ticks >= length) { mobile.IsMoving = false; - return NextActivity; - } + return NextActivity; + } mobile.IsMoving = true; return this; } public void Cancel(Actor self) { } - public void Queue( IActivity activity ) - { - if( NextActivity != null ) - NextActivity.Queue( activity ); - else - NextActivity = activity; - } - - public IEnumerable GetCurrentPath() - { - yield return endLocation; - } + public void Queue( IActivity activity ) + { + if( NextActivity != null ) + NextActivity.Queue( activity ); + else + NextActivity = activity; + } + + public IEnumerable GetCurrentPath() + { + yield return endLocation; + } } } diff --git a/OpenRA.Mods.RA/Move/Mobile.cs b/OpenRA.Mods.RA/Move/Mobile.cs index 20d512d0ba..7c6f4f0a00 100755 --- a/OpenRA.Mods.RA/Move/Mobile.cs +++ b/OpenRA.Mods.RA/Move/Mobile.cs @@ -1,467 +1,467 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Effects; -using OpenRA.Mods.RA.Activities; -using OpenRA.Traits.Activities; -using OpenRA.FileFormats; -using System.Diagnostics; -using OpenRA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Move -{ - public class MobileInfo : ITraitInfo - { - [FieldLoader.LoadUsing("LoadSpeeds")] - public readonly Dictionary TerrainSpeeds; - [FieldLoader.Load] - public readonly string[] Crushes; - [FieldLoader.Load] - public readonly int WaitAverage = 60; - [FieldLoader.Load] - public readonly int WaitSpread = 20; - [FieldLoader.Load] - public readonly int InitialFacing = 128; - [FieldLoader.Load] - public readonly int ROT = 255; - [FieldLoader.Load] - public readonly int Speed = 1; - [FieldLoader.Load] - public readonly bool OnRails = false; - [FieldLoader.Load] - public readonly bool SharesCell = false; - - public virtual object Create(ActorInitializer init) { return new Mobile(init, this); } - - static object LoadSpeeds(MiniYaml y) - { - Dictionary ret = new Dictionary(); - foreach (var t in y.NodesDict["TerrainSpeeds"].Nodes) - { - var speed = (decimal)FieldLoader.GetValue("speed", typeof(decimal), t.Value.Value); - var cost = t.Value.NodesDict.ContainsKey("PathingCost") ? (int)FieldLoader.GetValue("cost", typeof(int), t.Value.NodesDict["PathingCost"].Value) : (int)(10000 / speed); - ret.Add(t.Key, new TerrainInfo { Speed = speed, Cost = cost }); - } - - return ret; - } - - public class TerrainInfo - { - public int Cost = int.MaxValue; - public decimal Speed = 0; - } - - public int MovementCostForCell(World world, int2 cell) - { - if (!world.Map.IsInMap(cell.X, cell.Y)) - return int.MaxValue; - - var type = world.GetTerrainType(cell); - if (!TerrainSpeeds.ContainsKey(type)) - return int.MaxValue; - - return TerrainSpeeds[type].Cost; - } - - public readonly Dictionary SubCellOffsets = new Dictionary() - { - {SubCell.TopLeft, new int2(-7,-6)}, - {SubCell.TopRight, new int2(6,-6)}, - {SubCell.Center, new int2(0,0)}, - {SubCell.BottomLeft, new int2(-7,6)}, - {SubCell.BottomRight, new int2(6,6)}, - {SubCell.FullCell, new int2(0,0)}, - }; - - public bool CanEnterCell(World world, UnitInfluence uim, int2 cell, Actor ignoreActor, bool checkTransientActors) - { - if (MovementCostForCell(world, cell) == int.MaxValue) - return false; - - if (SharesCell && uim.HasFreeSubCell(cell)) - return true; - - var blockingActors = uim.GetUnitsAt(cell).Where(x => x != ignoreActor).ToList(); - if (checkTransientActors && blockingActors.Count > 0) - { - // Non-sharable unit can enter a cell with shareable units only if it can crush all of them - if (Crushes == null) - return false; - - if (blockingActors.Any(a => !(a.HasTrait() && - a.TraitsImplementing().Any(b => b.CrushClasses.Intersect(Crushes).Any())))) - return false; - } - - return true; - } - - public bool CanEnterCell(World world, int2 cell, Actor ignoreActor, bool checkTransientActors) - { - var uim = world.WorldActor.Trait(); - return CanEnterCell(world, uim, cell, ignoreActor, checkTransientActors); - } - } - - public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IOccupySpace, IMove, IFacing, INudge, ISync - { - public readonly Actor self; - public readonly MobileInfo Info; - public bool IsMoving { get; internal set; } - - int __facing; - int2 __fromCell, __toCell; - public SubCell __fromSubCell, __toSubCell; - - int __altitude; - - [Sync] - public int Facing - { - get { return __facing; } - set { __facing = value; } - } - - [Sync] - public int Altitude - { - get { return __altitude; } - set { __altitude = value; } - } - - public int ROT { get { return Info.ROT; } } - public int InitialFacing { get { return Info.InitialFacing; } } - - [Sync] - public int2 PxPosition { get; set; } - [Sync] - public int2 fromCell { get { return __fromCell; } } - [Sync] - public int2 toCell { get { return __toCell; } } - - [Sync] - public int PathHash; // written by Move.EvalPath, to temporarily debug this crap. - - public void SetLocation(int2 from, SubCell fromSub, int2 to, SubCell toSub) - { - if (fromCell == from && toCell == to) return; - RemoveInfluence(); - __fromCell = from; - __toCell = to; - __fromSubCell = fromSub; - __toSubCell = toSub; - AddInfluence(); - } - - UnitInfluence uim; - - const int avgTicksBeforePathing = 5; - const int spreadTicksBeforePathing = 5; - internal int ticksBeforePathing = 0; - - public Mobile(ActorInitializer init, MobileInfo info) - { - this.self = init.self; - this.Info = info; - - uim = self.World.WorldActor.Trait(); - __toSubCell = __fromSubCell = info.SharesCell ? SubCell.Center : SubCell.FullCell; - if (init.Contains()) - { - this.__fromSubCell = this.__toSubCell = init.Get(); - } - - if (init.Contains()) - { - this.__fromCell = this.__toCell = init.Get(); - this.PxPosition = Util.CenterOfCell(fromCell) + info.SubCellOffsets[__fromSubCell]; - } - - this.Facing = init.Contains() ? init.Get() : info.InitialFacing; - this.Altitude = init.Contains() ? init.Get() : 0; - } - - public void SetPosition(Actor self, int2 cell) - { - SetLocation(cell,__fromSubCell, cell,__fromSubCell); - PxPosition = Util.CenterOfCell(fromCell) + Info.SubCellOffsets[__fromSubCell]; - FinishedMoving(self); - } - - public void SetPxPosition(Actor self, int2 px) - { - var cell = Util.CellContaining(px); - SetLocation(cell,__fromSubCell, cell,__fromSubCell); - PxPosition = px; - FinishedMoving(self); - } - - public void AdjustPxPosition(Actor self, int2 px) /* visual hack only */ - { - PxPosition = px; - } - - public IEnumerable Orders { get { yield return new MoveOrderTargeter(Info); } } - - // Note: Returns a valid order even if the unit can't move to the target - public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) - { - if (order is MoveOrderTargeter) - { - if (Info.OnRails) return null; - return new Order("Move", self, queued) { TargetLocation = Util.CellContaining(target.CenterLocation) }; - } - return null; - } - - public int2 NearestMoveableCell(int2 target) - { - if (CanEnterCell(target)) - return target; - - var searched = new List() { }; - // Limit search to a radius of 10 tiles - for (int r = 1; r < 10; r++) - foreach (var tile in self.World.FindTilesInCircle(target, r).Except(searched)) - { - if (CanEnterCell(tile)) - return tile; - - searched.Add(tile); - } - - // Couldn't find a cell - return target; - } - - protected void PerformMove(Actor self, int2 targetLocation, bool queued) - { - var ph = new QueuedActivity( - (qa) => - { - int2 currentLocation = NearestMoveableCell(targetLocation); - - if (!CanEnterCell(currentLocation)) - { - if (queued) self.CancelActivity(); - return; - } - - if (!queued) self.CancelActivity(); - - ticksBeforePathing = avgTicksBeforePathing + self.World.SharedRandom.Next(-spreadTicksBeforePathing, spreadTicksBeforePathing); - - qa.Insert(new Move(currentLocation, 8)); - - self.SetTargetLine(Target.FromCell(currentLocation), Color.Green); - }); - - self.QueueActivity(queued ? ph : ph.Run(self)); - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "Move") - { - var target = order.TargetLocation.Clamp(self.World.Map.Bounds); - PerformMove(self, target, order.Queued && !self.IsIdle); - } - - if (order.OrderString == "Stop") - { - self.CancelActivity(); - } - - if (order.OrderString == "Scatter") - { - OnNudge(self, self); - } - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - if (order.OrderString == "Move") - return "Move"; - return null; - } - - public int2 TopLeft { get { return toCell; } } - - public IEnumerable> OccupiedCells() - { - if (fromCell == toCell) - yield return Pair.New(fromCell, __fromSubCell); - else if (CanEnterCell(toCell)) - yield return Pair.New(toCell, __toSubCell); - else - { - yield return Pair.New(fromCell, __fromSubCell); - yield return Pair.New(toCell, __toSubCell); - } - } - - public SubCell GetDesiredSubcell(int2 a, Actor ignoreActor) - { - if (!Info.SharesCell) - return SubCell.FullCell; - - // Prioritise the current subcell - return new[]{ __fromSubCell, SubCell.TopLeft, SubCell.TopRight, SubCell.Center, - SubCell.BottomLeft, SubCell.BottomRight}.First(b => - { - var blockingActors = uim.GetUnitsAt(a,b).Where(c => c != ignoreActor); - if (blockingActors.Count() > 0) - { - // Non-sharable unit can enter a cell with shareable units only if it can crush all of them - if (Info.Crushes == null) - return false; - - if (blockingActors.Any(c => !(c.HasTrait() && - c.TraitsImplementing().Any(d => d.CrushClasses.Intersect(Info.Crushes).Any())))) - return false; - } - return true; - }); - } - - public bool CanEnterCell(int2 p) - { - return CanEnterCell(p, null, true); - } - - public bool CanEnterCell(int2 cell, Actor ignoreActor, bool checkTransientActors) - { - var uim = self.World.WorldActor.Trait(); - return Info.CanEnterCell(self.World, uim, cell, ignoreActor, checkTransientActors); - } - - public void FinishedMoving(Actor self) - { - var crushable = uim.GetUnitsAt(toCell).Where(a => a != self && a.HasTrait()); - foreach (var a in crushable) - { - var crushActions = a.TraitsImplementing().Where(b => b.CrushClasses.Intersect(Info.Crushes).Any()); - foreach (var b in crushActions) - b.OnCrush(self); - } - } - - public int MovementSpeedForCell(Actor self, int2 cell) - { - var type = self.World.GetTerrainType(cell); - - if (!Info.TerrainSpeeds.ContainsKey(type)) - return 0; - - decimal speed = Info.Speed * Info.TerrainSpeeds[type].Speed; - foreach (var t in self.TraitsImplementing()) - speed *= t.GetSpeedModifier(); - return (int)(speed / 100); - } - - public void AddInfluence() - { - if (self.IsInWorld) - uim.Add(self, this); - } - - public void RemoveInfluence() - { - if (self.IsInWorld) - uim.Remove(self, this); - } - - public void OnNudge(Actor self, Actor nudger) - { - /* initial fairly braindead implementation. */ - - if (self.Owner.Stances[nudger.Owner] != Stance.Ally) - return; /* don't allow ourselves to be pushed around - * by the enemy! */ - - if (!self.IsIdle) - return; /* don't nudge if we're busy doing something! */ - - // pick an adjacent available cell. - var availCells = new List(); - var notStupidCells = new List(); - - for (var i = -1; i < 2; i++) - for (var j = -1; j < 2; j++) - { - var p = toCell + new int2(i, j); - if (CanEnterCell(p)) - availCells.Add(p); - else - if (p != nudger.Location && p != toCell) - notStupidCells.Add(p); - } - - var moveTo = availCells.Any() ? availCells.Random(self.World.SharedRandom) : - notStupidCells.Any() ? notStupidCells.Random(self.World.SharedRandom) : (int2?)null; - - if (moveTo.HasValue) - { - self.CancelActivity(); - self.SetTargetLine(Target.FromCell(moveTo.Value), Color.Green, false); - self.QueueActivity(new Move(moveTo.Value, 0)); - - Log.Write("debug", "OnNudge #{0} from {1} to {2}", - self.ActorID, self.Location, moveTo.Value); - } - else - Log.Write("debug", "OnNudge #{0} refuses at {1}", - self.ActorID, self.Location); - } - - class MoveOrderTargeter : IOrderTargeter - { - readonly MobileInfo unitType; - - public MoveOrderTargeter(MobileInfo unitType) - { - this.unitType = unitType; - } - - public string OrderID { get { return "Move"; } } - public int OrderPriority { get { return 4; } } - public bool IsQueued { get; protected set; } - - public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - return false; - } - - public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - IsQueued = forceQueued; - cursor = "move"; - if (!self.World.Map.IsInMap(location) || (self.World.LocalPlayer.Shroud.IsExplored(location) && - unitType.MovementCostForCell(self.World, location) == int.MaxValue)) - cursor = "move-blocked"; - - return true; - } - } - - public IActivity ScriptedMove(int2 cell) { return new Move(cell); } - public IActivity MoveTo(int2 cell, int nearEnough) { return new Move(cell, nearEnough); } - public IActivity MoveTo(int2 cell, Actor ignoredActor) { return new Move(cell, ignoredActor); } - public IActivity MoveWithinRange(Actor target, int range) { return new Move(target, range); } - public IActivity MoveWithinRange(Target target, int range) { return new Move(target, range); } - public IActivity MoveTo(Func> pathFunc) { return new Move(pathFunc); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Effects; +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits.Activities; +using OpenRA.FileFormats; +using System.Diagnostics; +using OpenRA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Move +{ + public class MobileInfo : ITraitInfo + { + [FieldLoader.LoadUsing("LoadSpeeds")] + public readonly Dictionary TerrainSpeeds; + [FieldLoader.Load] + public readonly string[] Crushes; + [FieldLoader.Load] + public readonly int WaitAverage = 60; + [FieldLoader.Load] + public readonly int WaitSpread = 20; + [FieldLoader.Load] + public readonly int InitialFacing = 128; + [FieldLoader.Load] + public readonly int ROT = 255; + [FieldLoader.Load] + public readonly int Speed = 1; + [FieldLoader.Load] + public readonly bool OnRails = false; + [FieldLoader.Load] + public readonly bool SharesCell = false; + + public virtual object Create(ActorInitializer init) { return new Mobile(init, this); } + + static object LoadSpeeds(MiniYaml y) + { + Dictionary ret = new Dictionary(); + foreach (var t in y.NodesDict["TerrainSpeeds"].Nodes) + { + var speed = (decimal)FieldLoader.GetValue("speed", typeof(decimal), t.Value.Value); + var cost = t.Value.NodesDict.ContainsKey("PathingCost") ? (int)FieldLoader.GetValue("cost", typeof(int), t.Value.NodesDict["PathingCost"].Value) : (int)(10000 / speed); + ret.Add(t.Key, new TerrainInfo { Speed = speed, Cost = cost }); + } + + return ret; + } + + public class TerrainInfo + { + public int Cost = int.MaxValue; + public decimal Speed = 0; + } + + public int MovementCostForCell(World world, int2 cell) + { + if (!world.Map.IsInMap(cell.X, cell.Y)) + return int.MaxValue; + + var type = world.GetTerrainType(cell); + if (!TerrainSpeeds.ContainsKey(type)) + return int.MaxValue; + + return TerrainSpeeds[type].Cost; + } + + public readonly Dictionary SubCellOffsets = new Dictionary() + { + {SubCell.TopLeft, new int2(-7,-6)}, + {SubCell.TopRight, new int2(6,-6)}, + {SubCell.Center, new int2(0,0)}, + {SubCell.BottomLeft, new int2(-7,6)}, + {SubCell.BottomRight, new int2(6,6)}, + {SubCell.FullCell, new int2(0,0)}, + }; + + public bool CanEnterCell(World world, UnitInfluence uim, int2 cell, Actor ignoreActor, bool checkTransientActors) + { + if (MovementCostForCell(world, cell) == int.MaxValue) + return false; + + if (SharesCell && uim.HasFreeSubCell(cell)) + return true; + + var blockingActors = uim.GetUnitsAt(cell).Where(x => x != ignoreActor).ToList(); + if (checkTransientActors && blockingActors.Count > 0) + { + // Non-sharable unit can enter a cell with shareable units only if it can crush all of them + if (Crushes == null) + return false; + + if (blockingActors.Any(a => !(a.HasTrait() && + a.TraitsImplementing().Any(b => b.CrushClasses.Intersect(Crushes).Any())))) + return false; + } + + return true; + } + + public bool CanEnterCell(World world, int2 cell, Actor ignoreActor, bool checkTransientActors) + { + var uim = world.WorldActor.Trait(); + return CanEnterCell(world, uim, cell, ignoreActor, checkTransientActors); + } + } + + public class Mobile : IIssueOrder, IResolveOrder, IOrderVoice, IOccupySpace, IMove, IFacing, INudge, ISync + { + public readonly Actor self; + public readonly MobileInfo Info; + public bool IsMoving { get; internal set; } + + int __facing; + int2 __fromCell, __toCell; + public SubCell __fromSubCell, __toSubCell; + + int __altitude; + + [Sync] + public int Facing + { + get { return __facing; } + set { __facing = value; } + } + + [Sync] + public int Altitude + { + get { return __altitude; } + set { __altitude = value; } + } + + public int ROT { get { return Info.ROT; } } + public int InitialFacing { get { return Info.InitialFacing; } } + + [Sync] + public int2 PxPosition { get; set; } + [Sync] + public int2 fromCell { get { return __fromCell; } } + [Sync] + public int2 toCell { get { return __toCell; } } + + [Sync] + public int PathHash; // written by Move.EvalPath, to temporarily debug this crap. + + public void SetLocation(int2 from, SubCell fromSub, int2 to, SubCell toSub) + { + if (fromCell == from && toCell == to) return; + RemoveInfluence(); + __fromCell = from; + __toCell = to; + __fromSubCell = fromSub; + __toSubCell = toSub; + AddInfluence(); + } + + UnitInfluence uim; + + const int avgTicksBeforePathing = 5; + const int spreadTicksBeforePathing = 5; + internal int ticksBeforePathing = 0; + + public Mobile(ActorInitializer init, MobileInfo info) + { + this.self = init.self; + this.Info = info; + + uim = self.World.WorldActor.Trait(); + __toSubCell = __fromSubCell = info.SharesCell ? SubCell.Center : SubCell.FullCell; + if (init.Contains()) + { + this.__fromSubCell = this.__toSubCell = init.Get(); + } + + if (init.Contains()) + { + this.__fromCell = this.__toCell = init.Get(); + this.PxPosition = Util.CenterOfCell(fromCell) + info.SubCellOffsets[__fromSubCell]; + } + + this.Facing = init.Contains() ? init.Get() : info.InitialFacing; + this.Altitude = init.Contains() ? init.Get() : 0; + } + + public void SetPosition(Actor self, int2 cell) + { + SetLocation(cell,__fromSubCell, cell,__fromSubCell); + PxPosition = Util.CenterOfCell(fromCell) + Info.SubCellOffsets[__fromSubCell]; + FinishedMoving(self); + } + + public void SetPxPosition(Actor self, int2 px) + { + var cell = Util.CellContaining(px); + SetLocation(cell,__fromSubCell, cell,__fromSubCell); + PxPosition = px; + FinishedMoving(self); + } + + public void AdjustPxPosition(Actor self, int2 px) /* visual hack only */ + { + PxPosition = px; + } + + public IEnumerable Orders { get { yield return new MoveOrderTargeter(Info); } } + + // Note: Returns a valid order even if the unit can't move to the target + public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) + { + if (order is MoveOrderTargeter) + { + if (Info.OnRails) return null; + return new Order("Move", self, queued) { TargetLocation = Util.CellContaining(target.CenterLocation) }; + } + return null; + } + + public int2 NearestMoveableCell(int2 target) + { + if (CanEnterCell(target)) + return target; + + var searched = new List() { }; + // Limit search to a radius of 10 tiles + for (int r = 1; r < 10; r++) + foreach (var tile in self.World.FindTilesInCircle(target, r).Except(searched)) + { + if (CanEnterCell(tile)) + return tile; + + searched.Add(tile); + } + + // Couldn't find a cell + return target; + } + + protected void PerformMove(Actor self, int2 targetLocation, bool queued) + { + var ph = new QueuedActivity( + (qa) => + { + int2 currentLocation = NearestMoveableCell(targetLocation); + + if (!CanEnterCell(currentLocation)) + { + if (queued) self.CancelActivity(); + return; + } + + if (!queued) self.CancelActivity(); + + ticksBeforePathing = avgTicksBeforePathing + self.World.SharedRandom.Next(-spreadTicksBeforePathing, spreadTicksBeforePathing); + + qa.Insert(new Move(currentLocation, 8)); + + self.SetTargetLine(Target.FromCell(currentLocation), Color.Green); + }); + + self.QueueActivity(queued ? ph : ph.Run(self)); + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Move") + { + var target = order.TargetLocation.Clamp(self.World.Map.Bounds); + PerformMove(self, target, order.Queued && !self.IsIdle); + } + + if (order.OrderString == "Stop") + { + self.CancelActivity(); + } + + if (order.OrderString == "Scatter") + { + OnNudge(self, self); + } + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + if (order.OrderString == "Move") + return "Move"; + return null; + } + + public int2 TopLeft { get { return toCell; } } + + public IEnumerable> OccupiedCells() + { + if (fromCell == toCell) + yield return Pair.New(fromCell, __fromSubCell); + else if (CanEnterCell(toCell)) + yield return Pair.New(toCell, __toSubCell); + else + { + yield return Pair.New(fromCell, __fromSubCell); + yield return Pair.New(toCell, __toSubCell); + } + } + + public SubCell GetDesiredSubcell(int2 a, Actor ignoreActor) + { + if (!Info.SharesCell) + return SubCell.FullCell; + + // Prioritise the current subcell + return new[]{ __fromSubCell, SubCell.TopLeft, SubCell.TopRight, SubCell.Center, + SubCell.BottomLeft, SubCell.BottomRight}.First(b => + { + var blockingActors = uim.GetUnitsAt(a,b).Where(c => c != ignoreActor); + if (blockingActors.Count() > 0) + { + // Non-sharable unit can enter a cell with shareable units only if it can crush all of them + if (Info.Crushes == null) + return false; + + if (blockingActors.Any(c => !(c.HasTrait() && + c.TraitsImplementing().Any(d => d.CrushClasses.Intersect(Info.Crushes).Any())))) + return false; + } + return true; + }); + } + + public bool CanEnterCell(int2 p) + { + return CanEnterCell(p, null, true); + } + + public bool CanEnterCell(int2 cell, Actor ignoreActor, bool checkTransientActors) + { + var uim = self.World.WorldActor.Trait(); + return Info.CanEnterCell(self.World, uim, cell, ignoreActor, checkTransientActors); + } + + public void FinishedMoving(Actor self) + { + var crushable = uim.GetUnitsAt(toCell).Where(a => a != self && a.HasTrait()); + foreach (var a in crushable) + { + var crushActions = a.TraitsImplementing().Where(b => b.CrushClasses.Intersect(Info.Crushes).Any()); + foreach (var b in crushActions) + b.OnCrush(self); + } + } + + public int MovementSpeedForCell(Actor self, int2 cell) + { + var type = self.World.GetTerrainType(cell); + + if (!Info.TerrainSpeeds.ContainsKey(type)) + return 0; + + decimal speed = Info.Speed * Info.TerrainSpeeds[type].Speed; + foreach (var t in self.TraitsImplementing()) + speed *= t.GetSpeedModifier(); + return (int)(speed / 100); + } + + public void AddInfluence() + { + if (self.IsInWorld) + uim.Add(self, this); + } + + public void RemoveInfluence() + { + if (self.IsInWorld) + uim.Remove(self, this); + } + + public void OnNudge(Actor self, Actor nudger) + { + /* initial fairly braindead implementation. */ + + if (self.Owner.Stances[nudger.Owner] != Stance.Ally) + return; /* don't allow ourselves to be pushed around + * by the enemy! */ + + if (!self.IsIdle) + return; /* don't nudge if we're busy doing something! */ + + // pick an adjacent available cell. + var availCells = new List(); + var notStupidCells = new List(); + + for (var i = -1; i < 2; i++) + for (var j = -1; j < 2; j++) + { + var p = toCell + new int2(i, j); + if (CanEnterCell(p)) + availCells.Add(p); + else + if (p != nudger.Location && p != toCell) + notStupidCells.Add(p); + } + + var moveTo = availCells.Any() ? availCells.Random(self.World.SharedRandom) : + notStupidCells.Any() ? notStupidCells.Random(self.World.SharedRandom) : (int2?)null; + + if (moveTo.HasValue) + { + self.CancelActivity(); + self.SetTargetLine(Target.FromCell(moveTo.Value), Color.Green, false); + self.QueueActivity(new Move(moveTo.Value, 0)); + + Log.Write("debug", "OnNudge #{0} from {1} to {2}", + self.ActorID, self.Location, moveTo.Value); + } + else + Log.Write("debug", "OnNudge #{0} refuses at {1}", + self.ActorID, self.Location); + } + + class MoveOrderTargeter : IOrderTargeter + { + readonly MobileInfo unitType; + + public MoveOrderTargeter(MobileInfo unitType) + { + this.unitType = unitType; + } + + public string OrderID { get { return "Move"; } } + public int OrderPriority { get { return 4; } } + public bool IsQueued { get; protected set; } + + public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + return false; + } + + public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + IsQueued = forceQueued; + cursor = "move"; + if (!self.World.Map.IsInMap(location) || (self.World.LocalPlayer.Shroud.IsExplored(location) && + unitType.MovementCostForCell(self.World, location) == int.MaxValue)) + cursor = "move-blocked"; + + return true; + } + } + + public IActivity ScriptedMove(int2 cell) { return new Move(cell); } + public IActivity MoveTo(int2 cell, int nearEnough) { return new Move(cell, nearEnough); } + public IActivity MoveTo(int2 cell, Actor ignoredActor) { return new Move(cell, ignoredActor); } + public IActivity MoveWithinRange(Actor target, int range) { return new Move(target, range); } + public IActivity MoveWithinRange(Target target, int range) { return new Move(target, range); } + public IActivity MoveTo(Func> pathFunc) { return new Move(pathFunc); } + } +} diff --git a/OpenRA.Mods.RA/Move/Move.cs b/OpenRA.Mods.RA/Move/Move.cs index 90a8ed7cf3..23ae8f2aca 100755 --- a/OpenRA.Mods.RA/Move/Move.cs +++ b/OpenRA.Mods.RA/Move/Move.cs @@ -1,381 +1,381 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using OpenRA.Mods.RA.Activities; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.RA.Move -{ - class Move : CancelableActivity - { - int2? destination; - int nearEnough; - public List path; - Func> getPath; - public Actor ignoreBuilding; - - // Scriptable move order - // Ignores lane bias and nearby units - public Move( int2 destination ) - { - this.getPath = (self,mobile) => - self.World.WorldActor.Trait().FindPath( - PathSearch.FromPoint( self.World, mobile.Info, mobile.toCell, destination, false ) - .WithoutLaneBias()); - this.destination = destination; - this.nearEnough = 0; - } - - public Move( int2 destination, int nearEnough ) - { - this.getPath = (self,mobile) => self.World.WorldActor.Trait().FindUnitPath( mobile.toCell, destination, self ); - this.destination = destination; - this.nearEnough = nearEnough; - } - - public Move(int2 destination, Actor ignoreBuilding) - { - this.getPath = (self,mobile) => - self.World.WorldActor.Trait().FindPath( - PathSearch.FromPoint( self.World, mobile.Info, mobile.toCell, destination, false ) - .WithIgnoredBuilding( ignoreBuilding )); - - this.destination = destination; - this.nearEnough = 0; - this.ignoreBuilding = ignoreBuilding; - } - - public Move( Actor target, int range ) - { - this.getPath = (self,mobile) => self.World.WorldActor.Trait().FindUnitPathToRange( - mobile.toCell, target.Location, - range, self ); - this.destination = null; - this.nearEnough = range; - } - - public Move(Target target, int range) - { - this.getPath = (self,mobile) => self.World.WorldActor.Trait().FindUnitPathToRange( - mobile.toCell, Util.CellContaining(target.CenterLocation), - range, self); - this.destination = null; - this.nearEnough = range; - } - - public Move(Func> getPath) - { - this.getPath = (_1,_2) => getPath(); - this.destination = null; - this.nearEnough = 0; - } - - static int HashList(List xs) - { - int hash = 0; - int n = 0; - foreach (var x in xs) - hash += n++ * x.GetHashCode(); - - return hash; - } - - List EvalPath( Actor self, Mobile mobile ) - { - var path = getPath(self, mobile).TakeWhile(a => a != mobile.toCell).ToList(); - mobile.PathHash = HashList(path); - Log.Write("debug", "EvalPathHash #{0} {1}", - self.ActorID, mobile.PathHash); - return path; - } - - public override IActivity Tick( Actor self ) - { - var mobile = self.Trait(); - - if (destination == mobile.toCell) - return NextActivity; - - if( path == null ) - { - if (mobile.ticksBeforePathing > 0) - { - --mobile.ticksBeforePathing; - return this; - } - - path = EvalPath(self, mobile); - SanityCheckPath( mobile ); - } - - if( path.Count == 0 ) - { - destination = mobile.toCell; - return this; - } - - destination = path[ 0 ]; - - var nextCell = PopPath( self, mobile ); - if( nextCell == null ) - return this; - - int2 dir = nextCell.Value.First - mobile.fromCell; - var firstFacing = Util.GetFacing( dir, mobile.Facing ); - if( firstFacing != mobile.Facing ) - { - path.Add( nextCell.Value.First ); - return Util.SequenceActivities( new Turn( firstFacing ), this ); - } - else - { - mobile.SetLocation( mobile.fromCell, mobile.__fromSubCell, nextCell.Value.First, nextCell.Value.Second ); - var move = new MoveFirstHalf( - this, - Util.CenterOfCell( mobile.fromCell ) + mobile.Info.SubCellOffsets[mobile.__fromSubCell], - Util.BetweenCells( mobile.fromCell, mobile.toCell ) + (mobile.Info.SubCellOffsets[mobile.__fromSubCell] + mobile.Info.SubCellOffsets[mobile.__toSubCell] ) / 2, - mobile.Facing, - mobile.Facing, - 0 ); - - return move; - } - } - - [Conditional( "SANITY_CHECKS")] - void SanityCheckPath( Mobile mobile ) - { - if( path.Count == 0 ) - return; - var d = path[path.Count-1] - mobile.toCell; - if( d.LengthSquared > 2 ) - throw new InvalidOperationException( "(Move) Sanity check failed" ); - } - - bool hasWaited; - bool hasNudged; - int waitTicksRemaining; - - void NudgeBlocker(Actor self, int2 nextCell) - { - var blocker = self.World.WorldActor.Trait().GetUnitsAt(nextCell).FirstOrDefault(); - if (blocker == null) return; - - Log.Write("debug", "NudgeBlocker #{0} nudges #{1} at {2} from {3}", - self.ActorID, blocker.ActorID, nextCell, self.Location); - - var nudge = blocker.TraitOrDefault(); - if (nudge != null) - nudge.OnNudge(blocker, self); - } - - Pair? PopPath( Actor self, Mobile mobile ) - { - if( path.Count == 0 ) return null; - var nextCell = path[ path.Count - 1 ]; - if( !mobile.CanEnterCell( nextCell, ignoreBuilding, true ) ) - { - if( ( mobile.toCell - destination.Value ).LengthSquared <= nearEnough ) - { - path.Clear(); - return null; - } - - if (!hasNudged) - { - NudgeBlocker(self, nextCell); - hasNudged = true; - } - - if (!hasWaited) - { - var info = self.Info.Traits.Get(); - waitTicksRemaining = info.WaitAverage + self.World.SharedRandom.Next(-info.WaitSpread, info.WaitSpread); - hasWaited = true; - } - - if (--waitTicksRemaining >= 0) - return null; - - if (mobile.ticksBeforePathing > 0) - { - --mobile.ticksBeforePathing; - return null; - } - - mobile.RemoveInfluence(); - var newPath = EvalPath(self, mobile); - mobile.AddInfluence(); - - if (newPath.Count != 0) - path = newPath; - - return null; - } - hasNudged = false; - hasWaited = false; - path.RemoveAt( path.Count - 1 ); - - var subCell = mobile.GetDesiredSubcell(nextCell, ignoreBuilding); - return Pair.New(nextCell, subCell); - } - - protected override bool OnCancel( Actor self ) - { - path = new List(); - return true; - } - - public override IEnumerable GetCurrentPath() - { - if( path != null ) - return Enumerable.Reverse(path).Select( c => (float2)Util.CenterOfCell(c) ); - if( destination != null ) - return new float2[] { destination.Value }; - return new float2[ 0 ]; - } - - abstract class MovePart : IActivity - { - public readonly Move move; - public readonly int2 from, to; - public readonly int fromFacing, toFacing; - public int moveFraction; - public readonly int moveFractionTotal; - - public MovePart( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction ) - { - this.move = move; - this.from = from; - this.to = to; - this.fromFacing = fromFacing; - this.toFacing = toFacing; - this.moveFraction = startingFraction; - this.moveFractionTotal = ( ( to - from ) * 3 ).Length; - } - - public void Cancel( Actor self ) - { - move.Cancel( self ); - } - - public void Queue( IActivity activity ) - { - move.Queue( activity ); - } - - public IActivity Tick( Actor self ) - { - var mobile = self.Trait(); - var ret = InnerTick( self, mobile ); - mobile.IsMoving = ( ret is MovePart ); - - if( moveFraction > moveFractionTotal ) - moveFraction = moveFractionTotal; - UpdateCenterLocation( self, mobile ); - - return ret; - } - - IActivity InnerTick( Actor self, Mobile mobile ) - { - moveFraction += mobile.MovementSpeedForCell(self, mobile.toCell); - if( moveFraction <= moveFractionTotal ) - return this; - - var next = OnComplete( self, mobile, move ); - if( next != null ) - return next; - - return move; - } - - void UpdateCenterLocation( Actor self, Mobile mobile ) - { - mobile.PxPosition = int2.Lerp( from, to, moveFraction, moveFractionTotal ); - - if( moveFraction >= moveFractionTotal ) - mobile.Facing = toFacing & 0xFF; - else - mobile.Facing = int2.Lerp( fromFacing, toFacing, moveFraction, moveFractionTotal ) & 0xFF; - } - - protected abstract MovePart OnComplete( Actor self, Mobile mobile, Move parent ); - - public IEnumerable GetCurrentPath() - { - return move.GetCurrentPath(); - } - } - - class MoveFirstHalf : MovePart - { - public MoveFirstHalf( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction ) - : base( move, from, to, fromFacing, toFacing, startingFraction ) - { - } - - protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent ) - { - var nextCell = parent.PopPath( self, mobile ); - if( nextCell != null ) - { - if( ( nextCell.Value.First - mobile.toCell ) != ( mobile.toCell - mobile.fromCell ) ) - { - var ret = new MoveFirstHalf( - move, - Util.BetweenCells( mobile.fromCell, mobile.toCell ) + (mobile.Info.SubCellOffsets[mobile.__fromSubCell] + mobile.Info.SubCellOffsets[mobile.__toSubCell]) / 2, - Util.BetweenCells( mobile.toCell, nextCell.Value.First ) + (mobile.Info.SubCellOffsets[mobile.__toSubCell] + mobile.Info.SubCellOffsets[nextCell.Value.Second]) / 2, - mobile.Facing, - Util.GetNearestFacing( mobile.Facing, Util.GetFacing( nextCell.Value.First - mobile.toCell, mobile.Facing ) ), - moveFraction - moveFractionTotal ); - - mobile.SetLocation( mobile.toCell, mobile.__toSubCell, nextCell.Value.First, nextCell.Value.Second); - return ret; - } - else - parent.path.Add( nextCell.Value.First ); - } - var ret2 = new MoveSecondHalf( - move, - Util.BetweenCells( mobile.fromCell, mobile.toCell ) + (mobile.Info.SubCellOffsets[mobile.__fromSubCell] + mobile.Info.SubCellOffsets[mobile.__toSubCell]) / 2, - Util.CenterOfCell( mobile.toCell ) + mobile.Info.SubCellOffsets[mobile.__toSubCell], - mobile.Facing, - mobile.Facing, - moveFraction - moveFractionTotal ); - - mobile.SetLocation( mobile.toCell, mobile.__toSubCell, mobile.toCell, mobile.__toSubCell ); - return ret2; - } - } - - class MoveSecondHalf : MovePart - { - public MoveSecondHalf( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction ) - : base( move, from, to, fromFacing, toFacing, startingFraction ) - { - } - - protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent ) - { - mobile.PxPosition = Util.CenterOfCell( mobile.toCell ); - mobile.SetLocation( mobile.toCell, mobile.__toSubCell, mobile.toCell, mobile.__toSubCell ); - mobile.FinishedMoving(self); - return null; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.RA.Move +{ + class Move : CancelableActivity + { + int2? destination; + int nearEnough; + public List path; + Func> getPath; + public Actor ignoreBuilding; + + // Scriptable move order + // Ignores lane bias and nearby units + public Move( int2 destination ) + { + this.getPath = (self,mobile) => + self.World.WorldActor.Trait().FindPath( + PathSearch.FromPoint( self.World, mobile.Info, mobile.toCell, destination, false ) + .WithoutLaneBias()); + this.destination = destination; + this.nearEnough = 0; + } + + public Move( int2 destination, int nearEnough ) + { + this.getPath = (self,mobile) => self.World.WorldActor.Trait().FindUnitPath( mobile.toCell, destination, self ); + this.destination = destination; + this.nearEnough = nearEnough; + } + + public Move(int2 destination, Actor ignoreBuilding) + { + this.getPath = (self,mobile) => + self.World.WorldActor.Trait().FindPath( + PathSearch.FromPoint( self.World, mobile.Info, mobile.toCell, destination, false ) + .WithIgnoredBuilding( ignoreBuilding )); + + this.destination = destination; + this.nearEnough = 0; + this.ignoreBuilding = ignoreBuilding; + } + + public Move( Actor target, int range ) + { + this.getPath = (self,mobile) => self.World.WorldActor.Trait().FindUnitPathToRange( + mobile.toCell, target.Location, + range, self ); + this.destination = null; + this.nearEnough = range; + } + + public Move(Target target, int range) + { + this.getPath = (self,mobile) => self.World.WorldActor.Trait().FindUnitPathToRange( + mobile.toCell, Util.CellContaining(target.CenterLocation), + range, self); + this.destination = null; + this.nearEnough = range; + } + + public Move(Func> getPath) + { + this.getPath = (_1,_2) => getPath(); + this.destination = null; + this.nearEnough = 0; + } + + static int HashList(List xs) + { + int hash = 0; + int n = 0; + foreach (var x in xs) + hash += n++ * x.GetHashCode(); + + return hash; + } + + List EvalPath( Actor self, Mobile mobile ) + { + var path = getPath(self, mobile).TakeWhile(a => a != mobile.toCell).ToList(); + mobile.PathHash = HashList(path); + Log.Write("debug", "EvalPathHash #{0} {1}", + self.ActorID, mobile.PathHash); + return path; + } + + public override IActivity Tick( Actor self ) + { + var mobile = self.Trait(); + + if (destination == mobile.toCell) + return NextActivity; + + if( path == null ) + { + if (mobile.ticksBeforePathing > 0) + { + --mobile.ticksBeforePathing; + return this; + } + + path = EvalPath(self, mobile); + SanityCheckPath( mobile ); + } + + if( path.Count == 0 ) + { + destination = mobile.toCell; + return this; + } + + destination = path[ 0 ]; + + var nextCell = PopPath( self, mobile ); + if( nextCell == null ) + return this; + + int2 dir = nextCell.Value.First - mobile.fromCell; + var firstFacing = Util.GetFacing( dir, mobile.Facing ); + if( firstFacing != mobile.Facing ) + { + path.Add( nextCell.Value.First ); + return Util.SequenceActivities( new Turn( firstFacing ), this ); + } + else + { + mobile.SetLocation( mobile.fromCell, mobile.__fromSubCell, nextCell.Value.First, nextCell.Value.Second ); + var move = new MoveFirstHalf( + this, + Util.CenterOfCell( mobile.fromCell ) + mobile.Info.SubCellOffsets[mobile.__fromSubCell], + Util.BetweenCells( mobile.fromCell, mobile.toCell ) + (mobile.Info.SubCellOffsets[mobile.__fromSubCell] + mobile.Info.SubCellOffsets[mobile.__toSubCell] ) / 2, + mobile.Facing, + mobile.Facing, + 0 ); + + return move; + } + } + + [Conditional( "SANITY_CHECKS")] + void SanityCheckPath( Mobile mobile ) + { + if( path.Count == 0 ) + return; + var d = path[path.Count-1] - mobile.toCell; + if( d.LengthSquared > 2 ) + throw new InvalidOperationException( "(Move) Sanity check failed" ); + } + + bool hasWaited; + bool hasNudged; + int waitTicksRemaining; + + void NudgeBlocker(Actor self, int2 nextCell) + { + var blocker = self.World.WorldActor.Trait().GetUnitsAt(nextCell).FirstOrDefault(); + if (blocker == null) return; + + Log.Write("debug", "NudgeBlocker #{0} nudges #{1} at {2} from {3}", + self.ActorID, blocker.ActorID, nextCell, self.Location); + + var nudge = blocker.TraitOrDefault(); + if (nudge != null) + nudge.OnNudge(blocker, self); + } + + Pair? PopPath( Actor self, Mobile mobile ) + { + if( path.Count == 0 ) return null; + var nextCell = path[ path.Count - 1 ]; + if( !mobile.CanEnterCell( nextCell, ignoreBuilding, true ) ) + { + if( ( mobile.toCell - destination.Value ).LengthSquared <= nearEnough ) + { + path.Clear(); + return null; + } + + if (!hasNudged) + { + NudgeBlocker(self, nextCell); + hasNudged = true; + } + + if (!hasWaited) + { + var info = self.Info.Traits.Get(); + waitTicksRemaining = info.WaitAverage + self.World.SharedRandom.Next(-info.WaitSpread, info.WaitSpread); + hasWaited = true; + } + + if (--waitTicksRemaining >= 0) + return null; + + if (mobile.ticksBeforePathing > 0) + { + --mobile.ticksBeforePathing; + return null; + } + + mobile.RemoveInfluence(); + var newPath = EvalPath(self, mobile); + mobile.AddInfluence(); + + if (newPath.Count != 0) + path = newPath; + + return null; + } + hasNudged = false; + hasWaited = false; + path.RemoveAt( path.Count - 1 ); + + var subCell = mobile.GetDesiredSubcell(nextCell, ignoreBuilding); + return Pair.New(nextCell, subCell); + } + + protected override bool OnCancel( Actor self ) + { + path = new List(); + return true; + } + + public override IEnumerable GetCurrentPath() + { + if( path != null ) + return Enumerable.Reverse(path).Select( c => (float2)Util.CenterOfCell(c) ); + if( destination != null ) + return new float2[] { destination.Value }; + return new float2[ 0 ]; + } + + abstract class MovePart : IActivity + { + public readonly Move move; + public readonly int2 from, to; + public readonly int fromFacing, toFacing; + public int moveFraction; + public readonly int moveFractionTotal; + + public MovePart( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction ) + { + this.move = move; + this.from = from; + this.to = to; + this.fromFacing = fromFacing; + this.toFacing = toFacing; + this.moveFraction = startingFraction; + this.moveFractionTotal = ( ( to - from ) * 3 ).Length; + } + + public void Cancel( Actor self ) + { + move.Cancel( self ); + } + + public void Queue( IActivity activity ) + { + move.Queue( activity ); + } + + public IActivity Tick( Actor self ) + { + var mobile = self.Trait(); + var ret = InnerTick( self, mobile ); + mobile.IsMoving = ( ret is MovePart ); + + if( moveFraction > moveFractionTotal ) + moveFraction = moveFractionTotal; + UpdateCenterLocation( self, mobile ); + + return ret; + } + + IActivity InnerTick( Actor self, Mobile mobile ) + { + moveFraction += mobile.MovementSpeedForCell(self, mobile.toCell); + if( moveFraction <= moveFractionTotal ) + return this; + + var next = OnComplete( self, mobile, move ); + if( next != null ) + return next; + + return move; + } + + void UpdateCenterLocation( Actor self, Mobile mobile ) + { + mobile.PxPosition = int2.Lerp( from, to, moveFraction, moveFractionTotal ); + + if( moveFraction >= moveFractionTotal ) + mobile.Facing = toFacing & 0xFF; + else + mobile.Facing = int2.Lerp( fromFacing, toFacing, moveFraction, moveFractionTotal ) & 0xFF; + } + + protected abstract MovePart OnComplete( Actor self, Mobile mobile, Move parent ); + + public IEnumerable GetCurrentPath() + { + return move.GetCurrentPath(); + } + } + + class MoveFirstHalf : MovePart + { + public MoveFirstHalf( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction ) + : base( move, from, to, fromFacing, toFacing, startingFraction ) + { + } + + protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent ) + { + var nextCell = parent.PopPath( self, mobile ); + if( nextCell != null ) + { + if( ( nextCell.Value.First - mobile.toCell ) != ( mobile.toCell - mobile.fromCell ) ) + { + var ret = new MoveFirstHalf( + move, + Util.BetweenCells( mobile.fromCell, mobile.toCell ) + (mobile.Info.SubCellOffsets[mobile.__fromSubCell] + mobile.Info.SubCellOffsets[mobile.__toSubCell]) / 2, + Util.BetweenCells( mobile.toCell, nextCell.Value.First ) + (mobile.Info.SubCellOffsets[mobile.__toSubCell] + mobile.Info.SubCellOffsets[nextCell.Value.Second]) / 2, + mobile.Facing, + Util.GetNearestFacing( mobile.Facing, Util.GetFacing( nextCell.Value.First - mobile.toCell, mobile.Facing ) ), + moveFraction - moveFractionTotal ); + + mobile.SetLocation( mobile.toCell, mobile.__toSubCell, nextCell.Value.First, nextCell.Value.Second); + return ret; + } + else + parent.path.Add( nextCell.Value.First ); + } + var ret2 = new MoveSecondHalf( + move, + Util.BetweenCells( mobile.fromCell, mobile.toCell ) + (mobile.Info.SubCellOffsets[mobile.__fromSubCell] + mobile.Info.SubCellOffsets[mobile.__toSubCell]) / 2, + Util.CenterOfCell( mobile.toCell ) + mobile.Info.SubCellOffsets[mobile.__toSubCell], + mobile.Facing, + mobile.Facing, + moveFraction - moveFractionTotal ); + + mobile.SetLocation( mobile.toCell, mobile.__toSubCell, mobile.toCell, mobile.__toSubCell ); + return ret2; + } + } + + class MoveSecondHalf : MovePart + { + public MoveSecondHalf( Move move, int2 from, int2 to, int fromFacing, int toFacing, int startingFraction ) + : base( move, from, to, fromFacing, toFacing, startingFraction ) + { + } + + protected override MovePart OnComplete( Actor self, Mobile mobile, Move parent ) + { + mobile.PxPosition = Util.CenterOfCell( mobile.toCell ); + mobile.SetLocation( mobile.toCell, mobile.__toSubCell, mobile.toCell, mobile.__toSubCell ); + mobile.FinishedMoving(self); + return null; + } + } + } +} diff --git a/OpenRA.Mods.RA/Move/PathFinder.cs b/OpenRA.Mods.RA/Move/PathFinder.cs index c0cd354dea..5e2486cdbf 100755 --- a/OpenRA.Mods.RA/Move/PathFinder.cs +++ b/OpenRA.Mods.RA/Move/PathFinder.cs @@ -1,243 +1,243 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using OpenRA.Support; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Move -{ - public class PathFinderInfo : ITraitInfo - { - public object Create( ActorInitializer init ) { return new PathFinder( init.world ); } - } - - public class PathFinder - { - readonly World world; - public PathFinder( World world ) { this.world = world; } - - class CachedPath - { - public int2 from; - public int2 to; - public List result; - public int tick; - public Actor actor; - } - - List CachedPaths = new List(); - const int MaxPathAge = 50; /* x 40ms ticks */ - - public List FindUnitPath(int2 from, int2 target, Actor self) - { - using (new PerfSample("Pathfinder")) - { - var cached = CachedPaths.FirstOrDefault(p => p.from == from && p.to == target && p.actor == self); - if (cached != null) - { - Log.Write("debug", "Actor {0} asked for a path from {1} tick(s) ago", self.ActorID, world.FrameNumber - cached.tick); - cached.tick = world.FrameNumber; - return new List(cached.result); - } - - var mi = self.Info.Traits.Get(); - - var pb = FindBidiPath( - PathSearch.FromPoint(world, mi, target, from, true) - .WithCustomBlocker(AvoidUnitsNear(from, 4, self)), - PathSearch.FromPoint(world, mi, from, target, true) - .WithCustomBlocker(AvoidUnitsNear(from, 4, self)) - .InReverse()); - - CheckSanePath2(pb, from, target); - - CachedPaths.RemoveAll(p => world.FrameNumber - p.tick > MaxPathAge); - CachedPaths.Add(new CachedPath { from = from, to = target, actor = self, result = pb, tick = world.FrameNumber }); - return new List(pb); - } - } - - public List FindUnitPathToRange( int2 src, int2 target, int range, Actor self ) - { - using( new PerfSample( "Pathfinder" ) ) - { - var mi = self.Info.Traits.Get(); - var tilesInRange = world.FindTilesInCircle(target, range) - .Where( t => mi.CanEnterCell(self.World, t, null, true)); - - var path = FindBidiPath( - PathSearch.FromPoints(world, mi, tilesInRange, src, true) - .WithCustomBlocker(AvoidUnitsNear(src, 4, self)), - PathSearch.FromPoint(world, mi, src, target, true) - .WithCustomBlocker(AvoidUnitsNear(src, 4, self)) - .InReverse()); - - return path; - } - } - - public Func AvoidUnitsNear(int2 p, int dist, Actor self) - { - return q => - p != q && - ((p - q).LengthSquared < dist * dist) && - (world.WorldActor.Trait().GetUnitsAt(q).Any(a => a.Group != self.Group)); - } - - public List FindPath( PathSearch search ) - { - using (new PerfSample("Pathfinder")) - { - while (!search.queue.Empty) - { - var p = search.Expand( world ); - if (search.heuristic(p) == 0) - return MakePath(search.cellInfo, p); - } - - // no path exists - return new List(); - } - } - - static List MakePath( CellInfo[ , ] cellInfo, int2 destination ) - { - List ret = new List(); - int2 pathNode = destination; - - while( cellInfo[ pathNode.X, pathNode.Y ].Path != pathNode ) - { - ret.Add( pathNode ); - pathNode = cellInfo[ pathNode.X, pathNode.Y ].Path; - } - - ret.Add(pathNode); - CheckSanePath(ret); - return ret; - } - - - - public List FindBidiPath( /* searches from both ends toward each other */ - PathSearch fromSrc, - PathSearch fromDest) - { - using (new PerfSample("Pathfinder")) - { - while (!fromSrc.queue.Empty && !fromDest.queue.Empty) - { - /* make some progress on the first search */ - var p = fromSrc.Expand( world ); - - if (fromDest.cellInfo[p.X, p.Y].Seen && fromDest.cellInfo[p.X, p.Y].MinCost < float.PositiveInfinity) - return MakeBidiPath(fromSrc, fromDest, p); - - /* make some progress on the second search */ - var q = fromDest.Expand( world ); - - if (fromSrc.cellInfo[q.X, q.Y].Seen && fromSrc.cellInfo[q.X, q.Y].MinCost < float.PositiveInfinity) - return MakeBidiPath(fromSrc, fromDest, q); - } - - return new List(); - } - } - - static List MakeBidiPath(PathSearch a, PathSearch b, int2 p) - { - var ca = a.cellInfo; - var cb = b.cellInfo; - - var ret = new List(); - - var q = p; - while (ca[q.X, q.Y].Path != q) - { - ret.Add( q ); - q = ca[ q.X, q.Y ].Path; - } - ret.Add(q); - - ret.Reverse(); - - q = p; - while (cb[q.X, q.Y].Path != q) - { - q = cb[q.X, q.Y].Path; - ret.Add(q); - } - - CheckSanePath( ret ); - return ret; - } - - [Conditional( "SANITY_CHECKS" )] - static void CheckSanePath( List path ) - { - if( path.Count == 0 ) - return; - var prev = path[ 0 ]; - for( int i = 0 ; i < path.Count ; i++ ) - { - var d = path[ i ] - prev; - if( Math.Abs( d.X ) > 1 || Math.Abs( d.Y ) > 1 ) - throw new InvalidOperationException( "(PathFinder) path sanity check failed" ); - prev = path[ i ]; - } - } - - [Conditional("SANITY_CHECKS")] - static void CheckSanePath2(List path, int2 src, int2 dest) - { - if (path.Count == 0) - return; - - if (path[0] != dest) - throw new InvalidOperationException("(PathFinder) sanity check failed: doesn't go to dest"); - if (path[path.Count - 1] != src) - throw new InvalidOperationException("(PathFinder) sanity check failed: doesn't come from src"); - } - } - - public struct CellInfo - { - public int MinCost; - public int2 Path; - public bool Seen; - - public CellInfo( int minCost, int2 path, bool seen ) - { - MinCost = minCost; - Path = path; - Seen = seen; - } - } - - public struct PathDistance : IComparable - { - public int EstTotal; - public int2 Location; - - public PathDistance(int estTotal, int2 location) - { - EstTotal = estTotal; - Location = location; - } - - public int CompareTo(PathDistance other) - { - return Math.Sign(EstTotal - other.EstTotal); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using OpenRA.Support; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Move +{ + public class PathFinderInfo : ITraitInfo + { + public object Create( ActorInitializer init ) { return new PathFinder( init.world ); } + } + + public class PathFinder + { + readonly World world; + public PathFinder( World world ) { this.world = world; } + + class CachedPath + { + public int2 from; + public int2 to; + public List result; + public int tick; + public Actor actor; + } + + List CachedPaths = new List(); + const int MaxPathAge = 50; /* x 40ms ticks */ + + public List FindUnitPath(int2 from, int2 target, Actor self) + { + using (new PerfSample("Pathfinder")) + { + var cached = CachedPaths.FirstOrDefault(p => p.from == from && p.to == target && p.actor == self); + if (cached != null) + { + Log.Write("debug", "Actor {0} asked for a path from {1} tick(s) ago", self.ActorID, world.FrameNumber - cached.tick); + cached.tick = world.FrameNumber; + return new List(cached.result); + } + + var mi = self.Info.Traits.Get(); + + var pb = FindBidiPath( + PathSearch.FromPoint(world, mi, target, from, true) + .WithCustomBlocker(AvoidUnitsNear(from, 4, self)), + PathSearch.FromPoint(world, mi, from, target, true) + .WithCustomBlocker(AvoidUnitsNear(from, 4, self)) + .InReverse()); + + CheckSanePath2(pb, from, target); + + CachedPaths.RemoveAll(p => world.FrameNumber - p.tick > MaxPathAge); + CachedPaths.Add(new CachedPath { from = from, to = target, actor = self, result = pb, tick = world.FrameNumber }); + return new List(pb); + } + } + + public List FindUnitPathToRange( int2 src, int2 target, int range, Actor self ) + { + using( new PerfSample( "Pathfinder" ) ) + { + var mi = self.Info.Traits.Get(); + var tilesInRange = world.FindTilesInCircle(target, range) + .Where( t => mi.CanEnterCell(self.World, t, null, true)); + + var path = FindBidiPath( + PathSearch.FromPoints(world, mi, tilesInRange, src, true) + .WithCustomBlocker(AvoidUnitsNear(src, 4, self)), + PathSearch.FromPoint(world, mi, src, target, true) + .WithCustomBlocker(AvoidUnitsNear(src, 4, self)) + .InReverse()); + + return path; + } + } + + public Func AvoidUnitsNear(int2 p, int dist, Actor self) + { + return q => + p != q && + ((p - q).LengthSquared < dist * dist) && + (world.WorldActor.Trait().GetUnitsAt(q).Any(a => a.Group != self.Group)); + } + + public List FindPath( PathSearch search ) + { + using (new PerfSample("Pathfinder")) + { + while (!search.queue.Empty) + { + var p = search.Expand( world ); + if (search.heuristic(p) == 0) + return MakePath(search.cellInfo, p); + } + + // no path exists + return new List(); + } + } + + static List MakePath( CellInfo[ , ] cellInfo, int2 destination ) + { + List ret = new List(); + int2 pathNode = destination; + + while( cellInfo[ pathNode.X, pathNode.Y ].Path != pathNode ) + { + ret.Add( pathNode ); + pathNode = cellInfo[ pathNode.X, pathNode.Y ].Path; + } + + ret.Add(pathNode); + CheckSanePath(ret); + return ret; + } + + + + public List FindBidiPath( /* searches from both ends toward each other */ + PathSearch fromSrc, + PathSearch fromDest) + { + using (new PerfSample("Pathfinder")) + { + while (!fromSrc.queue.Empty && !fromDest.queue.Empty) + { + /* make some progress on the first search */ + var p = fromSrc.Expand( world ); + + if (fromDest.cellInfo[p.X, p.Y].Seen && fromDest.cellInfo[p.X, p.Y].MinCost < float.PositiveInfinity) + return MakeBidiPath(fromSrc, fromDest, p); + + /* make some progress on the second search */ + var q = fromDest.Expand( world ); + + if (fromSrc.cellInfo[q.X, q.Y].Seen && fromSrc.cellInfo[q.X, q.Y].MinCost < float.PositiveInfinity) + return MakeBidiPath(fromSrc, fromDest, q); + } + + return new List(); + } + } + + static List MakeBidiPath(PathSearch a, PathSearch b, int2 p) + { + var ca = a.cellInfo; + var cb = b.cellInfo; + + var ret = new List(); + + var q = p; + while (ca[q.X, q.Y].Path != q) + { + ret.Add( q ); + q = ca[ q.X, q.Y ].Path; + } + ret.Add(q); + + ret.Reverse(); + + q = p; + while (cb[q.X, q.Y].Path != q) + { + q = cb[q.X, q.Y].Path; + ret.Add(q); + } + + CheckSanePath( ret ); + return ret; + } + + [Conditional( "SANITY_CHECKS" )] + static void CheckSanePath( List path ) + { + if( path.Count == 0 ) + return; + var prev = path[ 0 ]; + for( int i = 0 ; i < path.Count ; i++ ) + { + var d = path[ i ] - prev; + if( Math.Abs( d.X ) > 1 || Math.Abs( d.Y ) > 1 ) + throw new InvalidOperationException( "(PathFinder) path sanity check failed" ); + prev = path[ i ]; + } + } + + [Conditional("SANITY_CHECKS")] + static void CheckSanePath2(List path, int2 src, int2 dest) + { + if (path.Count == 0) + return; + + if (path[0] != dest) + throw new InvalidOperationException("(PathFinder) sanity check failed: doesn't go to dest"); + if (path[path.Count - 1] != src) + throw new InvalidOperationException("(PathFinder) sanity check failed: doesn't come from src"); + } + } + + public struct CellInfo + { + public int MinCost; + public int2 Path; + public bool Seen; + + public CellInfo( int minCost, int2 path, bool seen ) + { + MinCost = minCost; + Path = path; + Seen = seen; + } + } + + public struct PathDistance : IComparable + { + public int EstTotal; + public int2 Location; + + public PathDistance(int estTotal, int2 location) + { + EstTotal = estTotal; + Location = location; + } + + public int CompareTo(PathDistance other) + { + return Math.Sign(EstTotal - other.EstTotal); + } + } +} diff --git a/OpenRA.Mods.RA/Move/PathSearch.cs b/OpenRA.Mods.RA/Move/PathSearch.cs index 78ac52cc63..e1fb26d679 100755 --- a/OpenRA.Mods.RA/Move/PathSearch.cs +++ b/OpenRA.Mods.RA/Move/PathSearch.cs @@ -1,216 +1,216 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Move -{ - public class PathSearch - { - World world; - public CellInfo[ , ] cellInfo; - public PriorityQueue queue; - public Func heuristic; - Func customBlock; - public bool checkForBlocked; - public Actor ignoreBuilding; - public bool inReverse; - - MobileInfo mobileInfo; - UnitInfluence uim; - - public PathSearch(World world, MobileInfo mobileInfo) - { - this.world = world; - uim = world.WorldActor.Trait(); - cellInfo = InitCellInfo(); - this.mobileInfo = mobileInfo; - queue = new PriorityQueue(); - } - - public PathSearch InReverse() - { - inReverse = true; - return this; - } - - public PathSearch WithCustomBlocker(Func customBlock) - { - this.customBlock = customBlock; - return this; - } - - public PathSearch WithIgnoredBuilding(Actor b) - { - ignoreBuilding = b; - return this; - } - - public PathSearch WithHeuristic(Func h) - { - heuristic = h; - return this; - } - - public PathSearch WithoutLaneBias() - { - LaneBias = 0; - return this; - } - - public PathSearch FromPoint(int2 from) - { - AddInitialCell( from ); - return this; - } - - int LaneBias = 1; - - public int2 Expand( World world ) - { - var p = queue.Pop(); - while (cellInfo[p.Location.X, p.Location.Y].Seen) - if (queue.Empty) - return p.Location; - else - p = queue.Pop(); - - cellInfo[p.Location.X, p.Location.Y].Seen = true; - - var thisCost = mobileInfo.MovementCostForCell(world, p.Location); - - if (thisCost == int.MaxValue) - return p.Location; - - foreach( int2 d in directions ) - { - int2 newHere = p.Location + d; - - if (!world.Map.IsInMap(newHere.X, newHere.Y)) continue; - if( cellInfo[ newHere.X, newHere.Y ].Seen ) - continue; - - var costHere = mobileInfo.MovementCostForCell(world, newHere); - - if (costHere == int.MaxValue) - continue; - - if (!mobileInfo.CanEnterCell(world, uim, newHere, ignoreBuilding, checkForBlocked)) - continue; - - if (customBlock != null && customBlock(newHere)) - continue; - - var est = heuristic( newHere ); - if( est == int.MaxValue ) - continue; - - int cellCost = costHere; - if( d.X * d.Y != 0 ) cellCost = ( cellCost * 34 ) / 24; - - // directional bonuses for smoother flow! - var ux = (newHere.X + (inReverse ? 1 : 0) & 1); - var uy = (newHere.Y + (inReverse ? 1 : 0) & 1); - - if (ux == 0 && d.Y < 0) cellCost += LaneBias; - else if (ux == 1 && d.Y > 0) cellCost += LaneBias; - if (uy == 0 && d.X < 0) cellCost += LaneBias; - else if (uy == 1 && d.X > 0) cellCost += LaneBias; - - int newCost = cellInfo[ p.Location.X, p.Location.Y ].MinCost + cellCost; - - if( newCost >= cellInfo[ newHere.X, newHere.Y ].MinCost ) - continue; - - cellInfo[ newHere.X, newHere.Y ].Path = p.Location; - cellInfo[ newHere.X, newHere.Y ].MinCost = newCost; - - queue.Add( new PathDistance( newCost + est, newHere ) ); - - } - return p.Location; - } - - static readonly int2[] directions = - { - new int2( -1, -1 ), - new int2( -1, 0 ), - new int2( -1, 1 ), - new int2( 0, -1 ), - new int2( 0, 1 ), - new int2( 1, -1 ), - new int2( 1, 0 ), - new int2( 1, 1 ), - }; - - public void AddInitialCell( int2 location ) - { - if (!world.Map.IsInMap(location.X, location.Y)) - return; - - cellInfo[ location.X, location.Y ] = new CellInfo( 0, location, false ); - queue.Add( new PathDistance( heuristic( location ), location ) ); - } - - public static PathSearch Search( World world, MobileInfo mi, bool checkForBlocked ) - { - var search = new PathSearch(world, mi) { - checkForBlocked = checkForBlocked }; - return search; - } - - public static PathSearch FromPoint( World world, MobileInfo mi, int2 from, int2 target, bool checkForBlocked ) - { - var search = new PathSearch(world, mi) { - heuristic = DefaultEstimator( target ), - checkForBlocked = checkForBlocked }; - - search.AddInitialCell( from ); - return search; - } - - public static PathSearch FromPoints(World world, MobileInfo mi, IEnumerable froms, int2 target, bool checkForBlocked) - { - var search = new PathSearch(world, mi) - { - heuristic = DefaultEstimator(target), - checkForBlocked = checkForBlocked - }; - - foreach( var sl in froms ) - search.AddInitialCell( sl ); - - return search; - } - - CellInfo[ , ] InitCellInfo() - { - var cellInfo = new CellInfo[ world.Map.MapSize.X, world.Map.MapSize.Y ]; - for( int x = 0 ; x < world.Map.MapSize.X ; x++ ) - for( int y = 0 ; y < world.Map.MapSize.Y ; y++ ) - cellInfo[ x, y ] = new CellInfo( int.MaxValue, new int2( x, y ), false ); - return cellInfo; - } - - public static Func DefaultEstimator( int2 destination ) - { - return here => - { - int2 d = ( here - destination ).Abs(); - int diag = Math.Min( d.X, d.Y ); - int straight = Math.Abs( d.X - d.Y ); - return (3400 * diag / 24) + (100 * straight); - }; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Move +{ + public class PathSearch + { + World world; + public CellInfo[ , ] cellInfo; + public PriorityQueue queue; + public Func heuristic; + Func customBlock; + public bool checkForBlocked; + public Actor ignoreBuilding; + public bool inReverse; + + MobileInfo mobileInfo; + UnitInfluence uim; + + public PathSearch(World world, MobileInfo mobileInfo) + { + this.world = world; + uim = world.WorldActor.Trait(); + cellInfo = InitCellInfo(); + this.mobileInfo = mobileInfo; + queue = new PriorityQueue(); + } + + public PathSearch InReverse() + { + inReverse = true; + return this; + } + + public PathSearch WithCustomBlocker(Func customBlock) + { + this.customBlock = customBlock; + return this; + } + + public PathSearch WithIgnoredBuilding(Actor b) + { + ignoreBuilding = b; + return this; + } + + public PathSearch WithHeuristic(Func h) + { + heuristic = h; + return this; + } + + public PathSearch WithoutLaneBias() + { + LaneBias = 0; + return this; + } + + public PathSearch FromPoint(int2 from) + { + AddInitialCell( from ); + return this; + } + + int LaneBias = 1; + + public int2 Expand( World world ) + { + var p = queue.Pop(); + while (cellInfo[p.Location.X, p.Location.Y].Seen) + if (queue.Empty) + return p.Location; + else + p = queue.Pop(); + + cellInfo[p.Location.X, p.Location.Y].Seen = true; + + var thisCost = mobileInfo.MovementCostForCell(world, p.Location); + + if (thisCost == int.MaxValue) + return p.Location; + + foreach( int2 d in directions ) + { + int2 newHere = p.Location + d; + + if (!world.Map.IsInMap(newHere.X, newHere.Y)) continue; + if( cellInfo[ newHere.X, newHere.Y ].Seen ) + continue; + + var costHere = mobileInfo.MovementCostForCell(world, newHere); + + if (costHere == int.MaxValue) + continue; + + if (!mobileInfo.CanEnterCell(world, uim, newHere, ignoreBuilding, checkForBlocked)) + continue; + + if (customBlock != null && customBlock(newHere)) + continue; + + var est = heuristic( newHere ); + if( est == int.MaxValue ) + continue; + + int cellCost = costHere; + if( d.X * d.Y != 0 ) cellCost = ( cellCost * 34 ) / 24; + + // directional bonuses for smoother flow! + var ux = (newHere.X + (inReverse ? 1 : 0) & 1); + var uy = (newHere.Y + (inReverse ? 1 : 0) & 1); + + if (ux == 0 && d.Y < 0) cellCost += LaneBias; + else if (ux == 1 && d.Y > 0) cellCost += LaneBias; + if (uy == 0 && d.X < 0) cellCost += LaneBias; + else if (uy == 1 && d.X > 0) cellCost += LaneBias; + + int newCost = cellInfo[ p.Location.X, p.Location.Y ].MinCost + cellCost; + + if( newCost >= cellInfo[ newHere.X, newHere.Y ].MinCost ) + continue; + + cellInfo[ newHere.X, newHere.Y ].Path = p.Location; + cellInfo[ newHere.X, newHere.Y ].MinCost = newCost; + + queue.Add( new PathDistance( newCost + est, newHere ) ); + + } + return p.Location; + } + + static readonly int2[] directions = + { + new int2( -1, -1 ), + new int2( -1, 0 ), + new int2( -1, 1 ), + new int2( 0, -1 ), + new int2( 0, 1 ), + new int2( 1, -1 ), + new int2( 1, 0 ), + new int2( 1, 1 ), + }; + + public void AddInitialCell( int2 location ) + { + if (!world.Map.IsInMap(location.X, location.Y)) + return; + + cellInfo[ location.X, location.Y ] = new CellInfo( 0, location, false ); + queue.Add( new PathDistance( heuristic( location ), location ) ); + } + + public static PathSearch Search( World world, MobileInfo mi, bool checkForBlocked ) + { + var search = new PathSearch(world, mi) { + checkForBlocked = checkForBlocked }; + return search; + } + + public static PathSearch FromPoint( World world, MobileInfo mi, int2 from, int2 target, bool checkForBlocked ) + { + var search = new PathSearch(world, mi) { + heuristic = DefaultEstimator( target ), + checkForBlocked = checkForBlocked }; + + search.AddInitialCell( from ); + return search; + } + + public static PathSearch FromPoints(World world, MobileInfo mi, IEnumerable froms, int2 target, bool checkForBlocked) + { + var search = new PathSearch(world, mi) + { + heuristic = DefaultEstimator(target), + checkForBlocked = checkForBlocked + }; + + foreach( var sl in froms ) + search.AddInitialCell( sl ); + + return search; + } + + CellInfo[ , ] InitCellInfo() + { + var cellInfo = new CellInfo[ world.Map.MapSize.X, world.Map.MapSize.Y ]; + for( int x = 0 ; x < world.Map.MapSize.X ; x++ ) + for( int y = 0 ; y < world.Map.MapSize.Y ; y++ ) + cellInfo[ x, y ] = new CellInfo( int.MaxValue, new int2( x, y ), false ); + return cellInfo; + } + + public static Func DefaultEstimator( int2 destination ) + { + return here => + { + int2 d = ( here - destination ).Abs(); + int diag = Math.Min( d.X, d.Y ); + int straight = Math.Abs( d.X - d.Y ); + return (3400 * diag / 24) + (100 * straight); + }; + } + } +} diff --git a/OpenRA.Mods.RA/NukePaletteEffect.cs b/OpenRA.Mods.RA/NukePaletteEffect.cs index f47f37e33c..195e3a3c02 100644 --- a/OpenRA.Mods.RA/NukePaletteEffect.cs +++ b/OpenRA.Mods.RA/NukePaletteEffect.cs @@ -1,18 +1,18 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using OpenRA.FileFormats; -using OpenRA.Traits; - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using OpenRA.FileFormats; +using OpenRA.Traits; + namespace OpenRA.Mods.RA { class NukePaletteEffectInfo : TraitInfo { } @@ -33,25 +33,25 @@ namespace OpenRA.Mods.RA remainingFrames--; } - public void AdjustPalette(Dictionary palettes) + public void AdjustPalette(Dictionary palettes) { if (remainingFrames == 0) return; var frac = (float)remainingFrames / nukeEffectLength; - - var excludePalettes = new List(){"cursor", "chrome", "colorpicker", "shroud", "fog"}; - foreach (var pal in palettes) - { - if (excludePalettes.Contains(pal.Key)) - continue; - - for (var x = 0; x < 256; x++) - { - var orig = pal.Value.GetColor(x); - var white = Color.FromArgb(orig.A, 255, 255, 255); - pal.Value.SetColor(x, OpenRA.Graphics.Util.Lerp(frac,orig,white)); - } + + var excludePalettes = new List(){"cursor", "chrome", "colorpicker", "shroud", "fog"}; + foreach (var pal in palettes) + { + if (excludePalettes.Contains(pal.Key)) + continue; + + for (var x = 0; x < 256; x++) + { + var orig = pal.Value.GetColor(x); + var white = Color.FromArgb(orig.A, 255, 255, 255); + pal.Value.SetColor(x, OpenRA.Graphics.Util.Lerp(frac,orig,white)); + } } } } diff --git a/OpenRA.Mods.RA/NullLoadScreen.cs b/OpenRA.Mods.RA/NullLoadScreen.cs index 43b9a7ddc6..963e983055 100644 --- a/OpenRA.Mods.RA/NullLoadScreen.cs +++ b/OpenRA.Mods.RA/NullLoadScreen.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion @@ -19,9 +19,9 @@ namespace OpenRA.Mods.RA return; // Draw a black screen - Game.Renderer.BeginFrame(float2.Zero); + Game.Renderer.BeginFrame(float2.Zero); Game.Renderer.EndFrame( new NullInputHandler() ); - } + } } } diff --git a/OpenRA.Mods.RA/OpenWidgetAtGameStart.cs b/OpenRA.Mods.RA/OpenWidgetAtGameStart.cs index f91ab3542b..f094e4aa86 100644 --- a/OpenRA.Mods.RA/OpenWidgetAtGameStart.cs +++ b/OpenRA.Mods.RA/OpenWidgetAtGameStart.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion @@ -15,7 +15,7 @@ namespace OpenRA.Mods.RA { public class OpenWidgetAtGameStartInfo : ITraitInfo { - public readonly string Widget = "INGAME_ROOT"; + public readonly string Widget = "INGAME_ROOT"; public readonly string ObserverWidget = null; public object Create(ActorInitializer init) { return new OpenWidgetAtGameStart(this); } @@ -35,8 +35,8 @@ namespace OpenRA.Mods.RA Widget.RootWidget.Children.Clear(); if (world.LocalPlayer != null) - Game.OpenWindow(world, Info.Widget); - else if (Info.ObserverWidget != null) + Game.OpenWindow(world, Info.Widget); + else if (Info.ObserverWidget != null) Game.OpenWindow(world, Info.ObserverWidget); } } diff --git a/OpenRA.Mods.RA/Orders/EnterBuildingOrderTargeter.cs b/OpenRA.Mods.RA/Orders/EnterBuildingOrderTargeter.cs index 9d94f296ae..fc2b7f33e7 100755 --- a/OpenRA.Mods.RA/Orders/EnterBuildingOrderTargeter.cs +++ b/OpenRA.Mods.RA/Orders/EnterBuildingOrderTargeter.cs @@ -1,37 +1,37 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; - -namespace OpenRA.Mods.RA.Orders -{ - public class EnterOrderTargeter : UnitTraitOrderTargeter - { - readonly Func canTarget; - readonly Func useEnterCursor; - - public EnterOrderTargeter( string order, int priority, bool targetEnemy, bool targetAlly, - Func canTarget, Func useEnterCursor ) - : base( order, priority, "enter", targetEnemy, targetAlly ) - { - this.canTarget = canTarget; - this.useEnterCursor = useEnterCursor; - } - - public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - if( !base.CanTargetActor( self, target, forceAttack, forceMove, forceQueued, ref cursor ) ) return false; - if( !canTarget( target ) ) return false; - cursor = useEnterCursor(target) ? "enter" : "enter-blocked"; - IsQueued = forceQueued; - return true; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; + +namespace OpenRA.Mods.RA.Orders +{ + public class EnterOrderTargeter : UnitTraitOrderTargeter + { + readonly Func canTarget; + readonly Func useEnterCursor; + + public EnterOrderTargeter( string order, int priority, bool targetEnemy, bool targetAlly, + Func canTarget, Func useEnterCursor ) + : base( order, priority, "enter", targetEnemy, targetAlly ) + { + this.canTarget = canTarget; + this.useEnterCursor = useEnterCursor; + } + + public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + if( !base.CanTargetActor( self, target, forceAttack, forceMove, forceQueued, ref cursor ) ) return false; + if( !canTarget( target ) ) return false; + cursor = useEnterCursor(target) ? "enter" : "enter-blocked"; + IsQueued = forceQueued; + return true; + } + } +} diff --git a/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs b/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs index 83f2d12fed..3f863d265a 100755 --- a/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs @@ -1,104 +1,104 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Orders -{ - public class PlaceBuildingOrderGenerator : IOrderGenerator - { - readonly Actor Producer; - readonly string Building; - readonly IEnumerable Preview; - BuildingInfo BuildingInfo { get { return Rules.Info[ Building ].Traits.Get(); } } - - public PlaceBuildingOrderGenerator(Actor producer, string name) - { - Producer = producer; - Building = name; - - Preview = Rules.Info[Building].Traits.Get() - .RenderPreview(Rules.Info[Building], producer.World.Map.Tileset); - } - - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Right) - world.CancelInputMode(); - - var ret = InnerOrder( world, xy, mi ).ToList(); - if (ret.Count > 0) - world.CancelInputMode(); - - return ret; - } - - IEnumerable InnerOrder(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Left) - { - var topLeft = xy - FootprintUtils.AdjustForBuildingSize( BuildingInfo ); - if (!world.CanPlaceBuilding( Building, BuildingInfo, topLeft, null) - || !BuildingInfo.IsCloseEnoughToBase(world, Producer.Owner, Building, topLeft)) - { - var eva = world.WorldActor.Info.Traits.Get(); - Sound.Play(eva.BuildingCannotPlaceAudio); - yield break; - } - - var isLineBuild = Rules.Info[ Building ].Traits.Contains(); - yield return new Order(isLineBuild ? "LineBuild" : "PlaceBuilding", - Producer.Owner.PlayerActor, false) { TargetLocation = topLeft, TargetString = Building }; - } - } - - public void Tick( World world ) {} - public void RenderAfterWorld( WorldRenderer wr, World world ) {} - public void RenderBeforeWorld( WorldRenderer wr, World world ) - { - var position = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); - var topLeft = position - FootprintUtils.AdjustForBuildingSize( BuildingInfo ); - - var actorInfo = Rules.Info[Building]; - foreach (var dec in actorInfo.Traits.WithInterface()) - dec.Render(wr, world, actorInfo, Traits.Util.CenterOfCell(position)); /* hack hack */ - - var cells = new Dictionary(); - // Linebuild for walls. - // Assumes a 1x1 footprint; weird things will happen for other footprints - if (Rules.Info[Building].Traits.Contains()) - { - foreach( var t in BuildingUtils.GetLineBuildCells( world, topLeft, Building, BuildingInfo ) ) - cells.Add( t, BuildingInfo.IsCloseEnoughToBase( world, world.LocalPlayer, Building, t ) ); - } - else - { - foreach (var r in Preview) - r.Sprite.DrawAt(Game.CellSize*topLeft + r.Pos, - wr.GetPaletteIndex(r.Palette ?? world.LocalPlayer.Palette), - r.Scale*r.Sprite.size); - - var res = world.WorldActor.Trait(); - var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft); - foreach (var t in FootprintUtils.Tiles(Building, BuildingInfo, topLeft)) - cells.Add( t, isCloseEnough && world.IsCellBuildable(t, BuildingInfo.WaterBound) && res.GetResource(t) == null ); - } - - wr.uiOverlay.DrawGrid( wr, cells ); - } - - public string GetCursor(World world, int2 xy, MouseInput mi) { return "default"; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Orders +{ + public class PlaceBuildingOrderGenerator : IOrderGenerator + { + readonly Actor Producer; + readonly string Building; + readonly IEnumerable Preview; + BuildingInfo BuildingInfo { get { return Rules.Info[ Building ].Traits.Get(); } } + + public PlaceBuildingOrderGenerator(Actor producer, string name) + { + Producer = producer; + Building = name; + + Preview = Rules.Info[Building].Traits.Get() + .RenderPreview(Rules.Info[Building], producer.World.Map.Tileset); + } + + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Right) + world.CancelInputMode(); + + var ret = InnerOrder( world, xy, mi ).ToList(); + if (ret.Count > 0) + world.CancelInputMode(); + + return ret; + } + + IEnumerable InnerOrder(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Left) + { + var topLeft = xy - FootprintUtils.AdjustForBuildingSize( BuildingInfo ); + if (!world.CanPlaceBuilding( Building, BuildingInfo, topLeft, null) + || !BuildingInfo.IsCloseEnoughToBase(world, Producer.Owner, Building, topLeft)) + { + var eva = world.WorldActor.Info.Traits.Get(); + Sound.Play(eva.BuildingCannotPlaceAudio); + yield break; + } + + var isLineBuild = Rules.Info[ Building ].Traits.Contains(); + yield return new Order(isLineBuild ? "LineBuild" : "PlaceBuilding", + Producer.Owner.PlayerActor, false) { TargetLocation = topLeft, TargetString = Building }; + } + } + + public void Tick( World world ) {} + public void RenderAfterWorld( WorldRenderer wr, World world ) {} + public void RenderBeforeWorld( WorldRenderer wr, World world ) + { + var position = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); + var topLeft = position - FootprintUtils.AdjustForBuildingSize( BuildingInfo ); + + var actorInfo = Rules.Info[Building]; + foreach (var dec in actorInfo.Traits.WithInterface()) + dec.Render(wr, world, actorInfo, Traits.Util.CenterOfCell(position)); /* hack hack */ + + var cells = new Dictionary(); + // Linebuild for walls. + // Assumes a 1x1 footprint; weird things will happen for other footprints + if (Rules.Info[Building].Traits.Contains()) + { + foreach( var t in BuildingUtils.GetLineBuildCells( world, topLeft, Building, BuildingInfo ) ) + cells.Add( t, BuildingInfo.IsCloseEnoughToBase( world, world.LocalPlayer, Building, t ) ); + } + else + { + foreach (var r in Preview) + r.Sprite.DrawAt(Game.CellSize*topLeft + r.Pos, + wr.GetPaletteIndex(r.Palette ?? world.LocalPlayer.Palette), + r.Scale*r.Sprite.size); + + var res = world.WorldActor.Trait(); + var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft); + foreach (var t in FootprintUtils.Tiles(Building, BuildingInfo, topLeft)) + cells.Add( t, isCloseEnough && world.IsCellBuildable(t, BuildingInfo.WaterBound) && res.GetResource(t) == null ); + } + + wr.uiOverlay.DrawGrid( wr, cells ); + } + + public string GetCursor(World world, int2 xy, MouseInput mi) { return "default"; } + } +} diff --git a/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs b/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs index d98919827f..d281327746 100755 --- a/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/PowerDownOrderGenerator.cs @@ -1,53 +1,53 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; - -namespace OpenRA.Mods.RA.Orders -{ - class PowerDownOrderGenerator : IOrderGenerator - { - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Right) - world.CancelInputMode(); - - return OrderInner(world, xy, mi); - } - - IEnumerable OrderInner(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Left) - { - var underCursor = world.FindUnitsAtMouse(mi.Location) - .Where(a => a.Owner == world.LocalPlayer - && a.HasTrait()) - .FirstOrDefault(); - - if (underCursor != null) - yield return new Order("PowerDown", underCursor, false); - } - } - - public void Tick(World world) { } - public void RenderAfterWorld(WorldRenderer wr, World world) { } - public void RenderBeforeWorld(WorldRenderer wr, World world) { } - - public string GetCursor(World world, int2 xy, MouseInput mi) - { - mi.Button = MouseButton.Left; - return OrderInner(world, xy, mi).Any() - ? "powerdown" : "powerdown-blocked"; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Buildings; + +namespace OpenRA.Mods.RA.Orders +{ + class PowerDownOrderGenerator : IOrderGenerator + { + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Right) + world.CancelInputMode(); + + return OrderInner(world, xy, mi); + } + + IEnumerable OrderInner(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Left) + { + var underCursor = world.FindUnitsAtMouse(mi.Location) + .Where(a => a.Owner == world.LocalPlayer + && a.HasTrait()) + .FirstOrDefault(); + + if (underCursor != null) + yield return new Order("PowerDown", underCursor, false); + } + } + + public void Tick(World world) { } + public void RenderAfterWorld(WorldRenderer wr, World world) { } + public void RenderBeforeWorld(WorldRenderer wr, World world) { } + + public string GetCursor(World world, int2 xy, MouseInput mi) + { + mi.Button = MouseButton.Left; + return OrderInner(world, xy, mi).Any() + ? "powerdown" : "powerdown-blocked"; + } + } +} diff --git a/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs b/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs index 73a9b16f60..dc21c2b583 100644 --- a/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/RepairOrderGenerator.cs @@ -1,66 +1,66 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Orders -{ - class RepairOrderGenerator : IOrderGenerator - { - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Right) - world.CancelInputMode(); - - return OrderInner(world, xy, mi); - } - - IEnumerable OrderInner(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Left) - { - var underCursor = world.FindUnitsAtMouse(mi.Location) - .Where(a => a.Owner == world.LocalPlayer && a.HasTrait()).FirstOrDefault(); - - if (underCursor == null) - yield break; - - if (underCursor.Info.Traits.Contains() - && underCursor.GetDamageState() > DamageState.Undamaged) - yield return new Order("Repair", underCursor, false); - } - } - - public void Tick( World world ) - { - if( !PlayerIsAllowedToRepair( world ) ) - world.CancelInputMode(); - } - - public static bool PlayerIsAllowedToRepair( World world ) - { - return world.Queries.OwnedBy[ world.LocalPlayer ].WithTrait().Any(); - } - - public void RenderAfterWorld( WorldRenderer wr, World world ) { } - public void RenderBeforeWorld( WorldRenderer wr, World world ) { } - - public string GetCursor(World world, int2 xy, MouseInput mi) - { - mi.Button = MouseButton.Left; - return OrderInner(world, xy, mi).Any() - ? "repair" : "repair-blocked"; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Orders +{ + class RepairOrderGenerator : IOrderGenerator + { + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Right) + world.CancelInputMode(); + + return OrderInner(world, xy, mi); + } + + IEnumerable OrderInner(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Left) + { + var underCursor = world.FindUnitsAtMouse(mi.Location) + .Where(a => a.Owner == world.LocalPlayer && a.HasTrait()).FirstOrDefault(); + + if (underCursor == null) + yield break; + + if (underCursor.Info.Traits.Contains() + && underCursor.GetDamageState() > DamageState.Undamaged) + yield return new Order("Repair", underCursor, false); + } + } + + public void Tick( World world ) + { + if( !PlayerIsAllowedToRepair( world ) ) + world.CancelInputMode(); + } + + public static bool PlayerIsAllowedToRepair( World world ) + { + return world.Queries.OwnedBy[ world.LocalPlayer ].WithTrait().Any(); + } + + public void RenderAfterWorld( WorldRenderer wr, World world ) { } + public void RenderBeforeWorld( WorldRenderer wr, World world ) { } + + public string GetCursor(World world, int2 xy, MouseInput mi) + { + mi.Button = MouseButton.Left; + return OrderInner(world, xy, mi).Any() + ? "repair" : "repair-blocked"; + } + } +} diff --git a/OpenRA.Mods.RA/Orders/SellOrderGenerator.cs b/OpenRA.Mods.RA/Orders/SellOrderGenerator.cs index bc2cb8e31e..c42f291eb3 100755 --- a/OpenRA.Mods.RA/Orders/SellOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/SellOrderGenerator.cs @@ -1,56 +1,56 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Orders -{ - class SellOrderGenerator : IOrderGenerator - { - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Right) - world.CancelInputMode(); - - return OrderInner(world, xy, mi); - } - - IEnumerable OrderInner(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Left) - { - var underCursor = world.FindUnitsAtMouse(mi.Location) - .Where(a => a.Owner == world.LocalPlayer - && a.HasTrait() - && a.HasTrait()).FirstOrDefault(); - - var building = underCursor != null ? underCursor.Info.Traits.Get() : null; - - if (building != null && !building.Unsellable) - yield return new Order("Sell", underCursor, false); - } - } - - public void Tick( World world ) {} - public void RenderAfterWorld( WorldRenderer wr, World world ) { } - public void RenderBeforeWorld( WorldRenderer wr, World world ) { } - - public string GetCursor(World world, int2 xy, MouseInput mi) - { - mi.Button = MouseButton.Left; - return OrderInner(world, xy, mi).Any() - ? "sell" : "sell-blocked"; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Orders +{ + class SellOrderGenerator : IOrderGenerator + { + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Right) + world.CancelInputMode(); + + return OrderInner(world, xy, mi); + } + + IEnumerable OrderInner(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Left) + { + var underCursor = world.FindUnitsAtMouse(mi.Location) + .Where(a => a.Owner == world.LocalPlayer + && a.HasTrait() + && a.HasTrait()).FirstOrDefault(); + + var building = underCursor != null ? underCursor.Info.Traits.Get() : null; + + if (building != null && !building.Unsellable) + yield return new Order("Sell", underCursor, false); + } + } + + public void Tick( World world ) {} + public void RenderAfterWorld( WorldRenderer wr, World world ) { } + public void RenderBeforeWorld( WorldRenderer wr, World world ) { } + + public string GetCursor(World world, int2 xy, MouseInput mi) + { + mi.Button = MouseButton.Left; + return OrderInner(world, xy, mi).Any() + ? "sell" : "sell-blocked"; + } + } +} diff --git a/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs b/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs index c2c269a9ba..94cc87ef42 100644 --- a/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs +++ b/OpenRA.Mods.RA/Orders/SetChronoTankDestination.cs @@ -1,57 +1,57 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Orders -{ - class SetChronoTankDestination : IOrderGenerator - { - public readonly Actor self; - - public SetChronoTankDestination(Actor self) - { - this.self = self; - } - - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Left) - { - world.CancelInputMode(); - yield break; - } - - var queued = mi.Modifiers.HasModifier(Modifiers.Shift); - if (world.LocalPlayer.Shroud.IsExplored(xy)) - yield return new Order("ChronoshiftSelf", self, queued) { TargetLocation = xy }; - } - - public void Tick( World world ) { } - public void RenderAfterWorld( WorldRenderer wr, World world ) - { - wr.DrawSelectionBox(self, Color.White); - } - - public void RenderBeforeWorld( WorldRenderer wr, World world ) { } - - public string GetCursor(World world, int2 xy, MouseInput mi) - { - if (!world.LocalPlayer.Shroud.IsExplored(xy)) - return "move-blocked"; - - var movement = self.TraitOrDefault(); - return (movement.CanEnterCell(xy)) ? "chrono-target" : "move-blocked"; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Orders +{ + class SetChronoTankDestination : IOrderGenerator + { + public readonly Actor self; + + public SetChronoTankDestination(Actor self) + { + this.self = self; + } + + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Left) + { + world.CancelInputMode(); + yield break; + } + + var queued = mi.Modifiers.HasModifier(Modifiers.Shift); + if (world.LocalPlayer.Shroud.IsExplored(xy)) + yield return new Order("ChronoshiftSelf", self, queued) { TargetLocation = xy }; + } + + public void Tick( World world ) { } + public void RenderAfterWorld( WorldRenderer wr, World world ) + { + wr.DrawSelectionBox(self, Color.White); + } + + public void RenderBeforeWorld( WorldRenderer wr, World world ) { } + + public string GetCursor(World world, int2 xy, MouseInput mi) + { + if (!world.LocalPlayer.Shroud.IsExplored(xy)) + return "move-blocked"; + + var movement = self.TraitOrDefault(); + return (movement.CanEnterCell(xy)) ? "chrono-target" : "move-blocked"; + } + } +} diff --git a/OpenRA.Mods.RA/Orders/UnitOrderTargeter.cs b/OpenRA.Mods.RA/Orders/UnitOrderTargeter.cs index b044f46e7c..83decce9a2 100755 --- a/OpenRA.Mods.RA/Orders/UnitOrderTargeter.cs +++ b/OpenRA.Mods.RA/Orders/UnitOrderTargeter.cs @@ -1,74 +1,74 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Orders -{ - public class UnitOrderTargeter : IOrderTargeter - { - readonly string cursor; - readonly bool targetEnemyUnits, targetAllyUnits; - - public UnitOrderTargeter( string order, int priority, string cursor, bool targetEnemyUnits, bool targetAllyUnits ) - { - this.OrderID = order; - this.OrderPriority = priority; - this.cursor = cursor; - this.targetEnemyUnits = targetEnemyUnits; - this.targetAllyUnits = targetAllyUnits; - } - - public string OrderID { get; private set; } - public int OrderPriority { get; private set; } - - public virtual bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - if( self == null ) throw new ArgumentNullException( "self" ); - if( target == null ) throw new ArgumentNullException( "target" ); - - cursor = this.cursor; - IsQueued = forceQueued; - - var playerRelationship = self.Owner.Stances[ target.Owner ]; - - if( !forceAttack && playerRelationship == Stance.Ally && !targetAllyUnits ) return false; - if( !forceAttack && playerRelationship == Stance.Enemy && !targetEnemyUnits ) return false; - - return true; - } - - public virtual bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - return false; - } - public virtual bool IsQueued { get; protected set; } - } - - public class UnitTraitOrderTargeter : UnitOrderTargeter - { - public UnitTraitOrderTargeter( string order, int priority, string cursor, bool targetEnemyUnits, bool targetAllyUnits ) - : base( order, priority, cursor, targetEnemyUnits, targetAllyUnits ) - { - } - - public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - if( !base.CanTargetActor( self, target, forceAttack, forceMove, forceQueued, ref cursor ) ) return false; - if( !target.HasTrait() ) return false; - - IsQueued = forceQueued; - - return true; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Orders +{ + public class UnitOrderTargeter : IOrderTargeter + { + readonly string cursor; + readonly bool targetEnemyUnits, targetAllyUnits; + + public UnitOrderTargeter( string order, int priority, string cursor, bool targetEnemyUnits, bool targetAllyUnits ) + { + this.OrderID = order; + this.OrderPriority = priority; + this.cursor = cursor; + this.targetEnemyUnits = targetEnemyUnits; + this.targetAllyUnits = targetAllyUnits; + } + + public string OrderID { get; private set; } + public int OrderPriority { get; private set; } + + public virtual bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + if( self == null ) throw new ArgumentNullException( "self" ); + if( target == null ) throw new ArgumentNullException( "target" ); + + cursor = this.cursor; + IsQueued = forceQueued; + + var playerRelationship = self.Owner.Stances[ target.Owner ]; + + if( !forceAttack && playerRelationship == Stance.Ally && !targetAllyUnits ) return false; + if( !forceAttack && playerRelationship == Stance.Enemy && !targetEnemyUnits ) return false; + + return true; + } + + public virtual bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + return false; + } + public virtual bool IsQueued { get; protected set; } + } + + public class UnitTraitOrderTargeter : UnitOrderTargeter + { + public UnitTraitOrderTargeter( string order, int priority, string cursor, bool targetEnemyUnits, bool targetAllyUnits ) + : base( order, priority, cursor, targetEnemyUnits, targetAllyUnits ) + { + } + + public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + if( !base.CanTargetActor( self, target, forceAttack, forceMove, forceQueued, ref cursor ) ) return false; + if( !target.HasTrait() ) return false; + + IsQueued = forceQueued; + + return true; + } + } +} diff --git a/OpenRA.Mods.RA/OreRefinery.cs b/OpenRA.Mods.RA/OreRefinery.cs index 18de1d31b9..d2277c8fe1 100644 --- a/OpenRA.Mods.RA/OreRefinery.cs +++ b/OpenRA.Mods.RA/OreRefinery.cs @@ -1,157 +1,157 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; -using OpenRA.Mods.RA.Render; -using OpenRA.Mods.RA.Move; -using System.Drawing; - -namespace OpenRA.Mods.RA -{ - public class OreRefineryInfo : ITraitInfo - { - public readonly int PipCount = 0; - public readonly PipType PipColor = PipType.Red; - public readonly int2 DockOffset = new int2 (1, 2); - public readonly int Capacity = 0; - public readonly int ProcessTick = 25; - public readonly int ProcessAmount = 50; - public readonly int LowPowerProcessTick = 50; - - public virtual object Create(ActorInitializer init) { return new OreRefinery(init.self, this); } - } - - public class OreRefinery : ITick, IAcceptOre, INotifyDamage, INotifySold, INotifyCapture, IExplodeModifier, ISync - { - readonly Actor self; - readonly OreRefineryInfo Info; - PlayerResources PlayerResources; - - [Sync] - public int Ore = 0; - - [Sync] - Actor dockedHarv = null; - [Sync] - bool preventDock = false; - - public int2 DeliverOffset { get { return Info.DockOffset; } } - public virtual IActivity DockSequence(Actor harv, Actor self) - { - return new RAHarvesterDockSequence(harv, self); - } - - public OreRefinery (Actor self, OreRefineryInfo info) - { - this.self = self; - Info = info; - PlayerResources = self.Owner.PlayerActor.Trait(); - } - - public IEnumerable> GetLinkedHarvesters() - { - return self.World.Queries.WithTrait() - .Where(a => a.Trait.LinkedProc == self); - } - - public bool CanGiveOre(int amount) - { - return PlayerResources.CanGiveOre(amount); - } - - public void GiveOre(int amount) - { - PlayerResources.GiveOre(amount); - } - - void CancelDock(Actor self) - { - preventDock = true; - - // Cancel the dock sequence - if (dockedHarv != null && !dockedHarv.IsDead()) - dockedHarv.CancelActivity(); - } - - public void Tick (Actor self) - { - // Harvester was killed while unloading - if (dockedHarv != null && dockedHarv.IsDead()) - { - self.Trait().CancelCustomAnim(self); - dockedHarv = null; - } - } - - public void Damaged (Actor self, AttackInfo e) - { - if (e.DamageState == DamageState.Dead) - { - CancelDock(self); - foreach (var harv in GetLinkedHarvesters()) - harv.Trait.UnlinkProc(harv.Actor, self); - } - } - - public void OnDock (Actor harv, DeliverResources dockOrder) - { - var mobile = harv.Trait(); - var harvester = harv.Trait(); - - if (!preventDock) - { - harv.QueueActivity( new CallFunc( () => dockedHarv = harv, false ) ); - harv.QueueActivity( DockSequence(harv, self) ); - harv.QueueActivity( new CallFunc( () => dockedHarv = null, false ) ); - } - - // Tell the harvester to start harvesting - // TODO: This belongs on the harv idle activity - harv.QueueActivity( new CallFunc( () => - { - if (harvester.LastHarvestedCell != int2.Zero) - { - harv.QueueActivity( mobile.MoveTo(harvester.LastHarvestedCell, 5) ); - harv.SetTargetLine(Target.FromCell(harvester.LastHarvestedCell), Color.Red, false); - } - harv.QueueActivity( new Harvest() ); - })); - } - - - public void OnCapture (Actor self, Actor captor, Player oldOwner, Player newOwner) - { - // Steal any docked harv too - if (dockedHarv != null) - dockedHarv.ChangeOwner(newOwner); - - // Unlink any non-docked harvs - foreach (var harv in GetLinkedHarvesters()) - if (harv.Actor.Owner == oldOwner) - harv.Trait.UnlinkProc(harv.Actor, self); - - PlayerResources = newOwner.PlayerActor.Trait(); - } - - public void Selling (Actor self) { CancelDock(self); } - public void Sold (Actor self) - { - foreach (var harv in GetLinkedHarvesters()) - harv.Trait.UnlinkProc(harv.Actor, self); - } - - public bool ShouldExplode(Actor self) { return Ore > 0; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; +using OpenRA.Mods.RA.Render; +using OpenRA.Mods.RA.Move; +using System.Drawing; + +namespace OpenRA.Mods.RA +{ + public class OreRefineryInfo : ITraitInfo + { + public readonly int PipCount = 0; + public readonly PipType PipColor = PipType.Red; + public readonly int2 DockOffset = new int2 (1, 2); + public readonly int Capacity = 0; + public readonly int ProcessTick = 25; + public readonly int ProcessAmount = 50; + public readonly int LowPowerProcessTick = 50; + + public virtual object Create(ActorInitializer init) { return new OreRefinery(init.self, this); } + } + + public class OreRefinery : ITick, IAcceptOre, INotifyDamage, INotifySold, INotifyCapture, IExplodeModifier, ISync + { + readonly Actor self; + readonly OreRefineryInfo Info; + PlayerResources PlayerResources; + + [Sync] + public int Ore = 0; + + [Sync] + Actor dockedHarv = null; + [Sync] + bool preventDock = false; + + public int2 DeliverOffset { get { return Info.DockOffset; } } + public virtual IActivity DockSequence(Actor harv, Actor self) + { + return new RAHarvesterDockSequence(harv, self); + } + + public OreRefinery (Actor self, OreRefineryInfo info) + { + this.self = self; + Info = info; + PlayerResources = self.Owner.PlayerActor.Trait(); + } + + public IEnumerable> GetLinkedHarvesters() + { + return self.World.Queries.WithTrait() + .Where(a => a.Trait.LinkedProc == self); + } + + public bool CanGiveOre(int amount) + { + return PlayerResources.CanGiveOre(amount); + } + + public void GiveOre(int amount) + { + PlayerResources.GiveOre(amount); + } + + void CancelDock(Actor self) + { + preventDock = true; + + // Cancel the dock sequence + if (dockedHarv != null && !dockedHarv.IsDead()) + dockedHarv.CancelActivity(); + } + + public void Tick (Actor self) + { + // Harvester was killed while unloading + if (dockedHarv != null && dockedHarv.IsDead()) + { + self.Trait().CancelCustomAnim(self); + dockedHarv = null; + } + } + + public void Damaged (Actor self, AttackInfo e) + { + if (e.DamageState == DamageState.Dead) + { + CancelDock(self); + foreach (var harv in GetLinkedHarvesters()) + harv.Trait.UnlinkProc(harv.Actor, self); + } + } + + public void OnDock (Actor harv, DeliverResources dockOrder) + { + var mobile = harv.Trait(); + var harvester = harv.Trait(); + + if (!preventDock) + { + harv.QueueActivity( new CallFunc( () => dockedHarv = harv, false ) ); + harv.QueueActivity( DockSequence(harv, self) ); + harv.QueueActivity( new CallFunc( () => dockedHarv = null, false ) ); + } + + // Tell the harvester to start harvesting + // TODO: This belongs on the harv idle activity + harv.QueueActivity( new CallFunc( () => + { + if (harvester.LastHarvestedCell != int2.Zero) + { + harv.QueueActivity( mobile.MoveTo(harvester.LastHarvestedCell, 5) ); + harv.SetTargetLine(Target.FromCell(harvester.LastHarvestedCell), Color.Red, false); + } + harv.QueueActivity( new Harvest() ); + })); + } + + + public void OnCapture (Actor self, Actor captor, Player oldOwner, Player newOwner) + { + // Steal any docked harv too + if (dockedHarv != null) + dockedHarv.ChangeOwner(newOwner); + + // Unlink any non-docked harvs + foreach (var harv in GetLinkedHarvesters()) + if (harv.Actor.Owner == oldOwner) + harv.Trait.UnlinkProc(harv.Actor, self); + + PlayerResources = newOwner.PlayerActor.Trait(); + } + + public void Selling (Actor self) { CancelDock(self); } + public void Sold (Actor self) + { + foreach (var harv in GetLinkedHarvesters()) + harv.Trait.UnlinkProc(harv.Actor, self); + } + + public bool ShouldExplode(Actor self) { return Ore > 0; } + } +} diff --git a/OpenRA.Mods.RA/PaletteFromCurrentTileset.cs b/OpenRA.Mods.RA/PaletteFromCurrentTileset.cs index 8a64d071ad..305d2ded2b 100644 --- a/OpenRA.Mods.RA/PaletteFromCurrentTileset.cs +++ b/OpenRA.Mods.RA/PaletteFromCurrentTileset.cs @@ -1,11 +1,11 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ #endregion using OpenRA.FileFormats; @@ -22,19 +22,19 @@ namespace OpenRA.Mods.RA } class PaletteFromCurrentTileset : IPalette - { + { readonly World world; - readonly PaletteFromCurrentTilesetInfo info; - + readonly PaletteFromCurrentTilesetInfo info; + public PaletteFromCurrentTileset(World world, PaletteFromCurrentTilesetInfo info) - { - this.world = world; + { + this.world = world; this.info = info; - } - - public void InitPalette( OpenRA.Graphics.WorldRenderer wr ) - { + } + + public void InitPalette( OpenRA.Graphics.WorldRenderer wr ) + { wr.AddPalette( info.Name, new Palette( FileSystem.Open( world.TileSet.Palette ), info.Transparent ) ); - } + } } } diff --git a/OpenRA.Mods.RA/PaletteFromFile.cs b/OpenRA.Mods.RA/PaletteFromFile.cs index 372d3f96d5..e33519277d 100644 --- a/OpenRA.Mods.RA/PaletteFromFile.cs +++ b/OpenRA.Mods.RA/PaletteFromFile.cs @@ -1,43 +1,43 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.FileFormats; -using OpenRA.Traits; -using OpenRA.Graphics; - -namespace OpenRA.Mods.RA -{ - class PaletteFromFileInfo : ITraitInfo - { - public readonly string Name = null; - public readonly string Tileset = null; - public readonly string Filename = null; - public readonly bool Transparent = true; - - public object Create(ActorInitializer init) { return new PaletteFromFile(init.world, this); } - } - - class PaletteFromFile : IPalette - { - readonly World world; - readonly PaletteFromFileInfo info; - public PaletteFromFile(World world, PaletteFromFileInfo info) - { - this.world = world; - this.info = info; - } - - public void InitPalette( WorldRenderer wr ) - { - if( info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant() ) - wr.AddPalette( info.Name, new Palette( FileSystem.Open( info.Filename ), info.Transparent ) ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.FileFormats; +using OpenRA.Traits; +using OpenRA.Graphics; + +namespace OpenRA.Mods.RA +{ + class PaletteFromFileInfo : ITraitInfo + { + public readonly string Name = null; + public readonly string Tileset = null; + public readonly string Filename = null; + public readonly bool Transparent = true; + + public object Create(ActorInitializer init) { return new PaletteFromFile(init.world, this); } + } + + class PaletteFromFile : IPalette + { + readonly World world; + readonly PaletteFromFileInfo info; + public PaletteFromFile(World world, PaletteFromFileInfo info) + { + this.world = world; + this.info = info; + } + + public void InitPalette( WorldRenderer wr ) + { + if( info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant() ) + wr.AddPalette( info.Name, new Palette( FileSystem.Open( info.Filename ), info.Transparent ) ); + } + } +} diff --git a/OpenRA.Mods.RA/PaletteFromRGBA.cs b/OpenRA.Mods.RA/PaletteFromRGBA.cs index 5f9aa01253..a4856746ee 100644 --- a/OpenRA.Mods.RA/PaletteFromRGBA.cs +++ b/OpenRA.Mods.RA/PaletteFromRGBA.cs @@ -1,64 +1,64 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.FileFormats; -using OpenRA.Traits; -using OpenRA.Graphics; - -namespace OpenRA.Mods.RA -{ - class PaletteFromRGBAInfo : ITraitInfo - { - public readonly string Name = null; - public readonly string Tileset = null; - public readonly int R = 0; - public readonly int G = 0; - public readonly int B = 0; - public readonly int A = 255; - - public object Create(ActorInitializer init) { return new PaletteFromRGBA(init.world, this); } - } - - class PaletteFromRGBA : IPalette - { - readonly World world; - readonly PaletteFromRGBAInfo info; - public PaletteFromRGBA(World world, PaletteFromRGBAInfo info) - { - this.world = world; - this.info = info; - } - - public void InitPalette( WorldRenderer wr ) - { - if (info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant()) - { - // TODO: This shouldn't rely on a base palette - var pal = wr.GetPalette("terrain"); - wr.AddPalette(info.Name, new Palette(pal, new SingleColorRemap(Color.FromArgb(info.A, info.R, info.G, info.B)))); - } - } - } - - class SingleColorRemap : IPaletteRemap - { - Color c; - public SingleColorRemap(Color c) - { - this.c = c; - } - - public Color GetRemappedColor(Color original, int index) - { - return original.A > 0 ? c : original; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.FileFormats; +using OpenRA.Traits; +using OpenRA.Graphics; + +namespace OpenRA.Mods.RA +{ + class PaletteFromRGBAInfo : ITraitInfo + { + public readonly string Name = null; + public readonly string Tileset = null; + public readonly int R = 0; + public readonly int G = 0; + public readonly int B = 0; + public readonly int A = 255; + + public object Create(ActorInitializer init) { return new PaletteFromRGBA(init.world, this); } + } + + class PaletteFromRGBA : IPalette + { + readonly World world; + readonly PaletteFromRGBAInfo info; + public PaletteFromRGBA(World world, PaletteFromRGBAInfo info) + { + this.world = world; + this.info = info; + } + + public void InitPalette( WorldRenderer wr ) + { + if (info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant()) + { + // TODO: This shouldn't rely on a base palette + var pal = wr.GetPalette("terrain"); + wr.AddPalette(info.Name, new Palette(pal, new SingleColorRemap(Color.FromArgb(info.A, info.R, info.G, info.B)))); + } + } + } + + class SingleColorRemap : IPaletteRemap + { + Color c; + public SingleColorRemap(Color c) + { + this.c = c; + } + + public Color GetRemappedColor(Color original, int index) + { + return original.A > 0 ? c : original; + } + } +} diff --git a/OpenRA.Mods.RA/ParaDrop.cs b/OpenRA.Mods.RA/ParaDrop.cs index a2e9ee4eeb..d850c6dc89 100644 --- a/OpenRA.Mods.RA/ParaDrop.cs +++ b/OpenRA.Mods.RA/ParaDrop.cs @@ -1,104 +1,104 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Effects; -using OpenRA.Traits; -using OpenRA.Mods.RA.Air; - -namespace OpenRA.Mods.RA -{ - public class ParaDropInfo : TraitInfo - { - public readonly int LZRange = 4; - public readonly string ChuteSound = "chute1.aud"; - } - - public class ParaDrop : ITick, INotifyDamage - { - readonly List droppedAt = new List(); - int2 lz; - Actor flare; - - public void SetLZ( int2 lz, Actor flare ) - { - this.lz = lz; - this.flare = flare; - droppedAt.Clear(); - } - - public void Tick(Actor self) - { - var info = self.Info.Traits.Get(); - var r = info.LZRange; - - if ((self.Location - lz).LengthSquared <= r * r && !droppedAt.Contains(self.Location)) - { - var cargo = self.Trait(); - if (cargo.IsEmpty(self)) - FinishedDropping(self); - else - { - if (!IsSuitableCell(cargo.Peek(self), self.Location)) - return; - - // unload a dude here - droppedAt.Add(self.Location); - - var a = cargo.Unload(self); - var rs = a.Trait(); - - var aircraft = self.Trait(); - self.World.AddFrameEndTask(w => w.Add( - new Parachute(self.Owner, rs.anim.Name, - Util.CenterOfCell(Util.CellContaining(self.CenterLocation)), - aircraft.Altitude, a))); - - Sound.Play(info.ChuteSound, self.CenterLocation); - } - } - } - - bool IsSuitableCell(Actor actorToDrop, int2 p) - { - return actorToDrop.Trait().CanEnterCell(p); - } - - void FinishedDropping(Actor self) - { - self.CancelActivity(); - self.QueueActivity(new FlyOffMap { Interruptible = false }); - self.QueueActivity(new RemoveSelf()); - - if (flare != null) - { - flare.CancelActivity(); - flare.QueueActivity(new Wait(300)); - flare.QueueActivity(new RemoveSelf()); - flare = null; - } - } - - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageStateChanged && e.DamageState == DamageState.Dead) - { - if (flare != null) - { - flare.CancelActivity(); - flare.QueueActivity(new Wait(300)); - flare.QueueActivity(new RemoveSelf()); - flare = null; - } - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Effects; +using OpenRA.Traits; +using OpenRA.Mods.RA.Air; + +namespace OpenRA.Mods.RA +{ + public class ParaDropInfo : TraitInfo + { + public readonly int LZRange = 4; + public readonly string ChuteSound = "chute1.aud"; + } + + public class ParaDrop : ITick, INotifyDamage + { + readonly List droppedAt = new List(); + int2 lz; + Actor flare; + + public void SetLZ( int2 lz, Actor flare ) + { + this.lz = lz; + this.flare = flare; + droppedAt.Clear(); + } + + public void Tick(Actor self) + { + var info = self.Info.Traits.Get(); + var r = info.LZRange; + + if ((self.Location - lz).LengthSquared <= r * r && !droppedAt.Contains(self.Location)) + { + var cargo = self.Trait(); + if (cargo.IsEmpty(self)) + FinishedDropping(self); + else + { + if (!IsSuitableCell(cargo.Peek(self), self.Location)) + return; + + // unload a dude here + droppedAt.Add(self.Location); + + var a = cargo.Unload(self); + var rs = a.Trait(); + + var aircraft = self.Trait(); + self.World.AddFrameEndTask(w => w.Add( + new Parachute(self.Owner, rs.anim.Name, + Util.CenterOfCell(Util.CellContaining(self.CenterLocation)), + aircraft.Altitude, a))); + + Sound.Play(info.ChuteSound, self.CenterLocation); + } + } + } + + bool IsSuitableCell(Actor actorToDrop, int2 p) + { + return actorToDrop.Trait().CanEnterCell(p); + } + + void FinishedDropping(Actor self) + { + self.CancelActivity(); + self.QueueActivity(new FlyOffMap { Interruptible = false }); + self.QueueActivity(new RemoveSelf()); + + if (flare != null) + { + flare.CancelActivity(); + flare.QueueActivity(new Wait(300)); + flare.QueueActivity(new RemoveSelf()); + flare = null; + } + } + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageStateChanged && e.DamageState == DamageState.Dead) + { + if (flare != null) + { + flare.CancelActivity(); + flare.QueueActivity(new Wait(300)); + flare.QueueActivity(new RemoveSelf()); + flare = null; + } + } + } + } +} diff --git a/OpenRA.Mods.RA/Passenger.cs b/OpenRA.Mods.RA/Passenger.cs index cfd83bffad..ae4e8493e5 100644 --- a/OpenRA.Mods.RA/Passenger.cs +++ b/OpenRA.Mods.RA/Passenger.cs @@ -1,95 +1,95 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Effects; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA -{ - class PassengerInfo : ITraitInfo - { - public readonly string CargoType = null; - public readonly PipType PipType = PipType.Green; - - public object Create( ActorInitializer init ) { return new Passenger( init.self ); } - } - - public class Passenger : IIssueOrder, IResolveOrder, IOrderVoice - { - readonly Actor self; - public Passenger( Actor self ) { this.self = self; } - - public IEnumerable Orders - { - get - { - yield return new EnterOrderTargeter( "EnterTransport", 6, false, true, - target => IsCorrectCargoType( target ), target => CanEnter( target ) ); - } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "EnterTransport" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - return null; - } - - bool IsCorrectCargoType( Actor target ) - { - var pi = self.Info.Traits.Get(); - var ci = target.Info.Traits.Get(); - return ci.Types.Contains( pi.CargoType ); - } - - bool CanEnter( Actor target ) - { - var cargo = target.TraitOrDefault(); - return (cargo != null && !cargo.IsFull(target)); - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - if (order.OrderString != "EnterTransport" || - !CanEnter(order.TargetActor)) return null; - return "Move"; - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "EnterTransport") - { - if (order.TargetActor == null) return; - if (!CanEnter(order.TargetActor)) return; - if (!IsCorrectCargoType(order.TargetActor)) return; - - self.SetTargetLine(Target.FromOrder(order), Color.Green); - - var mobile = self.Trait(); - self.CancelActivity(); - self.QueueActivity(mobile.MoveTo(order.TargetActor.Location, 1)); - self.QueueActivity(new EnterTransport(self, order.TargetActor)); - } - } - - public PipType ColorOfCargoPip( Actor self ) - { - return self.Info.Traits.Get().PipType; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Effects; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA +{ + class PassengerInfo : ITraitInfo + { + public readonly string CargoType = null; + public readonly PipType PipType = PipType.Green; + + public object Create( ActorInitializer init ) { return new Passenger( init.self ); } + } + + public class Passenger : IIssueOrder, IResolveOrder, IOrderVoice + { + readonly Actor self; + public Passenger( Actor self ) { this.self = self; } + + public IEnumerable Orders + { + get + { + yield return new EnterOrderTargeter( "EnterTransport", 6, false, true, + target => IsCorrectCargoType( target ), target => CanEnter( target ) ); + } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "EnterTransport" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + return null; + } + + bool IsCorrectCargoType( Actor target ) + { + var pi = self.Info.Traits.Get(); + var ci = target.Info.Traits.Get(); + return ci.Types.Contains( pi.CargoType ); + } + + bool CanEnter( Actor target ) + { + var cargo = target.TraitOrDefault(); + return (cargo != null && !cargo.IsFull(target)); + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + if (order.OrderString != "EnterTransport" || + !CanEnter(order.TargetActor)) return null; + return "Move"; + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "EnterTransport") + { + if (order.TargetActor == null) return; + if (!CanEnter(order.TargetActor)) return; + if (!IsCorrectCargoType(order.TargetActor)) return; + + self.SetTargetLine(Target.FromOrder(order), Color.Green); + + var mobile = self.Trait(); + self.CancelActivity(); + self.QueueActivity(mobile.MoveTo(order.TargetActor.Location, 1)); + self.QueueActivity(new EnterTransport(self, order.TargetActor)); + } + } + + public PipType ColorOfCargoPip( Actor self ) + { + return self.Info.Traits.Get().PipType; + } + } +} diff --git a/OpenRA.Mods.RA/Player/ActorGroupProxy.cs b/OpenRA.Mods.RA/Player/ActorGroupProxy.cs index 55438dd672..35c5b404a6 100755 --- a/OpenRA.Mods.RA/Player/ActorGroupProxy.cs +++ b/OpenRA.Mods.RA/Player/ActorGroupProxy.cs @@ -1,34 +1,34 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class ActorGroupProxyInfo : TraitInfo { } - - class ActorGroupProxy : IResolveOrder - { - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "CreateGroup") - { - /* create a group */ - var actors = order.TargetString.Split(',') - .Select(id => uint.Parse(id)) - .Select(id => self.World.Actors.FirstOrDefault(a => a.ActorID == id)) - .Where(a => a != null); - - new Group(actors); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class ActorGroupProxyInfo : TraitInfo { } + + class ActorGroupProxy : IResolveOrder + { + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "CreateGroup") + { + /* create a group */ + var actors = order.TargetString.Split(',') + .Select(id => uint.Parse(id)) + .Select(id => self.World.Actors.FirstOrDefault(a => a.ActorID == id)) + .Where(a => a != null); + + new Group(actors); + } + } + } +} diff --git a/OpenRA.Mods.RA/Player/ClassicProductionQueue.cs b/OpenRA.Mods.RA/Player/ClassicProductionQueue.cs index aa1b7a130a..4ac80e99a3 100755 --- a/OpenRA.Mods.RA/Player/ClassicProductionQueue.cs +++ b/OpenRA.Mods.RA/Player/ClassicProductionQueue.cs @@ -1,16 +1,16 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Mods.RA.Buildings; +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Mods.RA.Buildings; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -18,8 +18,8 @@ namespace OpenRA.Mods.RA public class ClassicProductionQueueInfo : ProductionQueueInfo, ITraitPrerequisite, ITraitPrerequisite, ITraitPrerequisite { public override object Create(ActorInitializer init) { return new ClassicProductionQueue(init.self, this); } - } - + } + public class ClassicProductionQueue : ProductionQueue, ISync { public ClassicProductionQueue( Actor self, ClassicProductionQueueInfo info ) diff --git a/OpenRA.Mods.RA/Player/PlaceBuilding.cs b/OpenRA.Mods.RA/Player/PlaceBuilding.cs index 284d5dd389..8f25a1b716 100755 --- a/OpenRA.Mods.RA/Player/PlaceBuilding.cs +++ b/OpenRA.Mods.RA/Player/PlaceBuilding.cs @@ -1,117 +1,117 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Effects; -using OpenRA.FileFormats; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class PlaceBuildingInfo : TraitInfo {} - - class PlaceBuilding : IResolveOrder - { - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "PlaceBuilding" || order.OrderString == "LineBuild") - { - self.World.AddFrameEndTask(w => - { - var prevItems = GetNumBuildables(self.Owner); - - // Find the queue with the target actor - var queue = w.Queries.WithTrait() - .Where(p => p.Actor.Owner == self.Owner && - p.Trait.CurrentItem() != null && - p.Trait.CurrentItem().Item == order.TargetString && - p.Trait.CurrentItem().RemainingTime == 0) - .Select(p => p.Trait) - .FirstOrDefault(); - - if (queue == null) - return; - - var unit = Rules.Info[order.TargetString]; - var buildingInfo = unit.Traits.Get(); - - if (order.OrderString == "LineBuild") - { - bool playSounds = true; - foreach (var t in BuildingUtils.GetLineBuildCells(w, order.TargetLocation, order.TargetString, buildingInfo)) - { - var building = w.CreateActor(order.TargetString, new TypeDictionary - { - new LocationInit( t ), - new OwnerInit( order.Player ), - }); - - if (playSounds) - foreach (var s in buildingInfo.BuildSounds) - Sound.PlayToPlayer(order.Player, s, building.CenterLocation); - playSounds = false; - } - } - else - { - if (!self.World.CanPlaceBuilding(order.TargetString, buildingInfo, order.TargetLocation, null)) - { - return; - } - - var building = w.CreateActor(order.TargetString, new TypeDictionary - { - new LocationInit( order.TargetLocation ), - new OwnerInit( order.Player ), - }); - foreach (var s in buildingInfo.BuildSounds) - Sound.PlayToPlayer(order.Player, s, building.CenterLocation); - } - - PlayBuildAnim( self, unit ); - - queue.FinishProduction(); - - if (GetNumBuildables(self.Owner) > prevItems) - w.Add(new DelayedAction(10, - () => Sound.PlayToPlayer(order.Player, - w.WorldActor.Info.Traits.Get().NewOptions))); - }); - } - } - - // finds a construction yard (or equivalent) and runs its "build" animation. - static void PlayBuildAnim( Actor self, ActorInfo unit ) - { - var bi = unit.Traits.GetOrDefault(); - if (bi == null) - return; - - var producers = self.World.Queries.OwnedBy[ self.Owner ].WithTrait() - .Where( x => x.Actor.Info.Traits.Get().Produces.Contains( bi.Queue ) ) - .ToList(); - var producer = producers.Where( x => x.Actor.IsPrimaryBuilding() ).Concat( producers ) - .FirstOrDefault(); - - if( producer.Actor != null ) - producer.Actor.TraitsImplementing().First().PlayCustomAnim( producer.Actor, "build" ); - } - - static int GetNumBuildables(Player p) - { - if (p != p.World.LocalPlayer) return 0; // this only matters for local players. - - return p.World.Queries.WithTrait() - .Where(a => a.Actor.Owner == p) - .SelectMany(a => a.Trait.BuildableItems()).Distinct().Count(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Effects; +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class PlaceBuildingInfo : TraitInfo {} + + class PlaceBuilding : IResolveOrder + { + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "PlaceBuilding" || order.OrderString == "LineBuild") + { + self.World.AddFrameEndTask(w => + { + var prevItems = GetNumBuildables(self.Owner); + + // Find the queue with the target actor + var queue = w.Queries.WithTrait() + .Where(p => p.Actor.Owner == self.Owner && + p.Trait.CurrentItem() != null && + p.Trait.CurrentItem().Item == order.TargetString && + p.Trait.CurrentItem().RemainingTime == 0) + .Select(p => p.Trait) + .FirstOrDefault(); + + if (queue == null) + return; + + var unit = Rules.Info[order.TargetString]; + var buildingInfo = unit.Traits.Get(); + + if (order.OrderString == "LineBuild") + { + bool playSounds = true; + foreach (var t in BuildingUtils.GetLineBuildCells(w, order.TargetLocation, order.TargetString, buildingInfo)) + { + var building = w.CreateActor(order.TargetString, new TypeDictionary + { + new LocationInit( t ), + new OwnerInit( order.Player ), + }); + + if (playSounds) + foreach (var s in buildingInfo.BuildSounds) + Sound.PlayToPlayer(order.Player, s, building.CenterLocation); + playSounds = false; + } + } + else + { + if (!self.World.CanPlaceBuilding(order.TargetString, buildingInfo, order.TargetLocation, null)) + { + return; + } + + var building = w.CreateActor(order.TargetString, new TypeDictionary + { + new LocationInit( order.TargetLocation ), + new OwnerInit( order.Player ), + }); + foreach (var s in buildingInfo.BuildSounds) + Sound.PlayToPlayer(order.Player, s, building.CenterLocation); + } + + PlayBuildAnim( self, unit ); + + queue.FinishProduction(); + + if (GetNumBuildables(self.Owner) > prevItems) + w.Add(new DelayedAction(10, + () => Sound.PlayToPlayer(order.Player, + w.WorldActor.Info.Traits.Get().NewOptions))); + }); + } + } + + // finds a construction yard (or equivalent) and runs its "build" animation. + static void PlayBuildAnim( Actor self, ActorInfo unit ) + { + var bi = unit.Traits.GetOrDefault(); + if (bi == null) + return; + + var producers = self.World.Queries.OwnedBy[ self.Owner ].WithTrait() + .Where( x => x.Actor.Info.Traits.Get().Produces.Contains( bi.Queue ) ) + .ToList(); + var producer = producers.Where( x => x.Actor.IsPrimaryBuilding() ).Concat( producers ) + .FirstOrDefault(); + + if( producer.Actor != null ) + producer.Actor.TraitsImplementing().First().PlayCustomAnim( producer.Actor, "build" ); + } + + static int GetNumBuildables(Player p) + { + if (p != p.World.LocalPlayer) return 0; // this only matters for local players. + + return p.World.Queries.WithTrait() + .Where(a => a.Actor.Owner == p) + .SelectMany(a => a.Trait.BuildableItems()).Distinct().Count(); + } + } +} diff --git a/OpenRA.Mods.RA/Player/ProductionQueue.cs b/OpenRA.Mods.RA/Player/ProductionQueue.cs index 1918c06c95..1ed59e3d55 100755 --- a/OpenRA.Mods.RA/Player/ProductionQueue.cs +++ b/OpenRA.Mods.RA/Player/ProductionQueue.cs @@ -1,349 +1,349 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class ProductionQueueInfo : ITraitInfo - { - public readonly string Type = null; - public float BuildSpeed = 0.4f; - public readonly int LowPowerSlowdown = 3; - - public readonly string ReadyAudio = "unitrdy1.aud"; - public readonly string BlockedAudio = "nobuild1.aud"; - public readonly string QueuedAudio = "train1.aud"; - public readonly string OnHoldAudio = "onhold1.aud"; - public readonly string CancelledAudio = "cancld1.aud"; - - public virtual object Create(ActorInitializer init) { return new ProductionQueue(init.self, init.self.Owner.PlayerActor, this); } - } - - public class ProductionQueue : IResolveOrder, ITick, ITechTreeElement, INotifyCapture, ISync - { - public readonly Actor self; - public ProductionQueueInfo Info; - PowerManager PlayerPower; - PlayerResources PlayerResources; - - // A list of things we are currently building - public List Queue = new List(); - - [Sync] - public int QueueLength { get { return Queue.Count; } } - [Sync] - public int CurrentRemainingCost { get { return QueueLength == 0 ? 0 : Queue[0].RemainingCost; } } - [Sync] - public int CurrentRemainingTime { get { return QueueLength == 0 ? 0 : Queue[0].RemainingTime; } } - [Sync] - public int CurrentSlowdown { get { return QueueLength == 0 ? 0 : Queue[0].slowdown; } } - [Sync] - public bool CurrentPaused { get { return QueueLength == 0 ? false : Queue[0].Paused; } } - [Sync] - public bool CurrentDone { get { return QueueLength == 0 ? false : Queue[0].Done; } } - - // A list of things we could possibly build, even if our race doesn't normally get it - public Dictionary Produceable = new Dictionary(); - - public ProductionQueue( Actor self, Actor playerActor, ProductionQueueInfo info ) - { - this.self = self; - this.Info = info; - PlayerResources = playerActor.Trait(); - PlayerPower = playerActor.Trait(); - - var ttc = playerActor.Trait(); - - foreach (var a in AllBuildables(Info.Type)) - { - var bi = a.Traits.Get(); - // Can our race build this by satisfying normal prereqs? - var buildable = bi.Owner.Contains(self.Owner.Country.Race); - Produceable.Add( a, new ProductionState(){ Visible = buildable && !bi.Hidden } ); - if (buildable) - ttc.Add( a.Name, a.Traits.Get().Prerequisites.ToList(), this ); - } - } - - public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) - { - PlayerPower = newOwner.PlayerActor.Trait(); - PlayerResources = newOwner.PlayerActor.Trait(); - Queue.Clear(); - // Produceable contains the tech from the original owner - this is desired so we don't clear it. - } - - IEnumerable AllBuildables(string category) - { - return Rules.Info.Values - .Where( x => x.Name[ 0 ] != '^' ) - .Where( x => x.Traits.Contains() ) - .Where( x => x.Traits.Get().Queue == category ); - } - - public void OverrideProduction(ActorInfo type, bool buildable) - { - Produceable[type].Buildable = buildable; - Produceable[type].Sticky = true; - } - - public void PrerequisitesAvailable(string key) - { - var ps = Produceable[ Rules.Info[key] ]; - if (!ps.Sticky) - ps.Buildable = true; - } - - public void PrerequisitesUnavailable(string key) - { - var ps = Produceable[ Rules.Info[key] ]; - if (!ps.Sticky) - ps.Buildable = false; - } - - public ProductionItem CurrentItem() - { - return Queue.ElementAtOrDefault(0); - } - - public IEnumerable AllQueued() - { - return Queue; - } - - public virtual IEnumerable AllItems() - { - if (self.World.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait().AllTech) - return Produceable.Select(a => a.Key); - - return Produceable.Where(a => a.Value.Buildable || a.Value.Visible).Select(a => a.Key); - } - - public virtual IEnumerable BuildableItems() - { - if (self.World.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait().AllTech) - return Produceable.Select(a => a.Key); - - return Produceable.Where(a => a.Value.Buildable).Select(a => a.Key); - } - - public bool CanBuild(ActorInfo actor) - { - return Produceable.ContainsKey(actor) && Produceable[actor].Buildable; - } - - public virtual void Tick( Actor self ) - { - while( Queue.Count > 0 && !BuildableItems().Any(b => b.Name == Queue[ 0 ].Item) ) - { - self.Owner.PlayerActor.Trait().GiveCash(Queue[0].TotalCost - Queue[0].RemainingCost); // refund what's been paid so far. - FinishProduction(); - } - if( Queue.Count > 0 ) - Queue[ 0 ].Tick( PlayerResources, PlayerPower ); - } - - public void ResolveOrder( Actor self, Order order ) - { - switch( order.OrderString ) - { - case "StartProduction": - { - var unit = Rules.Info[order.TargetString]; - var bi = unit.Traits.Get(); - if (bi.Queue != Info.Type) - return; /* Not built by this queue */ - - var cost = unit.Traits.Contains() ? unit.Traits.Get().Cost : 0; - var time = GetBuildTime(order.TargetString); - - if (!BuildableItems().Any(b => b.Name == order.TargetString)) - return; /* you can't build that!! */ - - for (var n = 0; n < order.TargetLocation.X; n++) // repeat count - { - bool hasPlayedSound = false; - BeginProduction(new ProductionItem(this, order.TargetString, (int)time, cost, - () => self.World.AddFrameEndTask( - _ => - { - var isBuilding = unit.Traits.Contains(); - - if (isBuilding && !hasPlayedSound) - { - Sound.PlayToPlayer(order.Player, Info.ReadyAudio); - hasPlayedSound = true; - } - else if (!isBuilding) - { - if (BuildUnit(order.TargetString)) - Sound.PlayToPlayer(order.Player, Info.ReadyAudio); - else if (!hasPlayedSound && time > 0) - { - Sound.PlayToPlayer(order.Player, Info.BlockedAudio); - hasPlayedSound = true; - } - } - }))); - } - break; - } - case "PauseProduction": - { - if( Queue.Count > 0 && Queue[0].Item == order.TargetString ) - Queue[0].Paused = ( order.TargetLocation.X != 0 ); - break; - } - case "CancelProduction": - { - CancelProduction(order.TargetString,order.TargetLocation.X); - break; - } - } - } - - public int GetBuildTime(String unitString) - { - var unit = Rules.Info[unitString]; - if (unit == null || ! unit.Traits.Contains()) - return 0; - - if (self.World.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait().FastBuild) return 0; - var cost = unit.Traits.Contains() ? unit.Traits.Get().Cost : 0; - var time = cost - * Info.BuildSpeed - * (25 * 60) /* frames per min */ /* todo: build acceleration, if we do that */ - / 1000; - return (int) time; - } - - protected void CancelProduction(string itemName, int numberToCancel) - { - for (var i = 0; i < numberToCancel; i++) - CancelProductionInner(itemName); - } - - void CancelProductionInner(string itemName) - { - var lastIndex = Queue.FindLastIndex(a => a.Item == itemName); - - if (lastIndex > 0) - Queue.RemoveAt(lastIndex); - else if (lastIndex == 0) - { - var item = Queue[0]; - self.Owner.PlayerActor.Trait().GiveCash( - item.TotalCost - item.RemainingCost); // refund what has been paid - FinishProduction(); - } - } - - public void FinishProduction() - { - if (Queue.Count == 0) return; - Queue.RemoveAt(0); - } - - protected void BeginProduction( ProductionItem item ) - { - Queue.Add(item); - } - - protected static bool IsDisabledBuilding(Actor a) - { - return a.TraitsImplementing().Any(d => d.Disabled); - } - - // Builds a unit from the actor that holds this queue (1 queue per building) - // Returns false if the unit can't be built - protected virtual bool BuildUnit( string name ) - { - // Cannot produce if i'm dead - if (!self.IsInWorld || self.IsDead()) - { - CancelProduction(name, 1); - return true; - } - - var sp = self.TraitsImplementing().Where(p => p.Info.Produces.Contains(Info.Type)).FirstOrDefault(); - if (sp != null && !IsDisabledBuilding(self) && sp.Produce(self, Rules.Info[ name ])) - { - FinishProduction(); - return true; - } - return false; - } - } - - public class ProductionState - { - public bool Visible = false; - public bool Buildable = false; - public bool Sticky = false; - } - - public class ProductionItem - { - public readonly string Item; - public readonly ProductionQueue Queue; - public readonly int TotalTime; - public readonly int TotalCost; - public int RemainingTime { get; private set; } - public int RemainingCost { get; private set; } - - public bool Paused = false, Done = false; - public Action OnComplete; - public int slowdown = 0; - - public ProductionItem(ProductionQueue queue, string item, int time, int cost, Action onComplete) - { - if (time <= 0) time = 1; - Item = item; - RemainingTime = TotalTime = time; - RemainingCost = TotalCost = cost; - OnComplete = onComplete; - Queue = queue; - - //Log.Write("debug", "new ProductionItem: {0} time={1} cost={2}", item, time, cost); - } - - public void Tick(PlayerResources pr, PowerManager pm) - { - if (Done) - { - if (OnComplete != null) OnComplete(); - return; - } - - if (Paused) return; - - if (pm.PowerState != PowerState.Normal) - { - if (--slowdown <= 0) - slowdown = Queue.Info.LowPowerSlowdown; - else - return; - } - - var costThisFrame = RemainingCost / RemainingTime; - if (costThisFrame != 0 && !pr.TakeCash(costThisFrame)) return; - RemainingCost -= costThisFrame; - RemainingTime -= 1; - if (RemainingTime > 0) return; - - Done = true; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class ProductionQueueInfo : ITraitInfo + { + public readonly string Type = null; + public float BuildSpeed = 0.4f; + public readonly int LowPowerSlowdown = 3; + + public readonly string ReadyAudio = "unitrdy1.aud"; + public readonly string BlockedAudio = "nobuild1.aud"; + public readonly string QueuedAudio = "train1.aud"; + public readonly string OnHoldAudio = "onhold1.aud"; + public readonly string CancelledAudio = "cancld1.aud"; + + public virtual object Create(ActorInitializer init) { return new ProductionQueue(init.self, init.self.Owner.PlayerActor, this); } + } + + public class ProductionQueue : IResolveOrder, ITick, ITechTreeElement, INotifyCapture, ISync + { + public readonly Actor self; + public ProductionQueueInfo Info; + PowerManager PlayerPower; + PlayerResources PlayerResources; + + // A list of things we are currently building + public List Queue = new List(); + + [Sync] + public int QueueLength { get { return Queue.Count; } } + [Sync] + public int CurrentRemainingCost { get { return QueueLength == 0 ? 0 : Queue[0].RemainingCost; } } + [Sync] + public int CurrentRemainingTime { get { return QueueLength == 0 ? 0 : Queue[0].RemainingTime; } } + [Sync] + public int CurrentSlowdown { get { return QueueLength == 0 ? 0 : Queue[0].slowdown; } } + [Sync] + public bool CurrentPaused { get { return QueueLength == 0 ? false : Queue[0].Paused; } } + [Sync] + public bool CurrentDone { get { return QueueLength == 0 ? false : Queue[0].Done; } } + + // A list of things we could possibly build, even if our race doesn't normally get it + public Dictionary Produceable = new Dictionary(); + + public ProductionQueue( Actor self, Actor playerActor, ProductionQueueInfo info ) + { + this.self = self; + this.Info = info; + PlayerResources = playerActor.Trait(); + PlayerPower = playerActor.Trait(); + + var ttc = playerActor.Trait(); + + foreach (var a in AllBuildables(Info.Type)) + { + var bi = a.Traits.Get(); + // Can our race build this by satisfying normal prereqs? + var buildable = bi.Owner.Contains(self.Owner.Country.Race); + Produceable.Add( a, new ProductionState(){ Visible = buildable && !bi.Hidden } ); + if (buildable) + ttc.Add( a.Name, a.Traits.Get().Prerequisites.ToList(), this ); + } + } + + public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + { + PlayerPower = newOwner.PlayerActor.Trait(); + PlayerResources = newOwner.PlayerActor.Trait(); + Queue.Clear(); + // Produceable contains the tech from the original owner - this is desired so we don't clear it. + } + + IEnumerable AllBuildables(string category) + { + return Rules.Info.Values + .Where( x => x.Name[ 0 ] != '^' ) + .Where( x => x.Traits.Contains() ) + .Where( x => x.Traits.Get().Queue == category ); + } + + public void OverrideProduction(ActorInfo type, bool buildable) + { + Produceable[type].Buildable = buildable; + Produceable[type].Sticky = true; + } + + public void PrerequisitesAvailable(string key) + { + var ps = Produceable[ Rules.Info[key] ]; + if (!ps.Sticky) + ps.Buildable = true; + } + + public void PrerequisitesUnavailable(string key) + { + var ps = Produceable[ Rules.Info[key] ]; + if (!ps.Sticky) + ps.Buildable = false; + } + + public ProductionItem CurrentItem() + { + return Queue.ElementAtOrDefault(0); + } + + public IEnumerable AllQueued() + { + return Queue; + } + + public virtual IEnumerable AllItems() + { + if (self.World.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait().AllTech) + return Produceable.Select(a => a.Key); + + return Produceable.Where(a => a.Value.Buildable || a.Value.Visible).Select(a => a.Key); + } + + public virtual IEnumerable BuildableItems() + { + if (self.World.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait().AllTech) + return Produceable.Select(a => a.Key); + + return Produceable.Where(a => a.Value.Buildable).Select(a => a.Key); + } + + public bool CanBuild(ActorInfo actor) + { + return Produceable.ContainsKey(actor) && Produceable[actor].Buildable; + } + + public virtual void Tick( Actor self ) + { + while( Queue.Count > 0 && !BuildableItems().Any(b => b.Name == Queue[ 0 ].Item) ) + { + self.Owner.PlayerActor.Trait().GiveCash(Queue[0].TotalCost - Queue[0].RemainingCost); // refund what's been paid so far. + FinishProduction(); + } + if( Queue.Count > 0 ) + Queue[ 0 ].Tick( PlayerResources, PlayerPower ); + } + + public void ResolveOrder( Actor self, Order order ) + { + switch( order.OrderString ) + { + case "StartProduction": + { + var unit = Rules.Info[order.TargetString]; + var bi = unit.Traits.Get(); + if (bi.Queue != Info.Type) + return; /* Not built by this queue */ + + var cost = unit.Traits.Contains() ? unit.Traits.Get().Cost : 0; + var time = GetBuildTime(order.TargetString); + + if (!BuildableItems().Any(b => b.Name == order.TargetString)) + return; /* you can't build that!! */ + + for (var n = 0; n < order.TargetLocation.X; n++) // repeat count + { + bool hasPlayedSound = false; + BeginProduction(new ProductionItem(this, order.TargetString, (int)time, cost, + () => self.World.AddFrameEndTask( + _ => + { + var isBuilding = unit.Traits.Contains(); + + if (isBuilding && !hasPlayedSound) + { + Sound.PlayToPlayer(order.Player, Info.ReadyAudio); + hasPlayedSound = true; + } + else if (!isBuilding) + { + if (BuildUnit(order.TargetString)) + Sound.PlayToPlayer(order.Player, Info.ReadyAudio); + else if (!hasPlayedSound && time > 0) + { + Sound.PlayToPlayer(order.Player, Info.BlockedAudio); + hasPlayedSound = true; + } + } + }))); + } + break; + } + case "PauseProduction": + { + if( Queue.Count > 0 && Queue[0].Item == order.TargetString ) + Queue[0].Paused = ( order.TargetLocation.X != 0 ); + break; + } + case "CancelProduction": + { + CancelProduction(order.TargetString,order.TargetLocation.X); + break; + } + } + } + + public int GetBuildTime(String unitString) + { + var unit = Rules.Info[unitString]; + if (unit == null || ! unit.Traits.Contains()) + return 0; + + if (self.World.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait().FastBuild) return 0; + var cost = unit.Traits.Contains() ? unit.Traits.Get().Cost : 0; + var time = cost + * Info.BuildSpeed + * (25 * 60) /* frames per min */ /* todo: build acceleration, if we do that */ + / 1000; + return (int) time; + } + + protected void CancelProduction(string itemName, int numberToCancel) + { + for (var i = 0; i < numberToCancel; i++) + CancelProductionInner(itemName); + } + + void CancelProductionInner(string itemName) + { + var lastIndex = Queue.FindLastIndex(a => a.Item == itemName); + + if (lastIndex > 0) + Queue.RemoveAt(lastIndex); + else if (lastIndex == 0) + { + var item = Queue[0]; + self.Owner.PlayerActor.Trait().GiveCash( + item.TotalCost - item.RemainingCost); // refund what has been paid + FinishProduction(); + } + } + + public void FinishProduction() + { + if (Queue.Count == 0) return; + Queue.RemoveAt(0); + } + + protected void BeginProduction( ProductionItem item ) + { + Queue.Add(item); + } + + protected static bool IsDisabledBuilding(Actor a) + { + return a.TraitsImplementing().Any(d => d.Disabled); + } + + // Builds a unit from the actor that holds this queue (1 queue per building) + // Returns false if the unit can't be built + protected virtual bool BuildUnit( string name ) + { + // Cannot produce if i'm dead + if (!self.IsInWorld || self.IsDead()) + { + CancelProduction(name, 1); + return true; + } + + var sp = self.TraitsImplementing().Where(p => p.Info.Produces.Contains(Info.Type)).FirstOrDefault(); + if (sp != null && !IsDisabledBuilding(self) && sp.Produce(self, Rules.Info[ name ])) + { + FinishProduction(); + return true; + } + return false; + } + } + + public class ProductionState + { + public bool Visible = false; + public bool Buildable = false; + public bool Sticky = false; + } + + public class ProductionItem + { + public readonly string Item; + public readonly ProductionQueue Queue; + public readonly int TotalTime; + public readonly int TotalCost; + public int RemainingTime { get; private set; } + public int RemainingCost { get; private set; } + + public bool Paused = false, Done = false; + public Action OnComplete; + public int slowdown = 0; + + public ProductionItem(ProductionQueue queue, string item, int time, int cost, Action onComplete) + { + if (time <= 0) time = 1; + Item = item; + RemainingTime = TotalTime = time; + RemainingCost = TotalCost = cost; + OnComplete = onComplete; + Queue = queue; + + //Log.Write("debug", "new ProductionItem: {0} time={1} cost={2}", item, time, cost); + } + + public void Tick(PlayerResources pr, PowerManager pm) + { + if (Done) + { + if (OnComplete != null) OnComplete(); + return; + } + + if (Paused) return; + + if (pm.PowerState != PowerState.Normal) + { + if (--slowdown <= 0) + slowdown = Queue.Info.LowPowerSlowdown; + else + return; + } + + var costThisFrame = RemainingCost / RemainingTime; + if (costThisFrame != 0 && !pr.TakeCash(costThisFrame)) return; + RemainingCost -= costThisFrame; + RemainingTime -= 1; + if (RemainingTime > 0) return; + + Done = true; + } + } +} diff --git a/OpenRA.Mods.RA/Player/SurrenderOnDisconnect.cs b/OpenRA.Mods.RA/Player/SurrenderOnDisconnect.cs index 8c27a68d58..6b4451ba80 100644 --- a/OpenRA.Mods.RA/Player/SurrenderOnDisconnect.cs +++ b/OpenRA.Mods.RA/Player/SurrenderOnDisconnect.cs @@ -1,44 +1,44 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Network; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class SurrenderOnDisconnectInfo : TraitInfo - { - - } - - class SurrenderOnDisconnect : ITick - { - private bool Disconnected = false; - - public void Tick(Actor self) - { - if (Disconnected) return; - - var p = self.Owner; - - if (p.WinState == WinState.Lost || p.WinState == WinState.Won) return; /* already won or lost */ - - var client = p.World.LobbyInfo.ClientWithIndex(p.ClientIndex); - if (client == null) - return; - - if (client.State == Session.ClientState.Disconnected) - { - Disconnected = true; /* dont call this multiple times! */ - self.World.players.Do(pl => pl.Value.PlayerActor.TraitsImplementing().Do(t => t.ResolveOrder(pl.Value.PlayerActor, new Order("Surrender", self, false)))); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Network; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class SurrenderOnDisconnectInfo : TraitInfo + { + + } + + class SurrenderOnDisconnect : ITick + { + private bool Disconnected = false; + + public void Tick(Actor self) + { + if (Disconnected) return; + + var p = self.Owner; + + if (p.WinState == WinState.Lost || p.WinState == WinState.Won) return; /* already won or lost */ + + var client = p.World.LobbyInfo.ClientWithIndex(p.ClientIndex); + if (client == null) + return; + + if (client.State == Session.ClientState.Disconnected) + { + Disconnected = true; /* dont call this multiple times! */ + self.World.players.Do(pl => pl.Value.PlayerActor.TraitsImplementing().Do(t => t.ResolveOrder(pl.Value.PlayerActor, new Order("Surrender", self, false)))); + } + } + } +} diff --git a/OpenRA.Mods.RA/PrimaryBuilding.cs b/OpenRA.Mods.RA/PrimaryBuilding.cs index 8d3cbfdab9..075f08b7f4 100755 --- a/OpenRA.Mods.RA/PrimaryBuilding.cs +++ b/OpenRA.Mods.RA/PrimaryBuilding.cs @@ -1,80 +1,80 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; -using OpenRA.Mods.RA.Orders; - -namespace OpenRA.Mods.RA -{ - class PrimaryBuildingInfo : TraitInfo { } - - class PrimaryBuilding : IIssueOrder, IResolveOrder, ITags - { - bool isPrimary = false; - public bool IsPrimary { get { return isPrimary; } } - - public IEnumerable GetTags() - { - yield return (isPrimary) ? TagType.Primary : TagType.None; - } - - public IEnumerable Orders - { - get { yield return new DeployOrderTargeter( "PrimaryProducer", 1 ); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "PrimaryProducer" ) - return new Order( order.OrderID, self, false ); - - return null; - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "PrimaryProducer") - SetPrimaryProducer(self, !isPrimary); - } - - public void SetPrimaryProducer(Actor self, bool state) - { - if (state == false) - { - isPrimary = false; - return; - } - - // Cancel existing primaries - foreach (var p in self.Info.Traits.Get().Produces) - foreach (var b in self.World.Queries.OwnedBy[self.Owner] - .WithTrait() - .Where(x => x.Trait.IsPrimary - && (x.Actor.Info.Traits.Get().Produces.Contains(p)))) - b.Trait.SetPrimaryProducer(b.Actor, false); - - isPrimary = true; - - var eva = self.World.WorldActor.Info.Traits.Get(); - Sound.PlayToPlayer(self.Owner, eva.PrimaryBuildingSelected); - } - } - - static class PrimaryExts - { - public static bool IsPrimaryBuilding(this Actor a) - { - var pb = a.TraitOrDefault(); - return pb != null && pb.IsPrimary; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; +using OpenRA.Mods.RA.Orders; + +namespace OpenRA.Mods.RA +{ + class PrimaryBuildingInfo : TraitInfo { } + + class PrimaryBuilding : IIssueOrder, IResolveOrder, ITags + { + bool isPrimary = false; + public bool IsPrimary { get { return isPrimary; } } + + public IEnumerable GetTags() + { + yield return (isPrimary) ? TagType.Primary : TagType.None; + } + + public IEnumerable Orders + { + get { yield return new DeployOrderTargeter( "PrimaryProducer", 1 ); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "PrimaryProducer" ) + return new Order( order.OrderID, self, false ); + + return null; + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "PrimaryProducer") + SetPrimaryProducer(self, !isPrimary); + } + + public void SetPrimaryProducer(Actor self, bool state) + { + if (state == false) + { + isPrimary = false; + return; + } + + // Cancel existing primaries + foreach (var p in self.Info.Traits.Get().Produces) + foreach (var b in self.World.Queries.OwnedBy[self.Owner] + .WithTrait() + .Where(x => x.Trait.IsPrimary + && (x.Actor.Info.Traits.Get().Produces.Contains(p)))) + b.Trait.SetPrimaryProducer(b.Actor, false); + + isPrimary = true; + + var eva = self.World.WorldActor.Info.Traits.Get(); + Sound.PlayToPlayer(self.Owner, eva.PrimaryBuildingSelected); + } + } + + static class PrimaryExts + { + public static bool IsPrimaryBuilding(this Actor a) + { + var pb = a.TraitOrDefault(); + return pb != null && pb.IsPrimary; + } + } +} diff --git a/OpenRA.Mods.RA/Production.cs b/OpenRA.Mods.RA/Production.cs index 1945879ea3..98bbf8326c 100755 --- a/OpenRA.Mods.RA/Production.cs +++ b/OpenRA.Mods.RA/Production.cs @@ -1,132 +1,132 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Move; -using OpenRA.Mods.RA.Air; - -namespace OpenRA.Mods.RA -{ - public class ProductionInfo : ITraitInfo - { - public readonly string[] Produces = { }; - - public virtual object Create(ActorInitializer init) { return new Production(this); } - } - - public class ExitInfo : TraitInfo - { - public readonly int2 SpawnOffset = int2.Zero; // in px relative to CenterLocation - public readonly int2 ExitCell = int2.Zero; // in cells relative to TopLeft - public readonly int Facing = -1; - } - public class Exit {} - - public class Production - { - public ProductionInfo Info; - public Production(ProductionInfo info) - { - Info = info; - } - - public void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo) - { - var newUnit = self.World.CreateActor(false, producee.Name, new TypeDictionary - { - new OwnerInit( self.Owner ), - }); - - var exit = self.Location + exitinfo.ExitCell; - var spawn = self.Trait().PxPosition + exitinfo.SpawnOffset; - - var teleportable = newUnit.Trait(); - var facing = newUnit.TraitOrDefault(); - - // Set the physical position of the unit as the exit cell - teleportable.SetPosition(newUnit,exit); - var to = Util.CenterOfCell(exit); - teleportable.AdjustPxPosition(newUnit, spawn); - if (facing != null) - facing.Facing = exitinfo.Facing < 0 ? Util.GetFacing(to - spawn, facing.Facing) : exitinfo.Facing; - self.World.Add(newUnit); - - var mobile = newUnit.TraitOrDefault(); - if (mobile != null) - { - // Animate the spawn -> exit transition - var speed = mobile.MovementSpeedForCell(newUnit, exit); - var length = speed > 0 ? (int)((to - spawn).Length * 3 / speed) : 0; - newUnit.QueueActivity(new Drag(spawn, to, length)); - } - - var target = MoveToRallyPoint(self, newUnit, exit); - - newUnit.SetTargetLine(Target.FromCell(target), Color.Green, false); - foreach (var t in self.TraitsImplementing()) - t.UnitProduced(self, newUnit, exit); - } - - static int2 MoveToRallyPoint(Actor self, Actor newUnit, int2 exitLocation) - { - var rp = self.TraitOrDefault(); - if (rp == null) - return exitLocation; - - var mobile = newUnit.TraitOrDefault(); - if (mobile != null) - { - newUnit.QueueActivity(mobile.MoveTo(rp.rallyPoint, 1)); - return rp.rallyPoint; - } - - // todo: don't talk about HeliFly here. - var helicopter = newUnit.TraitOrDefault(); - if (helicopter != null) - { - newUnit.QueueActivity(new HeliFly(Util.CenterOfCell(rp.rallyPoint))); - return rp.rallyPoint; - } - - return exitLocation; - } - - public virtual bool Produce(Actor self, ActorInfo producee) - { - if (Reservable.IsReserved(self)) - return false; - - // pick a spawn/exit point pair - var exit = self.Info.Traits.WithInterface().Shuffle(self.World.SharedRandom) - .FirstOrDefault(e => CanUseExit(self, producee, e)); - - if (exit != null) - { - DoProduction(self, producee, exit); - return true; - } - - return false; - } - - static bool CanUseExit(Actor self, ActorInfo producee, ExitInfo s) - { - var uim = self.World.WorldActor.Trait(); - var mobileInfo = producee.Traits.GetOrDefault(); - - return mobileInfo == null || - mobileInfo.CanEnterCell(self.World, uim, self.Location + s.ExitCell, self, true); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Move; +using OpenRA.Mods.RA.Air; + +namespace OpenRA.Mods.RA +{ + public class ProductionInfo : ITraitInfo + { + public readonly string[] Produces = { }; + + public virtual object Create(ActorInitializer init) { return new Production(this); } + } + + public class ExitInfo : TraitInfo + { + public readonly int2 SpawnOffset = int2.Zero; // in px relative to CenterLocation + public readonly int2 ExitCell = int2.Zero; // in cells relative to TopLeft + public readonly int Facing = -1; + } + public class Exit {} + + public class Production + { + public ProductionInfo Info; + public Production(ProductionInfo info) + { + Info = info; + } + + public void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo) + { + var newUnit = self.World.CreateActor(false, producee.Name, new TypeDictionary + { + new OwnerInit( self.Owner ), + }); + + var exit = self.Location + exitinfo.ExitCell; + var spawn = self.Trait().PxPosition + exitinfo.SpawnOffset; + + var teleportable = newUnit.Trait(); + var facing = newUnit.TraitOrDefault(); + + // Set the physical position of the unit as the exit cell + teleportable.SetPosition(newUnit,exit); + var to = Util.CenterOfCell(exit); + teleportable.AdjustPxPosition(newUnit, spawn); + if (facing != null) + facing.Facing = exitinfo.Facing < 0 ? Util.GetFacing(to - spawn, facing.Facing) : exitinfo.Facing; + self.World.Add(newUnit); + + var mobile = newUnit.TraitOrDefault(); + if (mobile != null) + { + // Animate the spawn -> exit transition + var speed = mobile.MovementSpeedForCell(newUnit, exit); + var length = speed > 0 ? (int)((to - spawn).Length * 3 / speed) : 0; + newUnit.QueueActivity(new Drag(spawn, to, length)); + } + + var target = MoveToRallyPoint(self, newUnit, exit); + + newUnit.SetTargetLine(Target.FromCell(target), Color.Green, false); + foreach (var t in self.TraitsImplementing()) + t.UnitProduced(self, newUnit, exit); + } + + static int2 MoveToRallyPoint(Actor self, Actor newUnit, int2 exitLocation) + { + var rp = self.TraitOrDefault(); + if (rp == null) + return exitLocation; + + var mobile = newUnit.TraitOrDefault(); + if (mobile != null) + { + newUnit.QueueActivity(mobile.MoveTo(rp.rallyPoint, 1)); + return rp.rallyPoint; + } + + // todo: don't talk about HeliFly here. + var helicopter = newUnit.TraitOrDefault(); + if (helicopter != null) + { + newUnit.QueueActivity(new HeliFly(Util.CenterOfCell(rp.rallyPoint))); + return rp.rallyPoint; + } + + return exitLocation; + } + + public virtual bool Produce(Actor self, ActorInfo producee) + { + if (Reservable.IsReserved(self)) + return false; + + // pick a spawn/exit point pair + var exit = self.Info.Traits.WithInterface().Shuffle(self.World.SharedRandom) + .FirstOrDefault(e => CanUseExit(self, producee, e)); + + if (exit != null) + { + DoProduction(self, producee, exit); + return true; + } + + return false; + } + + static bool CanUseExit(Actor self, ActorInfo producee, ExitInfo s) + { + var uim = self.World.WorldActor.Trait(); + var mobileInfo = producee.Traits.GetOrDefault(); + + return mobileInfo == null || + mobileInfo.CanEnterCell(self.World, uim, self.Location + s.ExitCell, self, true); + } + } +} diff --git a/OpenRA.Mods.RA/ProvidesRadar.cs b/OpenRA.Mods.RA/ProvidesRadar.cs index ba5f838607..c01d46bdf9 100755 --- a/OpenRA.Mods.RA/ProvidesRadar.cs +++ b/OpenRA.Mods.RA/ProvidesRadar.cs @@ -1,40 +1,40 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class ProvidesRadarInfo : TraitInfo { } - - public class ProvidesRadar : ITick - { - public bool IsActive { get; private set; } - - public void Tick(Actor self) { IsActive = UpdateActive(self); } - - bool UpdateActive(Actor self) - { - // Check if powered - if (self.TraitsImplementing().Any(d => d.Disabled)) - return false; - - var isJammed = self.World.Queries.WithTrait().Any(a => self.Owner != a.Actor.Owner - && (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get().Range); - - return !isJammed; - } - } - - class JamsRadarInfo : TraitInfo { public readonly int Range = 0; } - - class JamsRadar { } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class ProvidesRadarInfo : TraitInfo { } + + public class ProvidesRadar : ITick + { + public bool IsActive { get; private set; } + + public void Tick(Actor self) { IsActive = UpdateActive(self); } + + bool UpdateActive(Actor self) + { + // Check if powered + if (self.TraitsImplementing().Any(d => d.Disabled)) + return false; + + var isJammed = self.World.Queries.WithTrait().Any(a => self.Owner != a.Actor.Owner + && (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get().Range); + + return !isJammed; + } + } + + class JamsRadarInfo : TraitInfo { public readonly int Range = 0; } + + class JamsRadar { } +} diff --git a/OpenRA.Mods.RA/ProximityCaptor.cs b/OpenRA.Mods.RA/ProximityCaptor.cs index 020106f5ba..1a1e86a267 100644 --- a/OpenRA.Mods.RA/ProximityCaptor.cs +++ b/OpenRA.Mods.RA/ProximityCaptor.cs @@ -1,48 +1,48 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class ProximityCaptorInfo : ITraitInfo - { - public readonly string[] Types = {}; - public object Create(ActorInitializer init) { return new ProximityCaptor(this); } - } - - public class ProximityCaptor - { - public readonly ProximityCaptorInfo Info; - - public string[] Types; - - [Sync] - public int Hash { get { return string.Join(",", Types).GetHashCode(); } } - - public ProximityCaptor(ProximityCaptorInfo info) - { - Info = info; - - Types = info.Types.Select(t => t.ToLowerInvariant()).OrderBy(t => t).ToArray(); - } - - public bool HasAny(string[] typesList) - { - return typesList.Select(t => t.ToLowerInvariant()).Any(flag => Types.Contains(flag)); - } - - public bool HasAll(string[] typesList) - { - return typesList.Select(t => t.ToLowerInvariant()).All(flag => Types.Contains(flag)); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class ProximityCaptorInfo : ITraitInfo + { + public readonly string[] Types = {}; + public object Create(ActorInitializer init) { return new ProximityCaptor(this); } + } + + public class ProximityCaptor + { + public readonly ProximityCaptorInfo Info; + + public string[] Types; + + [Sync] + public int Hash { get { return string.Join(",", Types).GetHashCode(); } } + + public ProximityCaptor(ProximityCaptorInfo info) + { + Info = info; + + Types = info.Types.Select(t => t.ToLowerInvariant()).OrderBy(t => t).ToArray(); + } + + public bool HasAny(string[] typesList) + { + return typesList.Select(t => t.ToLowerInvariant()).Any(flag => Types.Contains(flag)); + } + + public bool HasAll(string[] typesList) + { + return typesList.Select(t => t.ToLowerInvariant()).All(flag => Types.Contains(flag)); + } + } +} diff --git a/OpenRA.Mods.RA/RALoadScreen.cs b/OpenRA.Mods.RA/RALoadScreen.cs index d32b19da44..ec03594ce3 100644 --- a/OpenRA.Mods.RA/RALoadScreen.cs +++ b/OpenRA.Mods.RA/RALoadScreen.cs @@ -1,10 +1,10 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ #endregion @@ -64,7 +64,7 @@ namespace OpenRA.Mods.RA r.BeginFrame(float2.Zero); WidgetUtils.FillRectWithSprite(StripeRect, Stripe); r.RgbaSpriteRenderer.DrawSprite(Logo, LogoPos); - Font.DrawText(text, new float2(Renderer.Resolution.Width - textSize.X - 20, Renderer.Resolution.Height - textSize.Y - 20), Color.White); + Font.DrawText(text, new float2(Renderer.Resolution.Width - textSize.X - 20, Renderer.Resolution.Height - textSize.Y - 20), Color.White); r.EndFrame( new NullInputHandler() ); } } diff --git a/OpenRA.Mods.RA/RadarColorFromTerrain.cs b/OpenRA.Mods.RA/RadarColorFromTerrain.cs index 88a3b8f18a..4907286bc5 100644 --- a/OpenRA.Mods.RA/RadarColorFromTerrain.cs +++ b/OpenRA.Mods.RA/RadarColorFromTerrain.cs @@ -1,14 +1,14 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Drawing; +#endregion + +using System.Drawing; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -31,6 +31,6 @@ namespace OpenRA.Mods.RA public Color RadarColorOverride(Actor self) { return c; - } + } } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/RallyPoint.cs b/OpenRA.Mods.RA/RallyPoint.cs index d77e44bc55..5d94a7468b 100755 --- a/OpenRA.Mods.RA/RallyPoint.cs +++ b/OpenRA.Mods.RA/RallyPoint.cs @@ -1,80 +1,80 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Traits; -using OpenRA.Mods.RA.Effects; - -namespace OpenRA.Mods.RA -{ - class RallyPointInfo : ITraitInfo, ITraitPrerequisite - { - public readonly int[] RallyPoint = { 1, 3 }; - - public object Create(ActorInitializer init) { return new RallyPoint(init.self); } - } - - public class RallyPoint : IIssueOrder, IResolveOrder, ISync - { - [Sync] - public int2 rallyPoint; - - public RallyPoint(Actor self) - { - var info = self.Info.Traits.Get(); - rallyPoint = self.Location + new int2(info.RallyPoint[0], info.RallyPoint[1]); - self.World.AddFrameEndTask(w => w.Add(new Effects.RallyPoint(self))); - } - - public IEnumerable Orders - { - get { yield return new RallyPointOrderTargeter(); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "SetRallyPoint" ) - return new Order(order.OrderID, self, false) { TargetLocation = Traits.Util.CellContaining(target.CenterLocation) }; - - return null; - } - - public void ResolveOrder( Actor self, Order order ) - { - if( order.OrderString == "SetRallyPoint" ) - rallyPoint = order.TargetLocation; - } - - class RallyPointOrderTargeter : IOrderTargeter - { - public string OrderID { get { return "SetRallyPoint"; } } - public int OrderPriority { get { return 0; } } - - public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - return false; - } - - public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) - { - if (self.World.Map.IsInMap(location)) - { - cursor = "ability"; - return true; - } - return false; - } - - public bool IsQueued { get { return false; } } // unused - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Traits; +using OpenRA.Mods.RA.Effects; + +namespace OpenRA.Mods.RA +{ + class RallyPointInfo : ITraitInfo, ITraitPrerequisite + { + public readonly int[] RallyPoint = { 1, 3 }; + + public object Create(ActorInitializer init) { return new RallyPoint(init.self); } + } + + public class RallyPoint : IIssueOrder, IResolveOrder, ISync + { + [Sync] + public int2 rallyPoint; + + public RallyPoint(Actor self) + { + var info = self.Info.Traits.Get(); + rallyPoint = self.Location + new int2(info.RallyPoint[0], info.RallyPoint[1]); + self.World.AddFrameEndTask(w => w.Add(new Effects.RallyPoint(self))); + } + + public IEnumerable Orders + { + get { yield return new RallyPointOrderTargeter(); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "SetRallyPoint" ) + return new Order(order.OrderID, self, false) { TargetLocation = Traits.Util.CellContaining(target.CenterLocation) }; + + return null; + } + + public void ResolveOrder( Actor self, Order order ) + { + if( order.OrderString == "SetRallyPoint" ) + rallyPoint = order.TargetLocation; + } + + class RallyPointOrderTargeter : IOrderTargeter + { + public string OrderID { get { return "SetRallyPoint"; } } + public int OrderPriority { get { return 0; } } + + public bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + return false; + } + + public bool CanTargetLocation(Actor self, int2 location, List actorsAtLocation, bool forceAttack, bool forceMove, bool forceQueued, ref string cursor) + { + if (self.World.Map.IsInMap(location)) + { + cursor = "ability"; + return true; + } + return false; + } + + public bool IsQueued { get { return false; } } // unused + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderBuilding.cs b/OpenRA.Mods.RA/Render/RenderBuilding.cs index a4c7b033bc..436db9cf98 100755 --- a/OpenRA.Mods.RA/Render/RenderBuilding.cs +++ b/OpenRA.Mods.RA/Render/RenderBuilding.cs @@ -1,125 +1,125 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Effects; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Render -{ - public class RenderBuildingInfo : RenderSimpleInfo - { - public readonly bool HasMakeAnimation = true; - public readonly float2 Origin = float2.Zero; - public override object Create(ActorInitializer init) { return new RenderBuilding(init);} - - public override IEnumerable RenderPreview(ActorInfo building, string Tileset) - { - var rb = building.Traits.Get(); - return base.RenderPreview(building, Tileset) - .Select(a => a.WithPos(a.Pos + rb.Origin)); - } - } - - public class RenderBuilding : RenderSimple, INotifyDamage, INotifySold, IRenderModifier - { - readonly float2 Origin; - - public RenderBuilding( ActorInitializer init ) - : this( init, () => 0 ) - { - Origin = init.self.Info.Traits.Get().Origin; - } - - public IEnumerable ModifyRender(Actor self, IEnumerable r) - { - var disabled = self.TraitsImplementing().Any(d => d.Disabled); - foreach (var a in r) - { - var ret = a.WithPos(a.Pos - Origin); - yield return ret; - if (disabled) - yield return ret.WithPalette("disabled").WithZOffset(1); - } - } - - public RenderBuilding( ActorInitializer init, Func baseFacing ) - : base(init.self, baseFacing) - { - var self = init.self; - if( init.Contains() || !self.Info.Traits.Get().HasMakeAnimation ) - anim.PlayThen( "idle", () => self.World.AddFrameEndTask( _ => Complete( self ) ) ); - else - anim.PlayThen( "make", () => self.World.AddFrameEndTask( _ => Complete( self ) ) ); - } - - void Complete( Actor self ) - { - anim.PlayRepeating( NormalizeSequence(self, "idle") ); - foreach( var x in self.TraitsImplementing() ) - x.BuildingComplete( self ); - } - - public void PlayCustomAnimThen(Actor self, string name, Action a) - { - anim.PlayThen(NormalizeSequence(self, name), - () => { anim.PlayRepeating(NormalizeSequence(self, "idle")); a(); }); - } - - public void PlayCustomAnimRepeating(Actor self, string name) - { - anim.PlayThen(NormalizeSequence(self, name), - () => { PlayCustomAnimRepeating(self, name); }); - } - - public void PlayCustomAnimBackwards(Actor self, string name, Action a) - { - anim.PlayBackwardsThen(NormalizeSequence(self, name), - () => { anim.PlayRepeating(NormalizeSequence(self, "idle")); a(); }); - } - - public void CancelCustomAnim(Actor self) - { - anim.PlayRepeating( NormalizeSequence(self, "idle") ); - } - - public virtual void Damaged(Actor self, AttackInfo e) - { - if (!e.DamageStateChanged) - return; - - if (e.DamageState == DamageState.Dead) - foreach (var t in FootprintUtils.UnpathableTiles( self.Info.Name, self.Info.Traits.Get(), self.Location )) - { - var cell = t; // required: c# fails at bindings - self.World.AddFrameEndTask(w => w.Add(new Explosion(w, Traits.Util.CenterOfCell(cell), "building", false, 0))); - } - else if (e.DamageState >= DamageState.Heavy && e.PreviousDamageState < DamageState.Heavy) - anim.ReplaceAnim("damaged-idle"); - else if (e.DamageState < DamageState.Heavy) - anim.ReplaceAnim("idle"); - } - - public virtual void Selling( Actor self ) - { - if( self.Info.Traits.Get().HasMakeAnimation ) - anim.PlayBackwardsThen( "make", null ); - - foreach (var s in self.Info.Traits.Get().SellSounds) - Sound.PlayToPlayer(self.Owner, s, self.CenterLocation); - } - - public void Sold(Actor self) {} - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Effects; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + public class RenderBuildingInfo : RenderSimpleInfo + { + public readonly bool HasMakeAnimation = true; + public readonly float2 Origin = float2.Zero; + public override object Create(ActorInitializer init) { return new RenderBuilding(init);} + + public override IEnumerable RenderPreview(ActorInfo building, string Tileset) + { + var rb = building.Traits.Get(); + return base.RenderPreview(building, Tileset) + .Select(a => a.WithPos(a.Pos + rb.Origin)); + } + } + + public class RenderBuilding : RenderSimple, INotifyDamage, INotifySold, IRenderModifier + { + readonly float2 Origin; + + public RenderBuilding( ActorInitializer init ) + : this( init, () => 0 ) + { + Origin = init.self.Info.Traits.Get().Origin; + } + + public IEnumerable ModifyRender(Actor self, IEnumerable r) + { + var disabled = self.TraitsImplementing().Any(d => d.Disabled); + foreach (var a in r) + { + var ret = a.WithPos(a.Pos - Origin); + yield return ret; + if (disabled) + yield return ret.WithPalette("disabled").WithZOffset(1); + } + } + + public RenderBuilding( ActorInitializer init, Func baseFacing ) + : base(init.self, baseFacing) + { + var self = init.self; + if( init.Contains() || !self.Info.Traits.Get().HasMakeAnimation ) + anim.PlayThen( "idle", () => self.World.AddFrameEndTask( _ => Complete( self ) ) ); + else + anim.PlayThen( "make", () => self.World.AddFrameEndTask( _ => Complete( self ) ) ); + } + + void Complete( Actor self ) + { + anim.PlayRepeating( NormalizeSequence(self, "idle") ); + foreach( var x in self.TraitsImplementing() ) + x.BuildingComplete( self ); + } + + public void PlayCustomAnimThen(Actor self, string name, Action a) + { + anim.PlayThen(NormalizeSequence(self, name), + () => { anim.PlayRepeating(NormalizeSequence(self, "idle")); a(); }); + } + + public void PlayCustomAnimRepeating(Actor self, string name) + { + anim.PlayThen(NormalizeSequence(self, name), + () => { PlayCustomAnimRepeating(self, name); }); + } + + public void PlayCustomAnimBackwards(Actor self, string name, Action a) + { + anim.PlayBackwardsThen(NormalizeSequence(self, name), + () => { anim.PlayRepeating(NormalizeSequence(self, "idle")); a(); }); + } + + public void CancelCustomAnim(Actor self) + { + anim.PlayRepeating( NormalizeSequence(self, "idle") ); + } + + public virtual void Damaged(Actor self, AttackInfo e) + { + if (!e.DamageStateChanged) + return; + + if (e.DamageState == DamageState.Dead) + foreach (var t in FootprintUtils.UnpathableTiles( self.Info.Name, self.Info.Traits.Get(), self.Location )) + { + var cell = t; // required: c# fails at bindings + self.World.AddFrameEndTask(w => w.Add(new Explosion(w, Traits.Util.CenterOfCell(cell), "building", false, 0))); + } + else if (e.DamageState >= DamageState.Heavy && e.PreviousDamageState < DamageState.Heavy) + anim.ReplaceAnim("damaged-idle"); + else if (e.DamageState < DamageState.Heavy) + anim.ReplaceAnim("idle"); + } + + public virtual void Selling( Actor self ) + { + if( self.Info.Traits.Get().HasMakeAnimation ) + anim.PlayBackwardsThen( "make", null ); + + foreach (var s in self.Info.Traits.Get().SellSounds) + Sound.PlayToPlayer(self.Owner, s, self.CenterLocation); + } + + public void Sold(Actor self) {} + } +} diff --git a/OpenRA.Mods.RA/Render/RenderBuildingCharge.cs b/OpenRA.Mods.RA/Render/RenderBuildingCharge.cs index 6883cc6047..eafde6b651 100755 --- a/OpenRA.Mods.RA/Render/RenderBuildingCharge.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingCharge.cs @@ -1,34 +1,34 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -namespace OpenRA.Mods.RA.Render -{ - class RenderBuildingChargeInfo : RenderBuildingInfo - { - public readonly string ChargeAudio = "tslachg2.aud"; - public override object Create(ActorInitializer init) { return new RenderBuildingCharge(init); } - } - - /* used for tesla */ - public class RenderBuildingCharge : RenderBuilding - { - public RenderBuildingCharge( ActorInitializer init ) - : base(init) - { - } - - public void PlayCharge(Actor self) - { - Sound.Play(self.Info.Traits.Get().ChargeAudio, self.CenterLocation); - anim.PlayThen(NormalizeSequence(self, "active"), - () => anim.PlayRepeating(NormalizeSequence(self, "idle"))); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +namespace OpenRA.Mods.RA.Render +{ + class RenderBuildingChargeInfo : RenderBuildingInfo + { + public readonly string ChargeAudio = "tslachg2.aud"; + public override object Create(ActorInitializer init) { return new RenderBuildingCharge(init); } + } + + /* used for tesla */ + public class RenderBuildingCharge : RenderBuilding + { + public RenderBuildingCharge( ActorInitializer init ) + : base(init) + { + } + + public void PlayCharge(Actor self) + { + Sound.Play(self.Info.Traits.Get().ChargeAudio, self.CenterLocation); + anim.PlayThen(NormalizeSequence(self, "active"), + () => anim.PlayRepeating(NormalizeSequence(self, "idle"))); + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderBuildingOre.cs b/OpenRA.Mods.RA/Render/RenderBuildingOre.cs index 1e6f97174e..3f22fb9fb7 100755 --- a/OpenRA.Mods.RA/Render/RenderBuildingOre.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingOre.cs @@ -1,41 +1,41 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Render -{ - class RenderBuildingOreInfo : RenderBuildingInfo - { - public override object Create(ActorInitializer init) { return new RenderBuildingOre(init); } - } - - class RenderBuildingOre : RenderBuilding, INotifyBuildComplete, INotifyCapture - { - PlayerResources PlayerResources; - - public RenderBuildingOre( ActorInitializer init ) - : base(init) - { - PlayerResources = init.self.Owner.PlayerActor.Trait(); - } - - public void BuildingComplete( Actor self ) - { - anim.PlayFetchIndex( "idle", - () => (49 * PlayerResources.Ore) / (10*PlayerResources.OreCapacity)); - } - - public void OnCapture (Actor self, Actor captor, Player oldOwner, Player newOwner) - { - PlayerResources = newOwner.PlayerActor.Trait(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + class RenderBuildingOreInfo : RenderBuildingInfo + { + public override object Create(ActorInitializer init) { return new RenderBuildingOre(init); } + } + + class RenderBuildingOre : RenderBuilding, INotifyBuildComplete, INotifyCapture + { + PlayerResources PlayerResources; + + public RenderBuildingOre( ActorInitializer init ) + : base(init) + { + PlayerResources = init.self.Owner.PlayerActor.Trait(); + } + + public void BuildingComplete( Actor self ) + { + anim.PlayFetchIndex( "idle", + () => (49 * PlayerResources.Ore) / (10*PlayerResources.OreCapacity)); + } + + public void OnCapture (Actor self, Actor captor, Player oldOwner, Player newOwner) + { + PlayerResources = newOwner.PlayerActor.Trait(); + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderBuildingTurreted.cs b/OpenRA.Mods.RA/Render/RenderBuildingTurreted.cs index fc1ed8e561..5a8e6ba5c1 100644 --- a/OpenRA.Mods.RA/Render/RenderBuildingTurreted.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingTurreted.cs @@ -1,43 +1,43 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Render -{ - class RenderBuildingTurretedInfo : RenderBuildingInfo - { - public override object Create(ActorInitializer init) { return new RenderBuildingTurreted( init ); } - } - - class RenderBuildingTurreted : RenderBuilding, INotifyBuildComplete - { - public RenderBuildingTurreted( ActorInitializer init ) - : base(init, () => init.self.Trait().turretFacing) - { - } - - public void BuildingComplete( Actor self ) - { - anim.Play( "idle" ); - } - - public override void Damaged(Actor self, AttackInfo e) - { - if (!e.DamageStateChanged) return; - - if (e.DamageState >= DamageState.Heavy && e.PreviousDamageState < DamageState.Heavy) - anim.ReplaceAnim("damaged-idle"); - else if (e.DamageState < DamageState.Heavy) - anim.ReplaceAnim("idle"); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + class RenderBuildingTurretedInfo : RenderBuildingInfo + { + public override object Create(ActorInitializer init) { return new RenderBuildingTurreted( init ); } + } + + class RenderBuildingTurreted : RenderBuilding, INotifyBuildComplete + { + public RenderBuildingTurreted( ActorInitializer init ) + : base(init, () => init.self.Trait().turretFacing) + { + } + + public void BuildingComplete( Actor self ) + { + anim.Play( "idle" ); + } + + public override void Damaged(Actor self, AttackInfo e) + { + if (!e.DamageStateChanged) return; + + if (e.DamageState >= DamageState.Heavy && e.PreviousDamageState < DamageState.Heavy) + anim.ReplaceAnim("damaged-idle"); + else if (e.DamageState < DamageState.Heavy) + anim.ReplaceAnim("idle"); + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderBuildingWall.cs b/OpenRA.Mods.RA/Render/RenderBuildingWall.cs index 602edb751c..b8996c8250 100644 --- a/OpenRA.Mods.RA/Render/RenderBuildingWall.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingWall.cs @@ -1,78 +1,78 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Render -{ - class RenderBuildingWallInfo : RenderBuildingInfo - { - public override object Create(ActorInitializer init) { return new RenderBuildingWall(init); } - } - - class RenderBuildingWall : RenderBuilding - { - string seqName; - int adjacentWalls = 0; - - public RenderBuildingWall( ActorInitializer init ) - : base(init) - { - seqName = "idle"; - anim.PlayFetchIndex(seqName, () => adjacentWalls); - } - - public override void Damaged(Actor self, AttackInfo e) - { - if (!e.DamageStateChanged) return; - - if (e.DamageState == DamageState.Medium && anim.HasSequence("scratched-idle")) - seqName = "scratched-idle"; - else if (e.DamageState <= DamageState.Medium) - seqName = "idle"; - else if (e.DamageState == DamageState.Critical && anim.HasSequence("critical-idle")) - seqName = "critical-idle"; - else if (e.DamageState <= DamageState.Critical) - seqName = "damaged-idle"; - - anim.PlayFetchIndex(seqName, () => adjacentWalls); - } - - bool hasTicked = false; - public override void Tick(Actor self) - { - base.Tick(self); - - if (!hasTicked) - { - var oneCell = new float2(Game.CellSize, Game.CellSize); - var adjWalls = self.World.FindUnits(self.CenterLocation - oneCell, self.CenterLocation + oneCell) - .Where(a => a.Info == self.Info && a != self); - - foreach (var w in adjWalls) - { - w.Trait().AddAdjacentWall(w.Location, self.Location); - AddAdjacentWall(self.Location, w.Location); - } - hasTicked = true; - } - } - - void AddAdjacentWall(int2 location, int2 otherLocation) - { - if (otherLocation == location + new int2(0, -1)) adjacentWalls |= 1; - if (otherLocation == location + new int2(+1, 0)) adjacentWalls |= 2; - if (otherLocation == location + new int2(0, +1)) adjacentWalls |= 4; - if (otherLocation == location + new int2(-1, 0)) adjacentWalls |= 8; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + class RenderBuildingWallInfo : RenderBuildingInfo + { + public override object Create(ActorInitializer init) { return new RenderBuildingWall(init); } + } + + class RenderBuildingWall : RenderBuilding + { + string seqName; + int adjacentWalls = 0; + + public RenderBuildingWall( ActorInitializer init ) + : base(init) + { + seqName = "idle"; + anim.PlayFetchIndex(seqName, () => adjacentWalls); + } + + public override void Damaged(Actor self, AttackInfo e) + { + if (!e.DamageStateChanged) return; + + if (e.DamageState == DamageState.Medium && anim.HasSequence("scratched-idle")) + seqName = "scratched-idle"; + else if (e.DamageState <= DamageState.Medium) + seqName = "idle"; + else if (e.DamageState == DamageState.Critical && anim.HasSequence("critical-idle")) + seqName = "critical-idle"; + else if (e.DamageState <= DamageState.Critical) + seqName = "damaged-idle"; + + anim.PlayFetchIndex(seqName, () => adjacentWalls); + } + + bool hasTicked = false; + public override void Tick(Actor self) + { + base.Tick(self); + + if (!hasTicked) + { + var oneCell = new float2(Game.CellSize, Game.CellSize); + var adjWalls = self.World.FindUnits(self.CenterLocation - oneCell, self.CenterLocation + oneCell) + .Where(a => a.Info == self.Info && a != self); + + foreach (var w in adjWalls) + { + w.Trait().AddAdjacentWall(w.Location, self.Location); + AddAdjacentWall(self.Location, w.Location); + } + hasTicked = true; + } + } + + void AddAdjacentWall(int2 location, int2 otherLocation) + { + if (otherLocation == location + new int2(0, -1)) adjacentWalls |= 1; + if (otherLocation == location + new int2(+1, 0)) adjacentWalls |= 2; + if (otherLocation == location + new int2(0, +1)) adjacentWalls |= 4; + if (otherLocation == location + new int2(-1, 0)) adjacentWalls |= 8; + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs b/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs index 8c6ba5221a..e8ea26ffec 100755 --- a/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs @@ -1,96 +1,96 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Render -{ - class RenderWarFactoryInfo : RenderBuildingInfo - { - public override object Create(ActorInitializer init) { return new RenderWarFactory(init); } - - /* get around unverifiability */ - IEnumerable BaseBuildingPreview(ActorInfo building, string tileset) - { - return base.RenderPreview(building, tileset); - } - - public override IEnumerable RenderPreview(ActorInfo building, string Tileset) - { - foreach (var r in BaseBuildingPreview(building, Tileset)) - yield return r; - - var anim = new Animation(RenderSimple.GetImage(building, Tileset), () => 0); - anim.PlayRepeating("idle-top"); - var rb = building.Traits.Get(); - yield return new Renderable(anim.Image, rb.Origin + 0.5f*anim.Image.size*(1 - Scale), rb.Palette, 0, Scale); - } - } - - class RenderWarFactory : RenderBuilding, INotifyBuildComplete, INotifyDamage, ITick, INotifyProduction, INotifySold, ISync - { - public Animation roof; - [Sync] - bool isOpen; - [Sync] - int2 openExit; - - public RenderWarFactory(ActorInitializer init) - : base(init) - { - roof = new Animation(GetImage(init.self)); - } - - public void BuildingComplete( Actor self ) - { - roof.Play(NormalizeSequence(self, - self.GetDamageState() > DamageState.Heavy ? "damaged-idle-top" : "idle-top")); - self.Trait().anims.Add( "roof", new RenderSimple.AnimationWithOffset( roof ) { ZOffset = 24 } ); - } - - public override void Tick(Actor self) - { - base.Tick(self); - if (isOpen && !self.World.WorldActor.Trait() - .GetUnitsAt(openExit).Any( a => a != self )) - { - isOpen = false; - roof.PlayBackwardsThen(NormalizeSequence(self, "build-top"), () => roof.Play(NormalizeSequence(self, "idle-top"))); - } - } - - public override void Damaged(Actor self, AttackInfo e) - { - if (!e.DamageStateChanged) return; - - if (roof.CurrentSequence != null) - { - if (e.DamageState >= DamageState.Heavy) - roof.ReplaceAnim("damaged-" + roof.CurrentSequence.Name); - else - roof.ReplaceAnim(roof.CurrentSequence.Name.Replace("damaged-", "")); - } - } - - public void UnitProduced(Actor self, Actor other, int2 exit) - { - roof.PlayThen(NormalizeSequence(self, "build-top"), () => { isOpen = true; openExit = exit; }); - } - - public override void Selling( Actor self ) - { - self.Trait().anims.Remove( "roof" ); - base.Selling(self); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + class RenderWarFactoryInfo : RenderBuildingInfo + { + public override object Create(ActorInitializer init) { return new RenderWarFactory(init); } + + /* get around unverifiability */ + IEnumerable BaseBuildingPreview(ActorInfo building, string tileset) + { + return base.RenderPreview(building, tileset); + } + + public override IEnumerable RenderPreview(ActorInfo building, string Tileset) + { + foreach (var r in BaseBuildingPreview(building, Tileset)) + yield return r; + + var anim = new Animation(RenderSimple.GetImage(building, Tileset), () => 0); + anim.PlayRepeating("idle-top"); + var rb = building.Traits.Get(); + yield return new Renderable(anim.Image, rb.Origin + 0.5f*anim.Image.size*(1 - Scale), rb.Palette, 0, Scale); + } + } + + class RenderWarFactory : RenderBuilding, INotifyBuildComplete, INotifyDamage, ITick, INotifyProduction, INotifySold, ISync + { + public Animation roof; + [Sync] + bool isOpen; + [Sync] + int2 openExit; + + public RenderWarFactory(ActorInitializer init) + : base(init) + { + roof = new Animation(GetImage(init.self)); + } + + public void BuildingComplete( Actor self ) + { + roof.Play(NormalizeSequence(self, + self.GetDamageState() > DamageState.Heavy ? "damaged-idle-top" : "idle-top")); + self.Trait().anims.Add( "roof", new RenderSimple.AnimationWithOffset( roof ) { ZOffset = 24 } ); + } + + public override void Tick(Actor self) + { + base.Tick(self); + if (isOpen && !self.World.WorldActor.Trait() + .GetUnitsAt(openExit).Any( a => a != self )) + { + isOpen = false; + roof.PlayBackwardsThen(NormalizeSequence(self, "build-top"), () => roof.Play(NormalizeSequence(self, "idle-top"))); + } + } + + public override void Damaged(Actor self, AttackInfo e) + { + if (!e.DamageStateChanged) return; + + if (roof.CurrentSequence != null) + { + if (e.DamageState >= DamageState.Heavy) + roof.ReplaceAnim("damaged-" + roof.CurrentSequence.Name); + else + roof.ReplaceAnim(roof.CurrentSequence.Name.Replace("damaged-", "")); + } + } + + public void UnitProduced(Actor self, Actor other, int2 exit) + { + roof.PlayThen(NormalizeSequence(self, "build-top"), () => { isOpen = true; openExit = exit; }); + } + + public override void Selling( Actor self ) + { + self.Trait().anims.Remove( "roof" ); + base.Selling(self); + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderFlare.cs b/OpenRA.Mods.RA/Render/RenderFlare.cs index 898ac7f61c..e63641de88 100755 --- a/OpenRA.Mods.RA/Render/RenderFlare.cs +++ b/OpenRA.Mods.RA/Render/RenderFlare.cs @@ -1,28 +1,28 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Render -{ - class RenderFlareInfo : RenderSimpleInfo - { - public override object Create(ActorInitializer init) { return new RenderFlare(init.self); } - } - - class RenderFlare : RenderSimple - { - public RenderFlare(Actor self) - : base(self, () => 0) - { - anim.PlayThen("open", () => anim.PlayRepeating("idle")); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + class RenderFlareInfo : RenderSimpleInfo + { + public override object Create(ActorInitializer init) { return new RenderFlare(init.self); } + } + + class RenderFlare : RenderSimple + { + public RenderFlare(Actor self) + : base(self, () => 0) + { + anim.PlayThen("open", () => anim.PlayRepeating("idle")); + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderInfantry.cs b/OpenRA.Mods.RA/Render/RenderInfantry.cs index 5bd4237409..4ca3ce6015 100644 --- a/OpenRA.Mods.RA/Render/RenderInfantry.cs +++ b/OpenRA.Mods.RA/Render/RenderInfantry.cs @@ -1,91 +1,91 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Effects; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Move; - -namespace OpenRA.Mods.RA.Render -{ - public class RenderInfantryInfo : RenderSimpleInfo - { - public override object Create(ActorInitializer init) { return new RenderInfantry(init.self); } - } - - public class RenderInfantry : RenderSimple, INotifyAttack, INotifyDamage, INotifyIdle - { - public enum AnimationState - { - Idle, - Attacking, - Moving, - Waiting - }; - - public AnimationState State { get; private set; } - Mobile mobile; - public RenderInfantry(Actor self) - : base(self, () => self.Trait().Facing) - { - anim.Play("stand"); - State = AnimationState.Idle; - mobile = self.Trait(); - } - - public void Attacking(Actor self, Target target) - { - State = AnimationState.Attacking; - if (anim.HasSequence("shoot")) - anim.PlayThen("shoot", () => State = AnimationState.Idle); - else if (anim.HasSequence("heal")) - anim.PlayThen("heal", () => State = AnimationState.Idle); - } - - public override void Tick(Actor self) - { - base.Tick(self); - - // If path is blocked, we can have !isMoving and !idle - // Need to handle this case specially - if (!mobile.IsMoving && State == AnimationState.Moving) - { - State = AnimationState.Waiting; - anim.Play("stand"); - } - else if (State != AnimationState.Moving && mobile.IsMoving) - { - State = AnimationState.Moving; - anim.PlayRepeating("run"); - } - } - - public void TickIdle(Actor self) - { - if (State != AnimationState.Idle) - { - anim.Play("stand"); - State = AnimationState.Idle; - } - } - - - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageState == DamageState.Dead) - { - var death = e.Warhead != null ? e.Warhead.InfDeath : 0; - Sound.PlayVoice("Die", self, self.Owner.Country.Race); - self.World.AddFrameEndTask(w => w.Add(new Corpse(self, death))); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Effects; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Move; + +namespace OpenRA.Mods.RA.Render +{ + public class RenderInfantryInfo : RenderSimpleInfo + { + public override object Create(ActorInitializer init) { return new RenderInfantry(init.self); } + } + + public class RenderInfantry : RenderSimple, INotifyAttack, INotifyDamage, INotifyIdle + { + public enum AnimationState + { + Idle, + Attacking, + Moving, + Waiting + }; + + public AnimationState State { get; private set; } + Mobile mobile; + public RenderInfantry(Actor self) + : base(self, () => self.Trait().Facing) + { + anim.Play("stand"); + State = AnimationState.Idle; + mobile = self.Trait(); + } + + public void Attacking(Actor self, Target target) + { + State = AnimationState.Attacking; + if (anim.HasSequence("shoot")) + anim.PlayThen("shoot", () => State = AnimationState.Idle); + else if (anim.HasSequence("heal")) + anim.PlayThen("heal", () => State = AnimationState.Idle); + } + + public override void Tick(Actor self) + { + base.Tick(self); + + // If path is blocked, we can have !isMoving and !idle + // Need to handle this case specially + if (!mobile.IsMoving && State == AnimationState.Moving) + { + State = AnimationState.Waiting; + anim.Play("stand"); + } + else if (State != AnimationState.Moving && mobile.IsMoving) + { + State = AnimationState.Moving; + anim.PlayRepeating("run"); + } + } + + public void TickIdle(Actor self) + { + if (State != AnimationState.Idle) + { + anim.Play("stand"); + State = AnimationState.Idle; + } + } + + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageState == DamageState.Dead) + { + var death = e.Warhead != null ? e.Warhead.InfDeath : 0; + Sound.PlayVoice("Die", self, self.Owner.Country.Race); + self.World.AddFrameEndTask(w => w.Add(new Corpse(self, death))); + } + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderSpy.cs b/OpenRA.Mods.RA/Render/RenderSpy.cs index 5c4f19e6a5..62b95d5b04 100755 --- a/OpenRA.Mods.RA/Render/RenderSpy.cs +++ b/OpenRA.Mods.RA/Render/RenderSpy.cs @@ -1,78 +1,78 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; -using OpenRA.Mods.RA.Orders; - -namespace OpenRA.Mods.RA.Render -{ - class RenderSpyInfo : RenderInfantryInfo - { - public override object Create(ActorInitializer init) { return new RenderSpy(init.self); } - } - - class RenderSpy : RenderInfantry, IRenderModifier, IIssueOrder, IResolveOrder, IOrderVoice - { - Player disguisedAsPlayer; - string disguisedAsSprite; - - public RenderSpy(Actor self) : base(self) { } - - public IEnumerable ModifyRender(Actor self, IEnumerable r) - { - return disguisedAsPlayer != null ? r.Select(a => a.WithPalette(disguisedAsPlayer.Palette)) : r; - } - - public override void Tick(Actor self) - { - base.Tick(self); - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "Disguise") - { - var target = order.TargetActor == self ? null : order.TargetActor; - if (target != null && target.IsInWorld) - { - disguisedAsPlayer = target.Owner; - disguisedAsSprite = target.Trait().GetImage(target); - anim.ChangeImage(disguisedAsSprite, "stand"); - } - else - { - disguisedAsPlayer = null; - disguisedAsSprite = null; - anim.ChangeImage(GetImage(self), "stand"); - } - } - } - - public IEnumerable Orders - { - get { yield return new UnitTraitOrderTargeter( "Disguise", 5, "ability", true, true ); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "Disguise" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - return null; - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - return order.OrderString == "Disguise" ? "Attack" : null; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; +using OpenRA.Mods.RA.Orders; + +namespace OpenRA.Mods.RA.Render +{ + class RenderSpyInfo : RenderInfantryInfo + { + public override object Create(ActorInitializer init) { return new RenderSpy(init.self); } + } + + class RenderSpy : RenderInfantry, IRenderModifier, IIssueOrder, IResolveOrder, IOrderVoice + { + Player disguisedAsPlayer; + string disguisedAsSprite; + + public RenderSpy(Actor self) : base(self) { } + + public IEnumerable ModifyRender(Actor self, IEnumerable r) + { + return disguisedAsPlayer != null ? r.Select(a => a.WithPalette(disguisedAsPlayer.Palette)) : r; + } + + public override void Tick(Actor self) + { + base.Tick(self); + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Disguise") + { + var target = order.TargetActor == self ? null : order.TargetActor; + if (target != null && target.IsInWorld) + { + disguisedAsPlayer = target.Owner; + disguisedAsSprite = target.Trait().GetImage(target); + anim.ChangeImage(disguisedAsSprite, "stand"); + } + else + { + disguisedAsPlayer = null; + disguisedAsSprite = null; + anim.ChangeImage(GetImage(self), "stand"); + } + } + } + + public IEnumerable Orders + { + get { yield return new UnitTraitOrderTargeter( "Disguise", 5, "ability", true, true ); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "Disguise" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + return null; + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return order.OrderString == "Disguise" ? "Attack" : null; + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderUnit.cs b/OpenRA.Mods.RA/Render/RenderUnit.cs index 4b39e05de8..907eb78768 100644 --- a/OpenRA.Mods.RA/Render/RenderUnit.cs +++ b/OpenRA.Mods.RA/Render/RenderUnit.cs @@ -1,69 +1,69 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Render -{ - public class RenderUnitInfo : RenderSimpleInfo - { - public readonly bool Smokes = true; - public override object Create(ActorInitializer init) { return new RenderUnit(init.self); } - } - - public class RenderUnit : RenderSimple, INotifyDamage - { - public RenderUnit(Actor self) - : base(self, () => self.HasTrait() ? self.Trait().Facing : 0) - { - canSmoke = self.Info.Traits.Get().Smokes; - - anim.PlayRepeating("idle"); - - if (canSmoke) - anims.Add( "smoke", new AnimationWithOffset( new Animation( "smoke_m" ), null, () => !isSmoking ) ); - } - - public void PlayCustomAnimation(Actor self, string newAnim, Action after) - { - anim.PlayThen(newAnim, () => { anim.Play("idle"); if (after != null) after(); }); - } - - public void PlayCustomAnimRepeating(Actor self, string name) - { - anim.PlayThen(name, - () => { PlayCustomAnimRepeating(self, name); }); - } - - public void PlayCustomAnimBackwards(Actor self, string name, Action a) - { - anim.PlayBackwardsThen(name, - () => { anim.PlayRepeating("idle"); a(); }); - } - - bool isSmoking; - bool canSmoke; - - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageState < DamageState.Heavy) return; - if (isSmoking || !canSmoke) return; - - isSmoking = true; - var smoke = anims[ "smoke" ].Animation; - smoke.PlayThen( "idle", - () => smoke.PlayThen( "loop", - () => smoke.PlayBackwardsThen( "end", - () => isSmoking = false ) ) ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + public class RenderUnitInfo : RenderSimpleInfo + { + public readonly bool Smokes = true; + public override object Create(ActorInitializer init) { return new RenderUnit(init.self); } + } + + public class RenderUnit : RenderSimple, INotifyDamage + { + public RenderUnit(Actor self) + : base(self, () => self.HasTrait() ? self.Trait().Facing : 0) + { + canSmoke = self.Info.Traits.Get().Smokes; + + anim.PlayRepeating("idle"); + + if (canSmoke) + anims.Add( "smoke", new AnimationWithOffset( new Animation( "smoke_m" ), null, () => !isSmoking ) ); + } + + public void PlayCustomAnimation(Actor self, string newAnim, Action after) + { + anim.PlayThen(newAnim, () => { anim.Play("idle"); if (after != null) after(); }); + } + + public void PlayCustomAnimRepeating(Actor self, string name) + { + anim.PlayThen(name, + () => { PlayCustomAnimRepeating(self, name); }); + } + + public void PlayCustomAnimBackwards(Actor self, string name, Action a) + { + anim.PlayBackwardsThen(name, + () => { anim.PlayRepeating("idle"); a(); }); + } + + bool isSmoking; + bool canSmoke; + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageState < DamageState.Heavy) return; + if (isSmoking || !canSmoke) return; + + isSmoking = true; + var smoke = anims[ "smoke" ].Animation; + smoke.PlayThen( "idle", + () => smoke.PlayThen( "loop", + () => smoke.PlayBackwardsThen( "end", + () => isSmoking = false ) ) ); + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderUnitReload.cs b/OpenRA.Mods.RA/Render/RenderUnitReload.cs index 993eee9cfc..32d736dd64 100755 --- a/OpenRA.Mods.RA/Render/RenderUnitReload.cs +++ b/OpenRA.Mods.RA/Render/RenderUnitReload.cs @@ -1,56 +1,56 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Activities; - -namespace OpenRA.Mods.RA.Render -{ - class RenderUnitReloadInfo : RenderUnitInfo - { - public override object Create(ActorInitializer init) { return new RenderUnitReload(init.self); } - } - - class RenderUnitReload : RenderUnit - { - public RenderUnitReload(Actor self) - : base(self) { } - - public override void Tick(Actor self) - { - var attack = self.TraitOrDefault(); - - if (attack != null) - anim.ReplaceAnim((attack.IsReloading() ? "empty-" : "") - + (attack.IsAttacking ? "aim" : "idle")); - base.Tick(self); - } - } - - /* todo: native elevation support on turrets, and this dies? */ - - class RenderUnitTurretedAimInfo : RenderUnitTurretedInfo - { - public override object Create(ActorInitializer init) { return new RenderUnitTurretedAim(init.self); } - } - - class RenderUnitTurretedAim : RenderUnitTurreted - { - public RenderUnitTurretedAim(Actor self) - : base(self) { } - - public override void Tick(Actor self) - { - var attack = self.TraitOrDefault(); - var isAttacking = attack.IsAttacking; - anims["turret_0"].Animation.ReplaceAnim(isAttacking ? "aim" : "turret"); - base.Tick(self); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Activities; + +namespace OpenRA.Mods.RA.Render +{ + class RenderUnitReloadInfo : RenderUnitInfo + { + public override object Create(ActorInitializer init) { return new RenderUnitReload(init.self); } + } + + class RenderUnitReload : RenderUnit + { + public RenderUnitReload(Actor self) + : base(self) { } + + public override void Tick(Actor self) + { + var attack = self.TraitOrDefault(); + + if (attack != null) + anim.ReplaceAnim((attack.IsReloading() ? "empty-" : "") + + (attack.IsAttacking ? "aim" : "idle")); + base.Tick(self); + } + } + + /* todo: native elevation support on turrets, and this dies? */ + + class RenderUnitTurretedAimInfo : RenderUnitTurretedInfo + { + public override object Create(ActorInitializer init) { return new RenderUnitTurretedAim(init.self); } + } + + class RenderUnitTurretedAim : RenderUnitTurreted + { + public RenderUnitTurretedAim(Actor self) + : base(self) { } + + public override void Tick(Actor self) + { + var attack = self.TraitOrDefault(); + var isAttacking = attack.IsAttacking; + anims["turret_0"].Animation.ReplaceAnim(isAttacking ? "aim" : "turret"); + base.Tick(self); + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderUnitRotor.cs b/OpenRA.Mods.RA/Render/RenderUnitRotor.cs index 45d3ece7b0..67babdd36d 100755 --- a/OpenRA.Mods.RA/Render/RenderUnitRotor.cs +++ b/OpenRA.Mods.RA/Render/RenderUnitRotor.cs @@ -1,64 +1,64 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Render -{ - class RenderUnitRotorInfo : RenderUnitInfo - { - public readonly int[] PrimaryOffset = { 0, 0 }; - public readonly int[] SecondaryOffset = null; - - public override object Create(ActorInitializer init) { return new RenderUnitRotor(init.self); } - } - - class RenderUnitRotor : RenderUnit - { - public Animation rotorAnim, secondRotorAnim; - - public RenderUnitRotor( Actor self ) - : base(self) - { - var facing = self.Trait(); - var info = self.Info.Traits.Get(); - - rotorAnim = new Animation(GetImage(self)); - rotorAnim.PlayRepeating("rotor"); - anims.Add("rotor_1", new AnimationWithOffset( - rotorAnim, - () => Combat.GetTurretPosition( self, facing, new Turret(info.PrimaryOffset)), - null ) { ZOffset = 1 } ); - - if (info.SecondaryOffset == null) return; - - secondRotorAnim = new Animation(GetImage(self)); - secondRotorAnim.PlayRepeating("rotor2"); - anims.Add("rotor_2", new AnimationWithOffset( - secondRotorAnim, - () => Combat.GetTurretPosition(self, facing, new Turret(info.SecondaryOffset)), - null) { ZOffset = 1 }); - } - - public override void Tick(Actor self) - { - base.Tick(self); - - var isFlying = self.Trait().Altitude > 0 && !self.IsDead(); - if (isFlying ^ (rotorAnim.CurrentSequence.Name != "rotor")) - return; - - rotorAnim.ReplaceAnim(isFlying ? "rotor" : "slow-rotor"); - if (secondRotorAnim != null) - secondRotorAnim.ReplaceAnim(isFlying ? "rotor2" : "slow-rotor2"); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + class RenderUnitRotorInfo : RenderUnitInfo + { + public readonly int[] PrimaryOffset = { 0, 0 }; + public readonly int[] SecondaryOffset = null; + + public override object Create(ActorInitializer init) { return new RenderUnitRotor(init.self); } + } + + class RenderUnitRotor : RenderUnit + { + public Animation rotorAnim, secondRotorAnim; + + public RenderUnitRotor( Actor self ) + : base(self) + { + var facing = self.Trait(); + var info = self.Info.Traits.Get(); + + rotorAnim = new Animation(GetImage(self)); + rotorAnim.PlayRepeating("rotor"); + anims.Add("rotor_1", new AnimationWithOffset( + rotorAnim, + () => Combat.GetTurretPosition( self, facing, new Turret(info.PrimaryOffset)), + null ) { ZOffset = 1 } ); + + if (info.SecondaryOffset == null) return; + + secondRotorAnim = new Animation(GetImage(self)); + secondRotorAnim.PlayRepeating("rotor2"); + anims.Add("rotor_2", new AnimationWithOffset( + secondRotorAnim, + () => Combat.GetTurretPosition(self, facing, new Turret(info.SecondaryOffset)), + null) { ZOffset = 1 }); + } + + public override void Tick(Actor self) + { + base.Tick(self); + + var isFlying = self.Trait().Altitude > 0 && !self.IsDead(); + if (isFlying ^ (rotorAnim.CurrentSequence.Name != "rotor")) + return; + + rotorAnim.ReplaceAnim(isFlying ? "rotor" : "slow-rotor"); + if (secondRotorAnim != null) + secondRotorAnim.ReplaceAnim(isFlying ? "rotor2" : "slow-rotor2"); + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderUnitSpinner.cs b/OpenRA.Mods.RA/Render/RenderUnitSpinner.cs index 7b04b874a3..dbbcc0118d 100755 --- a/OpenRA.Mods.RA/Render/RenderUnitSpinner.cs +++ b/OpenRA.Mods.RA/Render/RenderUnitSpinner.cs @@ -1,37 +1,37 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Render -{ - class RenderUnitSpinnerInfo : RenderUnitInfo - { - public readonly int[] Offset = { 0, 0 }; - public override object Create(ActorInitializer init) { return new RenderUnitSpinner(init.self); } - } - - class RenderUnitSpinner : RenderUnit - { - public RenderUnitSpinner(Actor self) - : base(self) - { - var info = self.Info.Traits.Get(); - - var spinnerAnim = new Animation(GetImage(self)); - spinnerAnim.PlayRepeating("spinner"); - anims.Add("spinner", new AnimationWithOffset( - spinnerAnim, - () => Combat.GetTurretPosition( self, self.Trait(), new Turret(info.Offset)), - null ) { ZOffset = 1 } ); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + class RenderUnitSpinnerInfo : RenderUnitInfo + { + public readonly int[] Offset = { 0, 0 }; + public override object Create(ActorInitializer init) { return new RenderUnitSpinner(init.self); } + } + + class RenderUnitSpinner : RenderUnit + { + public RenderUnitSpinner(Actor self) + : base(self) + { + var info = self.Info.Traits.Get(); + + var spinnerAnim = new Animation(GetImage(self)); + spinnerAnim.PlayRepeating("spinner"); + anims.Add("spinner", new AnimationWithOffset( + spinnerAnim, + () => Combat.GetTurretPosition( self, self.Trait(), new Turret(info.Offset)), + null ) { ZOffset = 1 } ); + } + } +} diff --git a/OpenRA.Mods.RA/Render/RenderUnitTurreted.cs b/OpenRA.Mods.RA/Render/RenderUnitTurreted.cs index 53b3957b51..c1e86cd5ef 100755 --- a/OpenRA.Mods.RA/Render/RenderUnitTurreted.cs +++ b/OpenRA.Mods.RA/Render/RenderUnitTurreted.cs @@ -1,55 +1,55 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Render -{ - class RenderUnitTurretedInfo : RenderUnitInfo - { - public override object Create(ActorInitializer init) { return new RenderUnitTurreted(init.self); } - } - - class RenderUnitTurreted : RenderUnit - { - public RenderUnitTurreted(Actor self) - : base(self) - { - var facing = self.Trait(); - var turreted = self.Trait(); - var attack = self.TraitOrDefault(); - var attackInfo = self.Info.Traits.Get(); - - var turretAnim = new Animation(GetImage(self), () => turreted.turretFacing ); - turretAnim.Play( "turret" ); - - for( var i = 0; i < attack.Turrets.Count; i++ ) - { - var turret = attack.Turrets[i]; - anims.Add( "turret_{0}".F(i), - new AnimationWithOffset( turretAnim, - () => Combat.GetTurretPosition( self, facing, turret ), - null)); - - if (attackInfo.MuzzleFlash) - { - var muzzleFlash = new Animation(GetImage(self), () => turreted.turretFacing); - muzzleFlash.PlayFetchIndex("muzzle", - () => (int)(turret.Recoil * 5.9f)); /* hack: dumb crap */ - anims.Add("muzzle_flash_{0}".F(i), - new AnimationWithOffset(muzzleFlash, - () => Combat.GetTurretPosition(self, facing, turret), - () => turret.Recoil <= 0)); - } - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + class RenderUnitTurretedInfo : RenderUnitInfo + { + public override object Create(ActorInitializer init) { return new RenderUnitTurreted(init.self); } + } + + class RenderUnitTurreted : RenderUnit + { + public RenderUnitTurreted(Actor self) + : base(self) + { + var facing = self.Trait(); + var turreted = self.Trait(); + var attack = self.TraitOrDefault(); + var attackInfo = self.Info.Traits.Get(); + + var turretAnim = new Animation(GetImage(self), () => turreted.turretFacing ); + turretAnim.Play( "turret" ); + + for( var i = 0; i < attack.Turrets.Count; i++ ) + { + var turret = attack.Turrets[i]; + anims.Add( "turret_{0}".F(i), + new AnimationWithOffset( turretAnim, + () => Combat.GetTurretPosition( self, facing, turret ), + null)); + + if (attackInfo.MuzzleFlash) + { + var muzzleFlash = new Animation(GetImage(self), () => turreted.turretFacing); + muzzleFlash.PlayFetchIndex("muzzle", + () => (int)(turret.Recoil * 5.9f)); /* hack: dumb crap */ + anims.Add("muzzle_flash_{0}".F(i), + new AnimationWithOffset(muzzleFlash, + () => Combat.GetTurretPosition(self, facing, turret), + () => turret.Recoil <= 0)); + } + } + } + } +} diff --git a/OpenRA.Mods.RA/RenderDetectionCircle.cs b/OpenRA.Mods.RA/RenderDetectionCircle.cs index ce9d8f5a81..54e5300b46 100644 --- a/OpenRA.Mods.RA/RenderDetectionCircle.cs +++ b/OpenRA.Mods.RA/RenderDetectionCircle.cs @@ -1,30 +1,30 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class RenderDetectionCircleInfo : TraitInfo { } - class RenderDetectionCircle : IPreRenderSelection - { - public void RenderBeforeWorld(WorldRenderer wr, Actor self) - { - if (self.Owner != self.World.LocalPlayer) - return; - - wr.DrawRangeCircle( - Color.FromArgb(128, Color.LimeGreen), - self.CenterLocation, self.Info.Traits.Get().Range); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class RenderDetectionCircleInfo : TraitInfo { } + class RenderDetectionCircle : IPreRenderSelection + { + public void RenderBeforeWorld(WorldRenderer wr, Actor self) + { + if (self.Owner != self.World.LocalPlayer) + return; + + wr.DrawRangeCircle( + Color.FromArgb(128, Color.LimeGreen), + self.CenterLocation, self.Info.Traits.Get().Range); + } + } +} diff --git a/OpenRA.Mods.RA/RenderRangeCircle.cs b/OpenRA.Mods.RA/RenderRangeCircle.cs index 96af412143..f15e3b1613 100644 --- a/OpenRA.Mods.RA/RenderRangeCircle.cs +++ b/OpenRA.Mods.RA/RenderRangeCircle.cs @@ -1,51 +1,51 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public interface IPlaceBuildingDecoration - { - void Render(WorldRenderer wr, World w, ActorInfo ai, int2 centerLocation); - } - - class RenderRangeCircleInfo : TraitInfo, IPlaceBuildingDecoration - { - public readonly string RangeCircleType = null; - - public void Render(WorldRenderer wr, World w, ActorInfo ai, int2 centerLocation) - { - wr.DrawRangeCircle( - Color.FromArgb(128, Color.Yellow), - centerLocation, - ai.Traits.Get().GetMaximumRange()); - - foreach (var a in w.Queries.OwnedBy[w.LocalPlayer].WithTrait()) - if (a.Actor.Info.Traits.Get().RangeCircleType == RangeCircleType) - a.Trait.RenderBeforeWorld(wr, a.Actor); - } - } - - class RenderRangeCircle : IPreRenderSelection - { - public void RenderBeforeWorld(WorldRenderer wr, Actor self) - { - if (self.Owner != self.World.LocalPlayer) - return; - - wr.DrawRangeCircle( - Color.FromArgb(128, Color.Yellow), - self.CenterLocation, (int)self.Trait().GetMaximumRange()); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public interface IPlaceBuildingDecoration + { + void Render(WorldRenderer wr, World w, ActorInfo ai, int2 centerLocation); + } + + class RenderRangeCircleInfo : TraitInfo, IPlaceBuildingDecoration + { + public readonly string RangeCircleType = null; + + public void Render(WorldRenderer wr, World w, ActorInfo ai, int2 centerLocation) + { + wr.DrawRangeCircle( + Color.FromArgb(128, Color.Yellow), + centerLocation, + ai.Traits.Get().GetMaximumRange()); + + foreach (var a in w.Queries.OwnedBy[w.LocalPlayer].WithTrait()) + if (a.Actor.Info.Traits.Get().RangeCircleType == RangeCircleType) + a.Trait.RenderBeforeWorld(wr, a.Actor); + } + } + + class RenderRangeCircle : IPreRenderSelection + { + public void RenderBeforeWorld(WorldRenderer wr, Actor self) + { + if (self.Owner != self.World.LocalPlayer) + return; + + wr.DrawRangeCircle( + Color.FromArgb(128, Color.Yellow), + self.CenterLocation, (int)self.Trait().GetMaximumRange()); + } + } +} diff --git a/OpenRA.Mods.RA/Repairable.cs b/OpenRA.Mods.RA/Repairable.cs index 7c3eddcc08..929320616b 100644 --- a/OpenRA.Mods.RA/Repairable.cs +++ b/OpenRA.Mods.RA/Repairable.cs @@ -1,94 +1,94 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Effects; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Move; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class RepairableInfo : ITraitInfo, ITraitPrerequisite - { - public readonly string[] RepairBuildings = { "fix" }; - public virtual object Create(ActorInitializer init) { return new Repairable(init.self); } - } - - class Repairable : IIssueOrder, IResolveOrder, IOrderVoice - { - readonly Actor self; - readonly Health Health; - - public Repairable(Actor self) - { - this.self = self; - Health = self.Trait(); - } - - public IEnumerable Orders - { - get { yield return new EnterOrderTargeter( "Repair", 5, false, true, target => CanRepairAt( target ), _ => CanRepair() ); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "Repair" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - return null; - } - - bool CanRepairAt( Actor target ) - { - return self.Info.Traits.Get().RepairBuildings.Contains( target.Info.Name ); - } - - bool CanRepair() - { - var li = self.TraitOrDefault(); - return (Health.DamageState > DamageState.Undamaged || (li != null && !li.FullAmmo()) ); - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - return (order.OrderString == "Repair" && CanRepair()) ? "Move" : null; - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "Repair") - { - if( !CanRepairAt( order.TargetActor ) || !CanRepair() ) - return; - - var mobile = self.Trait(); - var rp = order.TargetActor.TraitOrDefault(); - self.SetTargetLine(Target.FromOrder(order), Color.Green); - - self.CancelActivity(); - self.QueueActivity(mobile.MoveTo(Traits.Util.CellContaining(order.TargetActor.CenterLocation), order.TargetActor)); - self.QueueActivity(new Rearm()); - self.QueueActivity(new Repair(order.TargetActor)); - - if (rp != null) - self.QueueActivity(new CallFunc(() => - { - self.SetTargetLine(Target.FromCell(rp.rallyPoint), Color.Green); - self.QueueActivity(mobile.MoveTo(rp.rallyPoint, order.TargetActor)); - })); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Effects; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Move; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class RepairableInfo : ITraitInfo, ITraitPrerequisite + { + public readonly string[] RepairBuildings = { "fix" }; + public virtual object Create(ActorInitializer init) { return new Repairable(init.self); } + } + + class Repairable : IIssueOrder, IResolveOrder, IOrderVoice + { + readonly Actor self; + readonly Health Health; + + public Repairable(Actor self) + { + this.self = self; + Health = self.Trait(); + } + + public IEnumerable Orders + { + get { yield return new EnterOrderTargeter( "Repair", 5, false, true, target => CanRepairAt( target ), _ => CanRepair() ); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "Repair" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + return null; + } + + bool CanRepairAt( Actor target ) + { + return self.Info.Traits.Get().RepairBuildings.Contains( target.Info.Name ); + } + + bool CanRepair() + { + var li = self.TraitOrDefault(); + return (Health.DamageState > DamageState.Undamaged || (li != null && !li.FullAmmo()) ); + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return (order.OrderString == "Repair" && CanRepair()) ? "Move" : null; + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Repair") + { + if( !CanRepairAt( order.TargetActor ) || !CanRepair() ) + return; + + var mobile = self.Trait(); + var rp = order.TargetActor.TraitOrDefault(); + self.SetTargetLine(Target.FromOrder(order), Color.Green); + + self.CancelActivity(); + self.QueueActivity(mobile.MoveTo(Traits.Util.CellContaining(order.TargetActor.CenterLocation), order.TargetActor)); + self.QueueActivity(new Rearm()); + self.QueueActivity(new Repair(order.TargetActor)); + + if (rp != null) + self.QueueActivity(new CallFunc(() => + { + self.SetTargetLine(Target.FromCell(rp.rallyPoint), Color.Green); + self.QueueActivity(mobile.MoveTo(rp.rallyPoint, order.TargetActor)); + })); + } + } + } +} diff --git a/OpenRA.Mods.RA/RepairableNear.cs b/OpenRA.Mods.RA/RepairableNear.cs index 87561de37b..5bbcf334fb 100644 --- a/OpenRA.Mods.RA/RepairableNear.cs +++ b/OpenRA.Mods.RA/RepairableNear.cs @@ -1,75 +1,75 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Move; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class RepairableNearInfo : ITraitInfo, ITraitPrerequisite - { - [ActorReference] - public readonly string[] Buildings = { "spen", "syrd" }; - - public object Create( ActorInitializer init ) { return new RepairableNear( init.self ); } - } - - class RepairableNear : IIssueOrder, IResolveOrder - { - readonly Actor self; - - public RepairableNear( Actor self ) { this.self = self; } - - public IEnumerable Orders - { - get - { - yield return new EnterOrderTargeter( "RepairNear", 5, false, true, - target => CanRepairAt( target ), _ => ShouldRepair() ); - } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "RepairNear" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - return null; - } - - bool CanRepairAt( Actor target ) - { - return self.Info.Traits.Get().Buildings.Contains( target.Info.Name ); - } - - bool ShouldRepair() - { - return self.GetDamageState() > DamageState.Undamaged; - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "RepairNear" && CanRepairAt(order.TargetActor) && ShouldRepair()) - { - var mobile = self.Trait(); - self.CancelActivity(); - self.QueueActivity(mobile.MoveWithinRange(order.TargetActor, 1)); - self.SetTargetLine(Target.FromOrder(order), Color.Green, false); - self.QueueActivity(new Repair(order.TargetActor)); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Move; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class RepairableNearInfo : ITraitInfo, ITraitPrerequisite + { + [ActorReference] + public readonly string[] Buildings = { "spen", "syrd" }; + + public object Create( ActorInitializer init ) { return new RepairableNear( init.self ); } + } + + class RepairableNear : IIssueOrder, IResolveOrder + { + readonly Actor self; + + public RepairableNear( Actor self ) { this.self = self; } + + public IEnumerable Orders + { + get + { + yield return new EnterOrderTargeter( "RepairNear", 5, false, true, + target => CanRepairAt( target ), _ => ShouldRepair() ); + } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "RepairNear" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + return null; + } + + bool CanRepairAt( Actor target ) + { + return self.Info.Traits.Get().Buildings.Contains( target.Info.Name ); + } + + bool ShouldRepair() + { + return self.GetDamageState() > DamageState.Undamaged; + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "RepairNear" && CanRepairAt(order.TargetActor) && ShouldRepair()) + { + var mobile = self.Trait(); + self.CancelActivity(); + self.QueueActivity(mobile.MoveWithinRange(order.TargetActor, 1)); + self.SetTargetLine(Target.FromOrder(order), Color.Green, false); + self.QueueActivity(new Repair(order.TargetActor)); + } + } + } +} diff --git a/OpenRA.Mods.RA/RepairsUnits.cs b/OpenRA.Mods.RA/RepairsUnits.cs index b59538de59..9f2cc82a4c 100644 --- a/OpenRA.Mods.RA/RepairsUnits.cs +++ b/OpenRA.Mods.RA/RepairsUnits.cs @@ -1,23 +1,23 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class RepairsUnitsInfo : TraitInfo - { - public readonly int ValuePercentage = 20; // charge 20% of the unit value to fully repair - public readonly int HpPerStep = 10; - public readonly int Interval = 24; // Ticks - } - - public class RepairsUnits { } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class RepairsUnitsInfo : TraitInfo + { + public readonly int ValuePercentage = 20; // charge 20% of the unit value to fully repair + public readonly int HpPerStep = 10; + public readonly int Interval = 24; // Ticks + } + + public class RepairsUnits { } } diff --git a/OpenRA.Mods.RA/ReplaceWithActor.cs b/OpenRA.Mods.RA/ReplaceWithActor.cs index d5c41556a5..895a3a84b7 100644 --- a/OpenRA.Mods.RA/ReplaceWithActor.cs +++ b/OpenRA.Mods.RA/ReplaceWithActor.cs @@ -1,14 +1,14 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; using OpenRA.FileFormats; namespace OpenRA.Mods.RA @@ -26,12 +26,12 @@ namespace OpenRA.Mods.RA public ReplaceWithActor(Actor self, ReplaceWithActorInfo info) { self.World.AddFrameEndTask(w => - { + { self.Destroy(); - w.CreateActor(info.Actor, new TypeDictionary - { - new LocationInit( self.Location ), - new OwnerInit( self.Owner ), + w.CreateActor(info.Actor, new TypeDictionary + { + new LocationInit( self.Location ), + new OwnerInit( self.Owner ), }); }); } diff --git a/OpenRA.Mods.RA/Reservable.cs b/OpenRA.Mods.RA/Reservable.cs index 6eea56759b..b4833a2849 100755 --- a/OpenRA.Mods.RA/Reservable.cs +++ b/OpenRA.Mods.RA/Reservable.cs @@ -1,58 +1,58 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class ReservableInfo : TraitInfo {} - - public class Reservable : ITick - { - Actor reservedFor; - //Actor self; - - //public Reservable(Actor self) { this.self = self; } - - public void Tick(Actor self) - { - if (reservedFor == null) - return; /* nothing to do */ - - if (!reservedFor.IsInWorld || reservedFor.IsDead()) // todo: replace with Target.IsValid? - reservedFor = null; /* not likely to arrive now. */ - } - - public IDisposable Reserve(Actor forActor) - { - //if (reservedFor != null) - // Game.Debug("BUG: #{0} {1} was already reserved (by #{2} {3})".F( - // self.ActorID, self.Info.Name, reservedFor.ActorID, reservedFor.Info.Name)); - - reservedFor = forActor; - //Game.Debug("#{0} {1} reserved by #{2} {3}".F( - // self.ActorID, self.Info.Name, forActor.ActorID, forActor.Info.Name)); - - return new DisposableAction(() => - { - //Game.Debug("#{0} {1} unreserved".F( - // self.ActorID, self.Info.Name)); - reservedFor = null; - }); - } - - public static bool IsReserved(Actor a) - { - var res = a.TraitOrDefault(); - return res != null && res.reservedFor != null; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class ReservableInfo : TraitInfo {} + + public class Reservable : ITick + { + Actor reservedFor; + //Actor self; + + //public Reservable(Actor self) { this.self = self; } + + public void Tick(Actor self) + { + if (reservedFor == null) + return; /* nothing to do */ + + if (!reservedFor.IsInWorld || reservedFor.IsDead()) // todo: replace with Target.IsValid? + reservedFor = null; /* not likely to arrive now. */ + } + + public IDisposable Reserve(Actor forActor) + { + //if (reservedFor != null) + // Game.Debug("BUG: #{0} {1} was already reserved (by #{2} {3})".F( + // self.ActorID, self.Info.Name, reservedFor.ActorID, reservedFor.Info.Name)); + + reservedFor = forActor; + //Game.Debug("#{0} {1} reserved by #{2} {3}".F( + // self.ActorID, self.Info.Name, forActor.ActorID, forActor.Info.Name)); + + return new DisposableAction(() => + { + //Game.Debug("#{0} {1} unreserved".F( + // self.ActorID, self.Info.Name)); + reservedFor = null; + }); + } + + public static bool IsReserved(Actor a) + { + var res = a.TraitOrDefault(); + return res != null && res.reservedFor != null; + } + } +} diff --git a/OpenRA.Mods.RA/Scripting/Media.cs b/OpenRA.Mods.RA/Scripting/Media.cs index 3d1d19e7fc..11ea6bc20d 100644 --- a/OpenRA.Mods.RA/Scripting/Media.cs +++ b/OpenRA.Mods.RA/Scripting/Media.cs @@ -1,14 +1,14 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System; +#endregion + +using System; using OpenRA.Widgets; namespace OpenRA.Scripting diff --git a/OpenRA.Mods.RA/Scripting/RASpecialPowers.cs b/OpenRA.Mods.RA/Scripting/RASpecialPowers.cs index 038fa10885..e843afc7ad 100644 --- a/OpenRA.Mods.RA/Scripting/RASpecialPowers.cs +++ b/OpenRA.Mods.RA/Scripting/RASpecialPowers.cs @@ -1,17 +1,17 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Mods.RA; +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Mods.RA; using OpenRA.Mods.RA.Render; namespace OpenRA.Scripting diff --git a/OpenRA.Mods.RA/SeedsResource.cs b/OpenRA.Mods.RA/SeedsResource.cs index 8a597b836c..77f2438881 100644 --- a/OpenRA.Mods.RA/SeedsResource.cs +++ b/OpenRA.Mods.RA/SeedsResource.cs @@ -1,84 +1,84 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class SeedsResourceInfo : TraitInfo - { - public readonly int Interval = 75; - public readonly string ResourceType = "Ore"; - public readonly int MaxRange = 100; - public readonly int AnimationInterval = 750; - } - - class SeedsResource : ITick - { - int ticks; - int animationTicks; - - public void Tick(Actor self) - { - if (--ticks <= 0) - { - var info = self.Info.Traits.Get(); - var resourceType = self.World.WorldActor - .TraitsImplementing() - .FirstOrDefault(t => t.info.Name == info.ResourceType); - - if (resourceType == null) - throw new InvalidOperationException("No such resource type `{0}`".F(info.ResourceType)); - - var resLayer = self.World.WorldActor.Trait(); - - var cell = RandomWalk(self.Location, self.World.SharedRandom) - .Take(info.MaxRange) - .SkipWhile(p => resLayer.GetResource(p) == resourceType && resLayer.IsFull(p.X, p.Y)) - .Cast().FirstOrDefault(); - - // Todo: Valid terrain should be specified in the resource - if (cell != null && self.World.Map.IsInMap(cell.Value) && - (resLayer.GetResource(cell.Value) == resourceType - || (resLayer.GetResource(cell.Value) == null && resLayer.AllowResourceAt(resourceType, cell.Value)))) - resLayer.AddResource(resourceType, cell.Value.X, cell.Value.Y, 1); - - ticks = info.Interval; - } - - if (--animationTicks <= 0) - { - var info = self.Info.Traits.Get(); - self.Trait().PlayCustomAnim(self, "active"); - animationTicks = info.AnimationInterval; - } - } - - static IEnumerable RandomWalk(int2 p, Thirdparty.Random r) - { - for (; ; ) - { - var dx = r.Next(-1, 2); - var dy = r.Next(-1, 2); - - if (dx == 0 && dy == 0) - continue; - - p.X += dx; - p.Y += dy; - yield return p; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class SeedsResourceInfo : TraitInfo + { + public readonly int Interval = 75; + public readonly string ResourceType = "Ore"; + public readonly int MaxRange = 100; + public readonly int AnimationInterval = 750; + } + + class SeedsResource : ITick + { + int ticks; + int animationTicks; + + public void Tick(Actor self) + { + if (--ticks <= 0) + { + var info = self.Info.Traits.Get(); + var resourceType = self.World.WorldActor + .TraitsImplementing() + .FirstOrDefault(t => t.info.Name == info.ResourceType); + + if (resourceType == null) + throw new InvalidOperationException("No such resource type `{0}`".F(info.ResourceType)); + + var resLayer = self.World.WorldActor.Trait(); + + var cell = RandomWalk(self.Location, self.World.SharedRandom) + .Take(info.MaxRange) + .SkipWhile(p => resLayer.GetResource(p) == resourceType && resLayer.IsFull(p.X, p.Y)) + .Cast().FirstOrDefault(); + + // Todo: Valid terrain should be specified in the resource + if (cell != null && self.World.Map.IsInMap(cell.Value) && + (resLayer.GetResource(cell.Value) == resourceType + || (resLayer.GetResource(cell.Value) == null && resLayer.AllowResourceAt(resourceType, cell.Value)))) + resLayer.AddResource(resourceType, cell.Value.X, cell.Value.Y, 1); + + ticks = info.Interval; + } + + if (--animationTicks <= 0) + { + var info = self.Info.Traits.Get(); + self.Trait().PlayCustomAnim(self, "active"); + animationTicks = info.AnimationInterval; + } + } + + static IEnumerable RandomWalk(int2 p, Thirdparty.Random r) + { + for (; ; ) + { + var dx = r.Next(-1, 2); + var dy = r.Next(-1, 2); + + if (dx == 0 && dy == 0) + continue; + + p.X += dx; + p.Y += dy; + yield return p; + } + } + } +} diff --git a/OpenRA.Mods.RA/SelfHealing.cs b/OpenRA.Mods.RA/SelfHealing.cs index 15c3ad803b..bd197a2f17 100644 --- a/OpenRA.Mods.RA/SelfHealing.cs +++ b/OpenRA.Mods.RA/SelfHealing.cs @@ -1,43 +1,43 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class SelfHealingInfo : TraitInfo, ITraitPrerequisite - { - public readonly int Step = 5; - public readonly int Ticks = 5; - public readonly float HealIfBelow = .5f; - } - - class SelfHealing : ITick, ISync - { - [Sync] - int ticks; - - public void Tick(Actor self) - { - if (self.IsDead()) - return; - - var info = self.Info.Traits.Get(); - if (self.Trait().HPFraction >= info.HealIfBelow) - return; - - if (--ticks <= 0) - { - ticks = info.Ticks; - self.InflictDamage(self, -info.Step, null); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class SelfHealingInfo : TraitInfo, ITraitPrerequisite + { + public readonly int Step = 5; + public readonly int Ticks = 5; + public readonly float HealIfBelow = .5f; + } + + class SelfHealing : ITick, ISync + { + [Sync] + int ticks; + + public void Tick(Actor self) + { + if (self.IsDead()) + return; + + var info = self.Info.Traits.Get(); + if (self.Trait().HPFraction >= info.HealIfBelow) + return; + + if (--ticks <= 0) + { + ticks = info.Ticks; + self.InflictDamage(self, -info.Step, null); + } + } + } +} diff --git a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs index f3fde35d54..42a2e0f485 100644 --- a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs @@ -1,299 +1,299 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Network; -using OpenRA.FileFormats; -using OpenRA.Server; -using S = OpenRA.Server.Server; - -namespace OpenRA.Mods.RA.Server -{ - public class LobbyCommands : ServerTrait, IInterpretCommand, INotifyServerStart - { - public static int MaxSpectators = 4; // How many spectators to allow // @todo Expose this as an option - - public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd) - { - if (server.GameStarted) - { - server.SendChatTo(conn, "Cannot change state when game started. ({0})".F(cmd)); - return false; - } - else if (client.State == Session.ClientState.Ready && !(cmd == "ready" || cmd == "startgame")) - { - server.SendChatTo(conn, "Cannot change state when marked as ready."); - return false; - } - - var dict = new Dictionary> - { - { "ready", - s => - { - // if we're downloading, we can't ready up. - if (client.State == Session.ClientState.NotReady) - client.State = Session.ClientState.Ready; - else if (client.State == Session.ClientState.Ready) - client.State = Session.ClientState.NotReady; - - Log.Write("server", "Player @{0} is {1}", - conn.socket.RemoteEndPoint, client.State); - - server.SyncLobbyInfo(); - - if (server.conns.Count > 0 && server.conns.All(c => server.GetClient(c).State == Session.ClientState.Ready)) - InterpretCommand(server, conn, client, "startgame"); - - return true; - }}, - { "startgame", - s => - { - server.StartGame(); - return true; - }}, - { "lag", - s => - { - int lag; - if (!int.TryParse(s, out lag)) { Log.Write("server", "Invalid order lag: {0}", s); return false; } - - Log.Write("server", "Order lag is now {0} frames.", lag); - - server.lobbyInfo.GlobalSettings.OrderLatency = lag; - server.SyncLobbyInfo(); - return true; - }}, - { "spectator", - s => - { - var slotData = server.lobbyInfo.Slots.Where(ax => ax.Spectator && !server.lobbyInfo.Clients.Any(l => l.Slot == ax.Index)).FirstOrDefault(); - if (slotData == null) - return true; - - client.Slot = slotData.Index; - S.SyncClientToPlayerReference(client, slotData.MapPlayer != null ? server.Map.Players[slotData.MapPlayer] : null); - - server.SyncLobbyInfo(); - return true; - }}, - { "slot", - s => - { - int slot; - if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; } - - var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot ); - if (slotData == null || slotData.Closed || slotData.Bot != null - || server.lobbyInfo.Clients.Any( c => c.Slot == slot )) - return false; - - client.Slot = slot; - S.SyncClientToPlayerReference(client, slotData.MapPlayer != null ? server.Map.Players[slotData.MapPlayer] : null); - - server.SyncLobbyInfo(); - return true; - }}, - { "slot_close", - s => - { - int slot; - if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; } - - var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot ); - if (slotData == null) - return false; - - if (conn.PlayerIndex != 0) - { - server.SendChatTo( conn, "Only the host can alter slots" ); - return true; - } - - slotData.Closed = true; - slotData.Bot = null; - - /* kick any player that's in the slot */ - var occupant = server.lobbyInfo.Clients.FirstOrDefault( c => c.Slot == slotData.Index ); - if (occupant != null) - { - 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.SyncLobbyInfo(); - return true; - }}, - { "slot_open", - s => - { - int slot; - if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; } - - var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot ); - if (slotData == null) - return false; - - if (conn.PlayerIndex != 0) - { - server.SendChatTo( conn, "Only the host can alter slots" ); - return true; - } - - slotData.Closed = false; - slotData.Bot = null; - - server.SyncLobbyInfo(); - return true; - }}, - { "slot_bot", - s => - { - var parts = s.Split(' '); - - if (parts.Length < 2) - { - server.SendChatTo( conn, "Malformed slot_bot command" ); - return true; - } - - int slot; - if (!int.TryParse(parts[0], out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; } - - var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot ); - if (slotData == null) - return false; - - if (conn.PlayerIndex != 0) - { - server.SendChatTo( conn, "Only the host can alter slots" ); - return true; - } - - slotData.Bot = string.Join(" ", parts.Skip(1).ToArray() ); - - server.SyncLobbyInfo(); - return true; - }}, - { "map", - s => - { - if (conn.PlayerIndex != 0) - { - server.SendChatTo( conn, "Only the host can change the map" ); - return true; - } - server.lobbyInfo.GlobalSettings.Map = s; - LoadMap(server); - - foreach(var c in server.lobbyInfo.Clients) - { - c.SpawnPoint = 0; - var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == c.Slot ); - if (slotData != null && slotData.MapPlayer != null) - S.SyncClientToPlayerReference(c, server.Map.Players[slotData.MapPlayer]); - - c.State = Session.ClientState.NotReady; - } - - server.SyncLobbyInfo(); - return true; - }}, - { "lockteams", - s => - { - if (conn.PlayerIndex != 0) - { - server.SendChatTo( conn, "Only the host can set that option" ); - return true; - } - - bool.TryParse(s, out server.lobbyInfo.GlobalSettings.LockTeams); - server.SyncLobbyInfo(); - return true; - }}, - { "kick", - s => - { - if (conn.PlayerIndex != 0) - { - server.SendChatTo( conn, "Only the host can kick players" ); - return true; - } - - int slot; - int.TryParse( s, out slot ); - - var connToKick = server.conns.SingleOrDefault( c => server.GetClient(c) != null && server.GetClient(c).Slot == slot); - if (connToKick == null) - { - server.SendChatTo( conn, "Noone in that slot." ); - return true; - } - - server.SendOrderTo(connToKick, "ServerError", "You have been kicked from the server"); - server.DropClient(connToKick); - - server.SyncLobbyInfo(); - - return true; - }}, - }; - - var cmdName = cmd.Split(' ').First(); - var cmdValue = string.Join(" ", cmd.Split(' ').Skip(1).ToArray()); - - Func a; - if (!dict.TryGetValue(cmdName, out a)) - return false; - - return a(cmdValue); - } - - public void ServerStarted(S server) { LoadMap(server); } - static Session.Slot MakeSlotFromPlayerReference(PlayerReference pr) - { - if (!pr.Playable) return null; - return new Session.Slot - { - MapPlayer = pr.Name, - Bot = null, /* todo: allow the map to specify a bot class? */ - Closed = false, - }; - } - - public static void LoadMap(S server) - { - server.Map = new Map(server.ModData.AvailableMaps[server.lobbyInfo.GlobalSettings.Map].Path); - server.lobbyInfo.Slots = server.Map.Players - .Select(p => MakeSlotFromPlayerReference(p.Value)) - .Where(s => s != null) - .Select((s, i) => { s.Index = i; return s; }) - .ToList(); - - // Generate slots for spectators - for (int i = 0; i < MaxSpectators; i++) - server.lobbyInfo.Slots.Add(new Session.Slot - { - Spectator = true, - Index = server.lobbyInfo.Slots.Count(), - MapPlayer = null, - Bot = null - }); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Network; +using OpenRA.FileFormats; +using OpenRA.Server; +using S = OpenRA.Server.Server; + +namespace OpenRA.Mods.RA.Server +{ + public class LobbyCommands : ServerTrait, IInterpretCommand, INotifyServerStart + { + public static int MaxSpectators = 4; // How many spectators to allow // @todo Expose this as an option + + public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd) + { + if (server.GameStarted) + { + server.SendChatTo(conn, "Cannot change state when game started. ({0})".F(cmd)); + return false; + } + else if (client.State == Session.ClientState.Ready && !(cmd == "ready" || cmd == "startgame")) + { + server.SendChatTo(conn, "Cannot change state when marked as ready."); + return false; + } + + var dict = new Dictionary> + { + { "ready", + s => + { + // if we're downloading, we can't ready up. + if (client.State == Session.ClientState.NotReady) + client.State = Session.ClientState.Ready; + else if (client.State == Session.ClientState.Ready) + client.State = Session.ClientState.NotReady; + + Log.Write("server", "Player @{0} is {1}", + conn.socket.RemoteEndPoint, client.State); + + server.SyncLobbyInfo(); + + if (server.conns.Count > 0 && server.conns.All(c => server.GetClient(c).State == Session.ClientState.Ready)) + InterpretCommand(server, conn, client, "startgame"); + + return true; + }}, + { "startgame", + s => + { + server.StartGame(); + return true; + }}, + { "lag", + s => + { + int lag; + if (!int.TryParse(s, out lag)) { Log.Write("server", "Invalid order lag: {0}", s); return false; } + + Log.Write("server", "Order lag is now {0} frames.", lag); + + server.lobbyInfo.GlobalSettings.OrderLatency = lag; + server.SyncLobbyInfo(); + return true; + }}, + { "spectator", + s => + { + var slotData = server.lobbyInfo.Slots.Where(ax => ax.Spectator && !server.lobbyInfo.Clients.Any(l => l.Slot == ax.Index)).FirstOrDefault(); + if (slotData == null) + return true; + + client.Slot = slotData.Index; + S.SyncClientToPlayerReference(client, slotData.MapPlayer != null ? server.Map.Players[slotData.MapPlayer] : null); + + server.SyncLobbyInfo(); + return true; + }}, + { "slot", + s => + { + int slot; + if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; } + + var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot ); + if (slotData == null || slotData.Closed || slotData.Bot != null + || server.lobbyInfo.Clients.Any( c => c.Slot == slot )) + return false; + + client.Slot = slot; + S.SyncClientToPlayerReference(client, slotData.MapPlayer != null ? server.Map.Players[slotData.MapPlayer] : null); + + server.SyncLobbyInfo(); + return true; + }}, + { "slot_close", + s => + { + int slot; + if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; } + + var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot ); + if (slotData == null) + return false; + + if (conn.PlayerIndex != 0) + { + server.SendChatTo( conn, "Only the host can alter slots" ); + return true; + } + + slotData.Closed = true; + slotData.Bot = null; + + /* kick any player that's in the slot */ + var occupant = server.lobbyInfo.Clients.FirstOrDefault( c => c.Slot == slotData.Index ); + if (occupant != null) + { + 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.SyncLobbyInfo(); + return true; + }}, + { "slot_open", + s => + { + int slot; + if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; } + + var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot ); + if (slotData == null) + return false; + + if (conn.PlayerIndex != 0) + { + server.SendChatTo( conn, "Only the host can alter slots" ); + return true; + } + + slotData.Closed = false; + slotData.Bot = null; + + server.SyncLobbyInfo(); + return true; + }}, + { "slot_bot", + s => + { + var parts = s.Split(' '); + + if (parts.Length < 2) + { + server.SendChatTo( conn, "Malformed slot_bot command" ); + return true; + } + + int slot; + if (!int.TryParse(parts[0], out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; } + + var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot ); + if (slotData == null) + return false; + + if (conn.PlayerIndex != 0) + { + server.SendChatTo( conn, "Only the host can alter slots" ); + return true; + } + + slotData.Bot = string.Join(" ", parts.Skip(1).ToArray() ); + + server.SyncLobbyInfo(); + return true; + }}, + { "map", + s => + { + if (conn.PlayerIndex != 0) + { + server.SendChatTo( conn, "Only the host can change the map" ); + return true; + } + server.lobbyInfo.GlobalSettings.Map = s; + LoadMap(server); + + foreach(var c in server.lobbyInfo.Clients) + { + c.SpawnPoint = 0; + var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == c.Slot ); + if (slotData != null && slotData.MapPlayer != null) + S.SyncClientToPlayerReference(c, server.Map.Players[slotData.MapPlayer]); + + c.State = Session.ClientState.NotReady; + } + + server.SyncLobbyInfo(); + return true; + }}, + { "lockteams", + s => + { + if (conn.PlayerIndex != 0) + { + server.SendChatTo( conn, "Only the host can set that option" ); + return true; + } + + bool.TryParse(s, out server.lobbyInfo.GlobalSettings.LockTeams); + server.SyncLobbyInfo(); + return true; + }}, + { "kick", + s => + { + if (conn.PlayerIndex != 0) + { + server.SendChatTo( conn, "Only the host can kick players" ); + return true; + } + + int slot; + int.TryParse( s, out slot ); + + var connToKick = server.conns.SingleOrDefault( c => server.GetClient(c) != null && server.GetClient(c).Slot == slot); + if (connToKick == null) + { + server.SendChatTo( conn, "Noone in that slot." ); + return true; + } + + server.SendOrderTo(connToKick, "ServerError", "You have been kicked from the server"); + server.DropClient(connToKick); + + server.SyncLobbyInfo(); + + return true; + }}, + }; + + var cmdName = cmd.Split(' ').First(); + var cmdValue = string.Join(" ", cmd.Split(' ').Skip(1).ToArray()); + + Func a; + if (!dict.TryGetValue(cmdName, out a)) + return false; + + return a(cmdValue); + } + + public void ServerStarted(S server) { LoadMap(server); } + static Session.Slot MakeSlotFromPlayerReference(PlayerReference pr) + { + if (!pr.Playable) return null; + return new Session.Slot + { + MapPlayer = pr.Name, + Bot = null, /* todo: allow the map to specify a bot class? */ + Closed = false, + }; + } + + public static void LoadMap(S server) + { + server.Map = new Map(server.ModData.AvailableMaps[server.lobbyInfo.GlobalSettings.Map].Path); + server.lobbyInfo.Slots = server.Map.Players + .Select(p => MakeSlotFromPlayerReference(p.Value)) + .Where(s => s != null) + .Select((s, i) => { s.Index = i; return s; }) + .ToList(); + + // Generate slots for spectators + for (int i = 0; i < MaxSpectators; i++) + server.lobbyInfo.Slots.Add(new Session.Slot + { + Spectator = true, + Index = server.lobbyInfo.Slots.Count(), + MapPlayer = null, + Bot = null + }); + } + } +} diff --git a/OpenRA.Mods.RA/ServerTraits/MasterServerPinger.cs b/OpenRA.Mods.RA/ServerTraits/MasterServerPinger.cs index db2d515926..ca7a1d4519 100644 --- a/OpenRA.Mods.RA/ServerTraits/MasterServerPinger.cs +++ b/OpenRA.Mods.RA/ServerTraits/MasterServerPinger.cs @@ -1,95 +1,95 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Net; -using OpenRA.Server; -using S = OpenRA.Server.Server; -using System.Linq; - -namespace OpenRA.Mods.RA.Server -{ - public class MasterServerPinger : ServerTrait, ITick, INotifySyncLobbyInfo, IStartGame - { - const int MasterPingInterval = 60 * 3; // 3 minutes. server has a 5 minute TTL for games, so give ourselves a bit - // of leeway. - public int TickTimeout { get { return MasterPingInterval * 10000; } } - public void Tick(S server) - { - if (Environment.TickCount - lastPing > MasterPingInterval * 1000) - PingMasterServer(server); - else - lock (masterServerMessages) - while (masterServerMessages.Count > 0) - server.SendChat(null, masterServerMessages.Dequeue()); - - } - - - public void LobbyInfoSynced(S server) { PingMasterServer(server); } - public void GameStarted(S server) { PingMasterServer(server); } - - static int lastPing = 0; - // Todo: use the settings passed to the server instead - static bool isInternetServer = Game.Settings.Server.AdvertiseOnline; - static string masterServerUrl = Game.Settings.Server.MasterServer; - static int externalPort = Game.Settings.Server.ExternalPort; - static bool isInitialPing = true; - - static volatile bool isBusy; - static Queue masterServerMessages = new Queue(); - public static void PingMasterServer(S server) - { - if (isBusy || !isInternetServer) return; - - lastPing = Environment.TickCount; - isBusy = true; - - Action a = () => - { - try - { - var url = "ping.php?port={0}&name={1}&state={2}&players={3}&mods={4}&map={5}"; - if (isInitialPing) url += "&new=1"; - - using (var wc = new WebClient()) - { - wc.Proxy = null; - wc.DownloadData( - masterServerUrl + url.F( - externalPort, Uri.EscapeUriString(server.Name), - server.GameStarted ? 2 : 1, // todo: post-game states, etc. - server.lobbyInfo.Clients.Count, - string.Join(",", Game.CurrentMods.Select(f => "{0}@{1}".F(f.Key, f.Value.Version)).ToArray()), - server.lobbyInfo.GlobalSettings.Map)); - - if (isInitialPing) - { - isInitialPing = false; - lock (masterServerMessages) - masterServerMessages.Enqueue("Master server communication established."); - } - } - } - catch(Exception ex) - { - Log.Write("server", ex.ToString()); - lock( masterServerMessages ) - masterServerMessages.Enqueue( "Master server communication failed." ); - } - - isBusy = false; - }; - - a.BeginInvoke(null, null); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Net; +using OpenRA.Server; +using S = OpenRA.Server.Server; +using System.Linq; + +namespace OpenRA.Mods.RA.Server +{ + public class MasterServerPinger : ServerTrait, ITick, INotifySyncLobbyInfo, IStartGame + { + const int MasterPingInterval = 60 * 3; // 3 minutes. server has a 5 minute TTL for games, so give ourselves a bit + // of leeway. + public int TickTimeout { get { return MasterPingInterval * 10000; } } + public void Tick(S server) + { + if (Environment.TickCount - lastPing > MasterPingInterval * 1000) + PingMasterServer(server); + else + lock (masterServerMessages) + while (masterServerMessages.Count > 0) + server.SendChat(null, masterServerMessages.Dequeue()); + + } + + + public void LobbyInfoSynced(S server) { PingMasterServer(server); } + public void GameStarted(S server) { PingMasterServer(server); } + + static int lastPing = 0; + // Todo: use the settings passed to the server instead + static bool isInternetServer = Game.Settings.Server.AdvertiseOnline; + static string masterServerUrl = Game.Settings.Server.MasterServer; + static int externalPort = Game.Settings.Server.ExternalPort; + static bool isInitialPing = true; + + static volatile bool isBusy; + static Queue masterServerMessages = new Queue(); + public static void PingMasterServer(S server) + { + if (isBusy || !isInternetServer) return; + + lastPing = Environment.TickCount; + isBusy = true; + + Action a = () => + { + try + { + var url = "ping.php?port={0}&name={1}&state={2}&players={3}&mods={4}&map={5}"; + if (isInitialPing) url += "&new=1"; + + using (var wc = new WebClient()) + { + wc.Proxy = null; + wc.DownloadData( + masterServerUrl + url.F( + externalPort, Uri.EscapeUriString(server.Name), + server.GameStarted ? 2 : 1, // todo: post-game states, etc. + server.lobbyInfo.Clients.Count, + string.Join(",", Game.CurrentMods.Select(f => "{0}@{1}".F(f.Key, f.Value.Version)).ToArray()), + server.lobbyInfo.GlobalSettings.Map)); + + if (isInitialPing) + { + isInitialPing = false; + lock (masterServerMessages) + masterServerMessages.Enqueue("Master server communication established."); + } + } + } + catch(Exception ex) + { + Log.Write("server", ex.ToString()); + lock( masterServerMessages ) + masterServerMessages.Enqueue( "Master server communication failed." ); + } + + isBusy = false; + }; + + a.BeginInvoke(null, null); + } + } +} diff --git a/OpenRA.Mods.RA/ServerTraits/PlayerCommands.cs b/OpenRA.Mods.RA/ServerTraits/PlayerCommands.cs index 5c2d2d7252..d3e30d4db1 100644 --- a/OpenRA.Mods.RA/ServerTraits/PlayerCommands.cs +++ b/OpenRA.Mods.RA/ServerTraits/PlayerCommands.cs @@ -1,104 +1,104 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Network; -using OpenRA.Server; -using S = OpenRA.Server.Server; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.RA.Server -{ - public class PlayerCommands : ServerTrait, IInterpretCommand - { - public bool InterpretCommand( S server, Connection conn, Session.Client client, string cmd) - { - if (server.GameStarted) - { - server.SendChatTo(conn, "Cannot change state when game started. ({0})".F(cmd)); - return false; - } - else if (client.State == Session.ClientState.Ready && !(cmd == "ready" || cmd == "startgame")) - { - server.SendChatTo(conn, "Cannot change state when marked as ready."); - return false; - } - - var dict = new Dictionary> - { - { "name", - s => - { - Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s); - client.Name = s; - server.SyncLobbyInfo(); - return true; - }}, - { "race", - s => - { - client.Country = s; - server.SyncLobbyInfo(); - return true; - }}, - { "team", - s => - { - int team; - if (!int.TryParse(s, out team)) { Log.Write("server", "Invalid team: {0}", s ); return false; } - - client.Team = team; - server.SyncLobbyInfo(); - return true; - }}, - { "spawn", - s => - { - int spawnPoint; - if (!int.TryParse(s, out spawnPoint) || spawnPoint < 0 || spawnPoint > 8) //TODO: SET properly! - { - Log.Write("server", "Invalid spawn point: {0}", s); - return false; - } - - if (server.lobbyInfo.Clients.Where( c => c != client ).Any( c => (c.SpawnPoint == spawnPoint) && (c.SpawnPoint != 0) )) - { - server.SendChatTo( conn, "You can't be at the same spawn point as another player" ); - return true; - } - - client.SpawnPoint = spawnPoint; - server.SyncLobbyInfo(); - return true; - }}, - { "color", - s => - { - var c = s.Split(',').Select(cc => int.Parse(cc)).ToArray(); - client.ColorRamp = new ColorRamp((byte)c[0], (byte)c[1], (byte)c[2], (byte)c[3]); - server.SyncLobbyInfo(); - return true; - }} - }; - - var cmdName = cmd.Split(' ').First(); - var cmdValue = string.Join(" ", cmd.Split(' ').Skip(1).ToArray()); - - Func a; - if (!dict.TryGetValue(cmdName, out a)) - return false; - - return a(cmdValue); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Network; +using OpenRA.Server; +using S = OpenRA.Server.Server; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.RA.Server +{ + public class PlayerCommands : ServerTrait, IInterpretCommand + { + public bool InterpretCommand( S server, Connection conn, Session.Client client, string cmd) + { + if (server.GameStarted) + { + server.SendChatTo(conn, "Cannot change state when game started. ({0})".F(cmd)); + return false; + } + else if (client.State == Session.ClientState.Ready && !(cmd == "ready" || cmd == "startgame")) + { + server.SendChatTo(conn, "Cannot change state when marked as ready."); + return false; + } + + var dict = new Dictionary> + { + { "name", + s => + { + Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s); + client.Name = s; + server.SyncLobbyInfo(); + return true; + }}, + { "race", + s => + { + client.Country = s; + server.SyncLobbyInfo(); + return true; + }}, + { "team", + s => + { + int team; + if (!int.TryParse(s, out team)) { Log.Write("server", "Invalid team: {0}", s ); return false; } + + client.Team = team; + server.SyncLobbyInfo(); + return true; + }}, + { "spawn", + s => + { + int spawnPoint; + if (!int.TryParse(s, out spawnPoint) || spawnPoint < 0 || spawnPoint > 8) //TODO: SET properly! + { + Log.Write("server", "Invalid spawn point: {0}", s); + return false; + } + + if (server.lobbyInfo.Clients.Where( c => c != client ).Any( c => (c.SpawnPoint == spawnPoint) && (c.SpawnPoint != 0) )) + { + server.SendChatTo( conn, "You can't be at the same spawn point as another player" ); + return true; + } + + client.SpawnPoint = spawnPoint; + server.SyncLobbyInfo(); + return true; + }}, + { "color", + s => + { + var c = s.Split(',').Select(cc => int.Parse(cc)).ToArray(); + client.ColorRamp = new ColorRamp((byte)c[0], (byte)c[1], (byte)c[2], (byte)c[3]); + server.SyncLobbyInfo(); + return true; + }} + }; + + var cmdName = cmd.Split(' ').First(); + var cmdValue = string.Join(" ", cmd.Split(' ').Skip(1).ToArray()); + + Func a; + if (!dict.TryGetValue(cmdName, out a)) + return false; + + return a(cmdValue); + } + } +} diff --git a/OpenRA.Mods.RA/ShroudPalette.cs b/OpenRA.Mods.RA/ShroudPalette.cs index e332e3a755..ae3e036ac2 100644 --- a/OpenRA.Mods.RA/ShroudPalette.cs +++ b/OpenRA.Mods.RA/ShroudPalette.cs @@ -1,65 +1,65 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.FileFormats; -using OpenRA.Traits; -using OpenRA.Graphics; - -namespace OpenRA.Mods.RA -{ - class ShroudPaletteInfo : ITraitInfo - { - public readonly string Name = "shroud"; - public readonly bool IsFog = false; - public object Create(ActorInitializer init) { return new ShroudPalette(this); } - } - - class ShroudPalette : IPalette - { - readonly ShroudPaletteInfo info; - public ShroudPalette( ShroudPaletteInfo info ) - { - this.info = info; - } - - public void InitPalette( WorldRenderer wr ) - { - var pal = wr.GetPalette( "terrain" ); - wr.AddPalette( info.Name, new Palette( pal, new ShroudPaletteRemap( info.IsFog ) ) ); - } - } - - class ShroudPaletteRemap : IPaletteRemap - { - bool isFog; - - public ShroudPaletteRemap(bool isFog) { this.isFog = isFog; } - public Color GetRemappedColor(Color original, int index) - { - if (isFog) - return new[] { - Color.Transparent, Color.Green, - Color.Blue, Color.Yellow, - Color.FromArgb(128,0,0,0), - Color.FromArgb(128,0,0,0), - Color.FromArgb(128,0,0,0), - Color.FromArgb(64,0,0,0)}[index % 8]; - else - return new[] { - Color.Transparent, Color.Green, - Color.Blue, Color.Yellow, - Color.Black, - Color.FromArgb(128,0,0,0), - Color.Transparent, - Color.Transparent}[index % 8]; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.FileFormats; +using OpenRA.Traits; +using OpenRA.Graphics; + +namespace OpenRA.Mods.RA +{ + class ShroudPaletteInfo : ITraitInfo + { + public readonly string Name = "shroud"; + public readonly bool IsFog = false; + public object Create(ActorInitializer init) { return new ShroudPalette(this); } + } + + class ShroudPalette : IPalette + { + readonly ShroudPaletteInfo info; + public ShroudPalette( ShroudPaletteInfo info ) + { + this.info = info; + } + + public void InitPalette( WorldRenderer wr ) + { + var pal = wr.GetPalette( "terrain" ); + wr.AddPalette( info.Name, new Palette( pal, new ShroudPaletteRemap( info.IsFog ) ) ); + } + } + + class ShroudPaletteRemap : IPaletteRemap + { + bool isFog; + + public ShroudPaletteRemap(bool isFog) { this.isFog = isFog; } + public Color GetRemappedColor(Color original, int index) + { + if (isFog) + return new[] { + Color.Transparent, Color.Green, + Color.Blue, Color.Yellow, + Color.FromArgb(128,0,0,0), + Color.FromArgb(128,0,0,0), + Color.FromArgb(128,0,0,0), + Color.FromArgb(64,0,0,0)}[index % 8]; + else + return new[] { + Color.Transparent, Color.Green, + Color.Blue, Color.Yellow, + Color.Black, + Color.FromArgb(128,0,0,0), + Color.Transparent, + Color.Transparent}[index % 8]; + } + } +} diff --git a/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs b/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs index 1dda898e7f..b3cbaf3a04 100644 --- a/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs +++ b/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs @@ -1,56 +1,56 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Effects; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class SmokeTrailWhenDamagedInfo : ITraitInfo - { - public readonly int[] Offset = { 0, 0 }; - public readonly int Interval = 1; - - public object Create(ActorInitializer init) { return new SmokeTrailWhenDamaged(init.self, this); } - } - - class SmokeTrailWhenDamaged : ITick - { - Turret smokeTurret; - int2 position; - int interval; - int ticks; - - public SmokeTrailWhenDamaged(Actor self, SmokeTrailWhenDamagedInfo info) - { - smokeTurret = new Turret(info.Offset); - interval = info.Interval; - } - - public void Tick(Actor self) - { - if (--ticks <= 0) - { - if (self.Trait().Altitude > 0) - { - var facing = self.Trait(); - var altitude = new float2(0, self.Trait().Altitude); - position = (self.CenterLocation - Combat.GetTurretPosition(self, facing, smokeTurret) - altitude).ToInt2(); - - if (self.GetDamageState() >= DamageState.Heavy) - self.World.AddFrameEndTask( - w => w.Add(new Smoke(w, position, "smokey"))); - } - - ticks = interval; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Effects; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class SmokeTrailWhenDamagedInfo : ITraitInfo + { + public readonly int[] Offset = { 0, 0 }; + public readonly int Interval = 1; + + public object Create(ActorInitializer init) { return new SmokeTrailWhenDamaged(init.self, this); } + } + + class SmokeTrailWhenDamaged : ITick + { + Turret smokeTurret; + int2 position; + int interval; + int ticks; + + public SmokeTrailWhenDamaged(Actor self, SmokeTrailWhenDamagedInfo info) + { + smokeTurret = new Turret(info.Offset); + interval = info.Interval; + } + + public void Tick(Actor self) + { + if (--ticks <= 0) + { + if (self.Trait().Altitude > 0) + { + var facing = self.Trait(); + var altitude = new float2(0, self.Trait().Altitude); + position = (self.CenterLocation - Combat.GetTurretPosition(self, facing, smokeTurret) - altitude).ToInt2(); + + if (self.GetDamageState() >= DamageState.Heavy) + self.World.AddFrameEndTask( + w => w.Add(new Smoke(w, position, "smokey"))); + } + + ticks = interval; + } + } + } +} diff --git a/OpenRA.Mods.RA/SpawnMPUnits.cs b/OpenRA.Mods.RA/SpawnMPUnits.cs index 7e25bc02a5..fbb7e9826e 100644 --- a/OpenRA.Mods.RA/SpawnMPUnits.cs +++ b/OpenRA.Mods.RA/SpawnMPUnits.cs @@ -1,38 +1,38 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.FileFormats; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class SpawnMPUnitsInfo : TraitInfo, ITraitPrerequisite {} - - class SpawnMPUnits : IWorldLoaded - { - public void WorldLoaded(World world) - { - foreach (var s in world.WorldActor.Trait().Start) - SpawnUnitsForPlayer(s.Key, s.Value); - } - - void SpawnUnitsForPlayer(Player p, int2 sp) - { - if (!p.PlayerRef.DefaultStartingUnits) - return; /* they don't want an mcv, the map provides something else for them OR it is a spectator. */ - - p.World.CreateActor("mcv", new TypeDictionary - { - new LocationInit( sp ), - new OwnerInit( p ), - }); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.FileFormats; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class SpawnMPUnitsInfo : TraitInfo, ITraitPrerequisite {} + + class SpawnMPUnits : IWorldLoaded + { + public void WorldLoaded(World world) + { + foreach (var s in world.WorldActor.Trait().Start) + SpawnUnitsForPlayer(s.Key, s.Value); + } + + void SpawnUnitsForPlayer(Player p, int2 sp) + { + if (!p.PlayerRef.DefaultStartingUnits) + return; /* they don't want an mcv, the map provides something else for them OR it is a spectator. */ + + p.World.CreateActor("mcv", new TypeDictionary + { + new LocationInit( sp ), + new OwnerInit( p ), + }); + } + } +} diff --git a/OpenRA.Mods.RA/SpawnMapActors.cs b/OpenRA.Mods.RA/SpawnMapActors.cs index 5b5343146d..3281636f5b 100644 --- a/OpenRA.Mods.RA/SpawnMapActors.cs +++ b/OpenRA.Mods.RA/SpawnMapActors.cs @@ -1,34 +1,34 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class SpawnMapActorsInfo : TraitInfo { } - - public class SpawnMapActors : IWorldLoaded - { - public Dictionary Actors = new Dictionary(); - - public void WorldLoaded(World world) - { - foreach (var actorReference in world.Map.Actors.Value) - { - var initDict = actorReference.Value.InitDict; - initDict.Add(new SkipMakeAnimsInit()); - Actors[actorReference.Key] = world.CreateActor(actorReference.Value.Type, initDict); - } - } - } - - public class SkipMakeAnimsInit : IActorInit {} -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class SpawnMapActorsInfo : TraitInfo { } + + public class SpawnMapActors : IWorldLoaded + { + public Dictionary Actors = new Dictionary(); + + public void WorldLoaded(World world) + { + foreach (var actorReference in world.Map.Actors.Value) + { + var initDict = actorReference.Value.InitDict; + initDict.Add(new SkipMakeAnimsInit()); + Actors[actorReference.Key] = world.CreateActor(actorReference.Value.Type, initDict); + } + } + } + + public class SkipMakeAnimsInit : IActorInit {} +} diff --git a/OpenRA.Mods.RA/Spy.cs b/OpenRA.Mods.RA/Spy.cs index b61fc5eab4..c5cd113e98 100644 --- a/OpenRA.Mods.RA/Spy.cs +++ b/OpenRA.Mods.RA/Spy.cs @@ -1,49 +1,49 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using System.Collections.Generic; - -namespace OpenRA.Mods.RA -{ - class SpyInfo : TraitInfo { } - - class Spy : IIssueOrder, IResolveOrder - { - public IEnumerable Orders - { - get { yield return new UnitTraitOrderTargeter( "SpyInfiltrate", 5, "enter", true, false ); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "SpyInfiltrate" ) - return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; - - return null; - } - - public void ResolveOrder(Actor self, Order order) - { - if (order.OrderString == "SpyInfiltrate") - { - self.SetTargetLine(Target.FromOrder(order), Color.Red); - - self.CancelActivity(); - self.QueueActivity(new Enter(order.TargetActor)); - self.QueueActivity(new Infiltrate(order.TargetActor)); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using System.Collections.Generic; + +namespace OpenRA.Mods.RA +{ + class SpyInfo : TraitInfo { } + + class Spy : IIssueOrder, IResolveOrder + { + public IEnumerable Orders + { + get { yield return new UnitTraitOrderTargeter( "SpyInfiltrate", 5, "enter", true, false ); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "SpyInfiltrate" ) + return new Order(order.OrderID, self, queued) { TargetActor = target.Actor }; + + return null; + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "SpyInfiltrate") + { + self.SetTargetLine(Target.FromOrder(order), Color.Red); + + self.CancelActivity(); + self.QueueActivity(new Enter(order.TargetActor)); + self.QueueActivity(new Infiltrate(order.TargetActor)); + } + } + } +} diff --git a/OpenRA.Mods.RA/StoresOre.cs b/OpenRA.Mods.RA/StoresOre.cs index 5abca6404c..ed5720302f 100644 --- a/OpenRA.Mods.RA/StoresOre.cs +++ b/OpenRA.Mods.RA/StoresOre.cs @@ -1,63 +1,63 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class StoresOreInfo : ITraitInfo - { - public readonly int PipCount = 0; - public readonly PipType PipColor = PipType.Yellow; - public readonly int Capacity = 0; - public object Create(ActorInitializer init) { return new StoresOre(init.self, this); } - } - - class StoresOre : IPips, INotifyCapture, INotifyDamage, IExplodeModifier, IStoreOre, ISync - { - readonly StoresOreInfo Info; - - [Sync] - public int Stored { get { return Player.OreCapacity == 0 ? 0 : Info.Capacity * Player.Ore / Player.OreCapacity; } } - - PlayerResources Player; - public StoresOre(Actor self, StoresOreInfo info) - { - Player = self.Owner.PlayerActor.Trait(); - Info = info; - } - - public int Capacity { get { return Info.Capacity; } } - - public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) - { - var ore = Stored; - Player.TakeOre(ore); - Player = newOwner.PlayerActor.Trait(); - Player.GiveOre(ore); - } - - public void Damaged(Actor self, AttackInfo e) - { - if (self.IsDead()) - Player.TakeOre(Stored); // Lose the stored ore - } - - public IEnumerable GetPips(Actor self) - { - return Graphics.Util.MakeArray( Info.PipCount, - i => ( Player.Ore * Info.PipCount > i * Player.OreCapacity ) - ? Info.PipColor : PipType.Transparent ); - } - - public bool ShouldExplode(Actor self) { return Stored > 0; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class StoresOreInfo : ITraitInfo + { + public readonly int PipCount = 0; + public readonly PipType PipColor = PipType.Yellow; + public readonly int Capacity = 0; + public object Create(ActorInitializer init) { return new StoresOre(init.self, this); } + } + + class StoresOre : IPips, INotifyCapture, INotifyDamage, IExplodeModifier, IStoreOre, ISync + { + readonly StoresOreInfo Info; + + [Sync] + public int Stored { get { return Player.OreCapacity == 0 ? 0 : Info.Capacity * Player.Ore / Player.OreCapacity; } } + + PlayerResources Player; + public StoresOre(Actor self, StoresOreInfo info) + { + Player = self.Owner.PlayerActor.Trait(); + Info = info; + } + + public int Capacity { get { return Info.Capacity; } } + + public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + { + var ore = Stored; + Player.TakeOre(ore); + Player = newOwner.PlayerActor.Trait(); + Player.GiveOre(ore); + } + + public void Damaged(Actor self, AttackInfo e) + { + if (self.IsDead()) + Player.TakeOre(Stored); // Lose the stored ore + } + + public IEnumerable GetPips(Actor self) + { + return Graphics.Util.MakeArray( Info.PipCount, + i => ( Player.Ore * Info.PipCount > i * Player.OreCapacity ) + ? Info.PipColor : PipType.Transparent ); + } + + public bool ShouldExplode(Actor self) { return Stored > 0; } + } +} diff --git a/OpenRA.Mods.RA/Strategic/StrategicVictoryConditions.cs b/OpenRA.Mods.RA/Strategic/StrategicVictoryConditions.cs index 8cf3e54c41..a59933f772 100644 --- a/OpenRA.Mods.RA/Strategic/StrategicVictoryConditions.cs +++ b/OpenRA.Mods.RA/Strategic/StrategicVictoryConditions.cs @@ -1,211 +1,211 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - /// - /// Attach to players only kthx :) - /// - public class StrategicVictoryConditionsInfo : ITraitInfo - { - public readonly int TicksToHold = 25 * 60 * 5; // ~5 minutes - public readonly bool ResetOnHoldLost = true; - public readonly float RatioRequired = 0.5f; // 50% required of all koth locations - public readonly float CriticalRatioRequired = 1f; // if someone owns 100% of all critical locations - public readonly bool SplitHolds = true; // disallow or allow the 'holdsrequired' to include critical locations - - public object Create(ActorInitializer init) { return new StrategicVictoryConditions(init.self, this); } - } - - public class StrategicVictoryConditions : ITick, ISync - { - [Sync] public Actor Self; - public StrategicVictoryConditionsInfo Info; - - [Sync] public int TicksToHold; - [Sync] public bool ResetOnHoldLost; - public float RatioRequired; - public float CriticalRatioRequired; - [Sync] public bool SplitHolds; - [Sync] public int TicksLeft = 0; - [Sync] public int CriticalTicksLeft = 0; - - public StrategicVictoryConditions(Actor self, StrategicVictoryConditionsInfo info) - { - Self = self; - Info = info; - - TicksToHold = info.TicksToHold; - ResetOnHoldLost = info.ResetOnHoldLost; - RatioRequired = info.RatioRequired; - CriticalRatioRequired = info.CriticalRatioRequired; - SplitHolds = info.SplitHolds; - } - - /// - /// Includes your allies as well - /// - public int Owned - { - get { return (SplitHolds) ? CountOwnedPoints(false) : CountOwnedPoints(false) + OwnedCritical; } - } - - /// - /// Includes your allies as well - /// - public int OwnedCritical - { - get { return CountOwnedPoints(true); } - } - - public int Total - { - get - { - return (SplitHolds) ? Self.World.Actors.Where(a => !a.Destroyed && a.HasTrait() && a.TraitOrDefault().Critical == false).Count() : Self.World.Actors.Where(a => a.HasTrait()).Count(); - } - } - - public int TotalCritical - { - get - { - return Self.World.Actors.Where(a => !a.Destroyed && a.HasTrait() && a.TraitOrDefault().Critical).Count(); - } - } - - public int CountOwnedPoints(bool critical) - { - int total = 0; - - foreach (var p in Self.World.players.Select(k => k.Value)) - { - if (p == Self.Owner || (p.Stances[Self.Owner] == Stance.Ally && Self.Owner.Stances[p] == Stance.Ally)) - { - total += Self.World.Queries.OwnedBy[p].Where(a => a.HasTrait() && a.TraitOrDefault().Critical == critical).Count(); - } - } - return total; - } - - public bool HoldingCritical - { - get - { - var criticalOwned = 1f / TotalCritical * OwnedCritical; - - return (criticalOwned >= CriticalRatioRequired); - } - } - - public bool Holding - { - get - { - var owned = 1f / Total * Owned; - - return (owned >= RatioRequired); - } - } - - public void Tick(Actor self) - { - if (self.Owner.WinState != WinState.Undefined || self.Owner.NonCombatant) return; - - var cvc = self.TraitOrDefault(); - if (cvc == null) - return; // Cannot work without ConquestVictoryConditions - - // See if any of the conditions are met to increase the count - if (TotalCritical > 0) - { - if (HoldingCritical) - { - // Hah! We met ths critical owned condition - if (CriticalTicksLeft == 0) - { - // First time - CriticalTicksLeft = TicksToHold; - } - else - { - // nth time - if (--CriticalTicksLeft == 0) - { - // Player & allies have won! - Won(); - } - } - } - else if (CriticalTicksLeft != 0) - { - // we lost the hold :/ - if (ResetOnHoldLost) - { - CriticalTicksLeft = TicksToHold; // Reset the time hold - } - } - } - - // See if any of the conditions are met to increase the count - if (Total > 0) - { - if (Holding) - { - // Hah! We met ths critical owned condition - if (TicksLeft == 0) - { - // First time - TicksLeft = TicksToHold; - } - else - { - // nth time - if (--TicksLeft == 0) - { - // Player & allies have won! - Won(); - } - } - } - else if (TicksLeft != 0) - { - // we lost the hold :/ - if (ResetOnHoldLost) - { - TicksLeft = TicksToHold; // Reset the time hold - } - } - } - } - - public void Won() - { - // Player has won - foreach (var p in Self.World.players.Select(k => k.Value)) - { - var cvc = p.PlayerActor.TraitOrDefault(); - - if ((p.WinState == WinState.Undefined) && (p == Self.Owner || (p.Stances[Self.Owner] == Stance.Ally && Self.Owner.Stances[p] == Stance.Ally))) - { - cvc.Win(p.PlayerActor); - } - else if (p.WinState == WinState.Undefined) - { - cvc.Surrender(p.PlayerActor); - } - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + /// + /// Attach to players only kthx :) + /// + public class StrategicVictoryConditionsInfo : ITraitInfo + { + public readonly int TicksToHold = 25 * 60 * 5; // ~5 minutes + public readonly bool ResetOnHoldLost = true; + public readonly float RatioRequired = 0.5f; // 50% required of all koth locations + public readonly float CriticalRatioRequired = 1f; // if someone owns 100% of all critical locations + public readonly bool SplitHolds = true; // disallow or allow the 'holdsrequired' to include critical locations + + public object Create(ActorInitializer init) { return new StrategicVictoryConditions(init.self, this); } + } + + public class StrategicVictoryConditions : ITick, ISync + { + [Sync] public Actor Self; + public StrategicVictoryConditionsInfo Info; + + [Sync] public int TicksToHold; + [Sync] public bool ResetOnHoldLost; + public float RatioRequired; + public float CriticalRatioRequired; + [Sync] public bool SplitHolds; + [Sync] public int TicksLeft = 0; + [Sync] public int CriticalTicksLeft = 0; + + public StrategicVictoryConditions(Actor self, StrategicVictoryConditionsInfo info) + { + Self = self; + Info = info; + + TicksToHold = info.TicksToHold; + ResetOnHoldLost = info.ResetOnHoldLost; + RatioRequired = info.RatioRequired; + CriticalRatioRequired = info.CriticalRatioRequired; + SplitHolds = info.SplitHolds; + } + + /// + /// Includes your allies as well + /// + public int Owned + { + get { return (SplitHolds) ? CountOwnedPoints(false) : CountOwnedPoints(false) + OwnedCritical; } + } + + /// + /// Includes your allies as well + /// + public int OwnedCritical + { + get { return CountOwnedPoints(true); } + } + + public int Total + { + get + { + return (SplitHolds) ? Self.World.Actors.Where(a => !a.Destroyed && a.HasTrait() && a.TraitOrDefault().Critical == false).Count() : Self.World.Actors.Where(a => a.HasTrait()).Count(); + } + } + + public int TotalCritical + { + get + { + return Self.World.Actors.Where(a => !a.Destroyed && a.HasTrait() && a.TraitOrDefault().Critical).Count(); + } + } + + public int CountOwnedPoints(bool critical) + { + int total = 0; + + foreach (var p in Self.World.players.Select(k => k.Value)) + { + if (p == Self.Owner || (p.Stances[Self.Owner] == Stance.Ally && Self.Owner.Stances[p] == Stance.Ally)) + { + total += Self.World.Queries.OwnedBy[p].Where(a => a.HasTrait() && a.TraitOrDefault().Critical == critical).Count(); + } + } + return total; + } + + public bool HoldingCritical + { + get + { + var criticalOwned = 1f / TotalCritical * OwnedCritical; + + return (criticalOwned >= CriticalRatioRequired); + } + } + + public bool Holding + { + get + { + var owned = 1f / Total * Owned; + + return (owned >= RatioRequired); + } + } + + public void Tick(Actor self) + { + if (self.Owner.WinState != WinState.Undefined || self.Owner.NonCombatant) return; + + var cvc = self.TraitOrDefault(); + if (cvc == null) + return; // Cannot work without ConquestVictoryConditions + + // See if any of the conditions are met to increase the count + if (TotalCritical > 0) + { + if (HoldingCritical) + { + // Hah! We met ths critical owned condition + if (CriticalTicksLeft == 0) + { + // First time + CriticalTicksLeft = TicksToHold; + } + else + { + // nth time + if (--CriticalTicksLeft == 0) + { + // Player & allies have won! + Won(); + } + } + } + else if (CriticalTicksLeft != 0) + { + // we lost the hold :/ + if (ResetOnHoldLost) + { + CriticalTicksLeft = TicksToHold; // Reset the time hold + } + } + } + + // See if any of the conditions are met to increase the count + if (Total > 0) + { + if (Holding) + { + // Hah! We met ths critical owned condition + if (TicksLeft == 0) + { + // First time + TicksLeft = TicksToHold; + } + else + { + // nth time + if (--TicksLeft == 0) + { + // Player & allies have won! + Won(); + } + } + } + else if (TicksLeft != 0) + { + // we lost the hold :/ + if (ResetOnHoldLost) + { + TicksLeft = TicksToHold; // Reset the time hold + } + } + } + } + + public void Won() + { + // Player has won + foreach (var p in Self.World.players.Select(k => k.Value)) + { + var cvc = p.PlayerActor.TraitOrDefault(); + + if ((p.WinState == WinState.Undefined) && (p == Self.Owner || (p.Stances[Self.Owner] == Stance.Ally && Self.Owner.Stances[p] == Stance.Ally))) + { + cvc.Win(p.PlayerActor); + } + else if (p.WinState == WinState.Undefined) + { + cvc.Surrender(p.PlayerActor); + } + } + } + } +} diff --git a/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs b/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs index 888050276b..1c28c071ae 100755 --- a/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs +++ b/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs @@ -1,64 +1,64 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.FileFormats; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Air; -using OpenRA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class AirstrikePowerInfo : SupportPowerInfo - { - [ActorReference] - public readonly string UnitType = "badr.bomber"; - [ActorReference] - public readonly string FlareType = null; - - public override object Create(ActorInitializer init) { return new AirstrikePower(init.self, this); } - } - - class AirstrikePower : SupportPower - { - public AirstrikePower(Actor self, AirstrikePowerInfo info) : base(self, info) { } - public override void Activate(Actor self, Order order) - { - var startPos = self.World.ChooseRandomEdgeCell(); - self.World.AddFrameEndTask(w => - { - var info = (Info as AirstrikePowerInfo); - var flare = info.FlareType != null ? w.CreateActor(info.FlareType, new TypeDictionary - { - new LocationInit( order.TargetLocation ), - new OwnerInit( self.Owner ), - }) : null; - - var a = w.CreateActor(info.UnitType, new TypeDictionary - { - new LocationInit( startPos ), - new OwnerInit( self.Owner ), - new FacingInit( Util.GetFacing(order.TargetLocation - startPos, 0) ), - new AltitudeInit( Rules.Info[info.UnitType].Traits.Get().CruiseAltitude ), - }); - a.Trait().SetTarget(order.TargetLocation); - - a.CancelActivity(); - a.QueueActivity(Fly.ToCell(order.TargetLocation)); - - if (flare != null) - a.QueueActivity(new CallFunc(() => flare.Destroy())); - - a.QueueActivity(new FlyOffMap { Interruptible = false }); - a.QueueActivity(new RemoveSelf()); - }); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Air; +using OpenRA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class AirstrikePowerInfo : SupportPowerInfo + { + [ActorReference] + public readonly string UnitType = "badr.bomber"; + [ActorReference] + public readonly string FlareType = null; + + public override object Create(ActorInitializer init) { return new AirstrikePower(init.self, this); } + } + + class AirstrikePower : SupportPower + { + public AirstrikePower(Actor self, AirstrikePowerInfo info) : base(self, info) { } + public override void Activate(Actor self, Order order) + { + var startPos = self.World.ChooseRandomEdgeCell(); + self.World.AddFrameEndTask(w => + { + var info = (Info as AirstrikePowerInfo); + var flare = info.FlareType != null ? w.CreateActor(info.FlareType, new TypeDictionary + { + new LocationInit( order.TargetLocation ), + new OwnerInit( self.Owner ), + }) : null; + + var a = w.CreateActor(info.UnitType, new TypeDictionary + { + new LocationInit( startPos ), + new OwnerInit( self.Owner ), + new FacingInit( Util.GetFacing(order.TargetLocation - startPos, 0) ), + new AltitudeInit( Rules.Info[info.UnitType].Traits.Get().CruiseAltitude ), + }); + a.Trait().SetTarget(order.TargetLocation); + + a.CancelActivity(); + a.QueueActivity(Fly.ToCell(order.TargetLocation)); + + if (flare != null) + a.QueueActivity(new CallFunc(() => flare.Destroy())); + + a.QueueActivity(new FlyOffMap { Interruptible = false }); + a.QueueActivity(new RemoveSelf()); + }); + } + } +} diff --git a/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs b/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs index c841c42802..334f5a1551 100755 --- a/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/ChronoshiftPower.cs @@ -1,245 +1,245 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using OpenRA.Mods.RA.Effects; - -namespace OpenRA.Mods.RA -{ - class ChronoshiftPowerInfo : SupportPowerInfo - { - public readonly int Range = 1; // Range in cells - public readonly int Duration = 30; // Seconds - public readonly bool KillCargo = true; - - public override object Create(ActorInitializer init) { return new ChronoshiftPower(init.self,this); } - } - - class ChronoshiftPower : SupportPower - { - public ChronoshiftPower(Actor self, ChronoshiftPowerInfo info) : base(self, info) { } - - public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager) - { - Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound); - return new SelectTarget(order, manager, this); - } - - public override void Activate(Actor self, Order order) - { - self.Trait().PlayCustomAnim(self, "active"); - - // Trigger screen desaturate effect - foreach (var a in self.World.Queries.WithTrait()) - a.Trait.Enable(); - - Sound.Play("chrono2.aud", Game.CellSize * order.TargetLocation); - Sound.Play("chrono2.aud", Game.CellSize * order.ExtraLocation); - foreach (var target in UnitsInRange(order.ExtraLocation)) - { - var cs = target.Trait(); - var targetCell = target.Location + order.TargetLocation - order.ExtraLocation; - var cpi = Info as ChronoshiftPowerInfo; - - if (cs.CanChronoshiftTo(target, targetCell, true)) - cs.Teleport(target, targetCell, - cpi.Duration * 25, cpi.KillCargo, self); - } - } - - public IEnumerable UnitsInRange(int2 xy) - { - int range = (Info as ChronoshiftPowerInfo).Range; - var uim = self.World.WorldActor.Trait(); - var tiles = self.World.FindTilesInCircle(xy, range); - var units = new List(); - foreach (var t in tiles) - units.AddRange(uim.GetUnitsAt(t)); - - return units.Distinct().Where(a => a.HasTrait()); - } - - class SelectTarget : IOrderGenerator - { - readonly ChronoshiftPower power; - readonly int range; - readonly Sprite tile; - readonly SupportPowerManager manager; - readonly string order; - - public SelectTarget(string order, SupportPowerManager manager, ChronoshiftPower power) - { - this.manager = manager; - this.order = order; - this.power = power; - this.range = (power.Info as ChronoshiftPowerInfo).Range; - tile = UiOverlay.SynthesizeTile(0x04); - } - - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - world.CancelInputMode(); - if (mi.Button == MouseButton.Left) - world.OrderGenerator = new SelectDestination(order, manager, power, xy); - - yield break; - } - - public void Tick(World world) - { - // Cancel the OG if we can't use the power - if (!manager.Powers.ContainsKey(order)) - world.CancelInputMode(); - } - - public void RenderAfterWorld(WorldRenderer wr, World world) - { - var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); - var targetUnits = power.UnitsInRange(xy); - foreach (var unit in targetUnits) - wr.DrawSelectionBox(unit, Color.Red); - } - - public void RenderBeforeWorld(WorldRenderer wr, World world) - { - var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); - var tiles = world.FindTilesInCircle(xy, range); - foreach (var t in tiles) - tile.DrawAt( wr, Game.CellSize * t, "terrain" ); - } - - public string GetCursor(World world, int2 xy, MouseInput mi) - { - return "chrono-select"; - } - } - - class SelectDestination : IOrderGenerator - { - readonly ChronoshiftPower power; - readonly int2 sourceLocation; - readonly int range; - readonly Sprite validTile, invalidTile, sourceTile; - readonly SupportPowerManager manager; - readonly string order; - - public SelectDestination(string order, SupportPowerManager manager, ChronoshiftPower power, int2 sourceLocation) - { - this.manager = manager; - this.order = order; - this.power = power; - this.sourceLocation = sourceLocation; - this.range = (power.Info as ChronoshiftPowerInfo).Range; - - // todo: this burns up more texture space every time someone uses chronoshift. - validTile = UiOverlay.SynthesizeTile(0x0f); - invalidTile = UiOverlay.SynthesizeTile(0x08); - sourceTile = UiOverlay.SynthesizeTile(0x04); - } - - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - if (mi.Button == MouseButton.Right) - { - world.CancelInputMode(); - yield break; - } - - var ret = OrderInner( world, xy, mi ).FirstOrDefault(); - if (ret == null) - yield break; - - world.CancelInputMode(); - yield return ret; - } - - IEnumerable OrderInner(World world, int2 xy, MouseInput mi) - { - // Cannot chronoshift into unexplored location - if (IsValidTarget(xy)) - yield return new Order(order, manager.self, false) - { - TargetLocation = xy, - ExtraLocation = sourceLocation - }; - } - - public void Tick(World world) - { - // Cancel the OG if we can't use the power - if (!manager.Powers.ContainsKey(order)) - world.CancelInputMode(); - } - - public void RenderAfterWorld(WorldRenderer wr, World world) - { - foreach (var unit in power.UnitsInRange(sourceLocation)) - wr.DrawSelectionBox(unit, Color.Red); - } - - public void RenderBeforeWorld(WorldRenderer wr, World world) - { - var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); - - // Source tiles - foreach (var t in world.FindTilesInCircle(sourceLocation, range)) - sourceTile.DrawAt( wr, Game.CellSize * t, "terrain" ); - - // Destination tiles - foreach (var t in world.FindTilesInCircle(xy, range)) - sourceTile.DrawAt( wr, Game.CellSize * t, "terrain" ); - - // Unit previews - foreach (var unit in power.UnitsInRange(sourceLocation)) - { - var targetCell = unit.Location + xy - sourceLocation; - foreach (var r in unit.Render()) - r.Sprite.DrawAt(r.Pos - Traits.Util.CenterOfCell(unit.Location) + Traits.Util.CenterOfCell(targetCell), - wr.GetPaletteIndex(r.Palette ?? unit.Owner.Palette), - r.Scale*r.Sprite.size); - } - - // Unit tiles - foreach (var unit in power.UnitsInRange(sourceLocation)) - { - var targetCell = unit.Location + xy - sourceLocation; - var canEnter = unit.Trait().CanChronoshiftTo(unit,targetCell, false); - var tile = canEnter ? validTile : invalidTile; - tile.DrawAt( wr, Game.CellSize * targetCell, "terrain" ); - } - } - - bool IsValidTarget(int2 xy) - { - var canTeleport = false; - foreach (var unit in power.UnitsInRange(sourceLocation)) - { - var targetCell = unit.Location + xy - sourceLocation; - if (unit.Trait().CanChronoshiftTo(unit,targetCell, false)) - { - canTeleport = true; - break; - } - } - return canTeleport; - } - - public string GetCursor(World world, int2 xy, MouseInput mi) - { - return IsValidTarget(xy) ? "chrono-target" : "move-blocked"; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using OpenRA.Mods.RA.Effects; + +namespace OpenRA.Mods.RA +{ + class ChronoshiftPowerInfo : SupportPowerInfo + { + public readonly int Range = 1; // Range in cells + public readonly int Duration = 30; // Seconds + public readonly bool KillCargo = true; + + public override object Create(ActorInitializer init) { return new ChronoshiftPower(init.self,this); } + } + + class ChronoshiftPower : SupportPower + { + public ChronoshiftPower(Actor self, ChronoshiftPowerInfo info) : base(self, info) { } + + public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager) + { + Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound); + return new SelectTarget(order, manager, this); + } + + public override void Activate(Actor self, Order order) + { + self.Trait().PlayCustomAnim(self, "active"); + + // Trigger screen desaturate effect + foreach (var a in self.World.Queries.WithTrait()) + a.Trait.Enable(); + + Sound.Play("chrono2.aud", Game.CellSize * order.TargetLocation); + Sound.Play("chrono2.aud", Game.CellSize * order.ExtraLocation); + foreach (var target in UnitsInRange(order.ExtraLocation)) + { + var cs = target.Trait(); + var targetCell = target.Location + order.TargetLocation - order.ExtraLocation; + var cpi = Info as ChronoshiftPowerInfo; + + if (cs.CanChronoshiftTo(target, targetCell, true)) + cs.Teleport(target, targetCell, + cpi.Duration * 25, cpi.KillCargo, self); + } + } + + public IEnumerable UnitsInRange(int2 xy) + { + int range = (Info as ChronoshiftPowerInfo).Range; + var uim = self.World.WorldActor.Trait(); + var tiles = self.World.FindTilesInCircle(xy, range); + var units = new List(); + foreach (var t in tiles) + units.AddRange(uim.GetUnitsAt(t)); + + return units.Distinct().Where(a => a.HasTrait()); + } + + class SelectTarget : IOrderGenerator + { + readonly ChronoshiftPower power; + readonly int range; + readonly Sprite tile; + readonly SupportPowerManager manager; + readonly string order; + + public SelectTarget(string order, SupportPowerManager manager, ChronoshiftPower power) + { + this.manager = manager; + this.order = order; + this.power = power; + this.range = (power.Info as ChronoshiftPowerInfo).Range; + tile = UiOverlay.SynthesizeTile(0x04); + } + + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + world.CancelInputMode(); + if (mi.Button == MouseButton.Left) + world.OrderGenerator = new SelectDestination(order, manager, power, xy); + + yield break; + } + + public void Tick(World world) + { + // Cancel the OG if we can't use the power + if (!manager.Powers.ContainsKey(order)) + world.CancelInputMode(); + } + + public void RenderAfterWorld(WorldRenderer wr, World world) + { + var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); + var targetUnits = power.UnitsInRange(xy); + foreach (var unit in targetUnits) + wr.DrawSelectionBox(unit, Color.Red); + } + + public void RenderBeforeWorld(WorldRenderer wr, World world) + { + var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); + var tiles = world.FindTilesInCircle(xy, range); + foreach (var t in tiles) + tile.DrawAt( wr, Game.CellSize * t, "terrain" ); + } + + public string GetCursor(World world, int2 xy, MouseInput mi) + { + return "chrono-select"; + } + } + + class SelectDestination : IOrderGenerator + { + readonly ChronoshiftPower power; + readonly int2 sourceLocation; + readonly int range; + readonly Sprite validTile, invalidTile, sourceTile; + readonly SupportPowerManager manager; + readonly string order; + + public SelectDestination(string order, SupportPowerManager manager, ChronoshiftPower power, int2 sourceLocation) + { + this.manager = manager; + this.order = order; + this.power = power; + this.sourceLocation = sourceLocation; + this.range = (power.Info as ChronoshiftPowerInfo).Range; + + // todo: this burns up more texture space every time someone uses chronoshift. + validTile = UiOverlay.SynthesizeTile(0x0f); + invalidTile = UiOverlay.SynthesizeTile(0x08); + sourceTile = UiOverlay.SynthesizeTile(0x04); + } + + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Right) + { + world.CancelInputMode(); + yield break; + } + + var ret = OrderInner( world, xy, mi ).FirstOrDefault(); + if (ret == null) + yield break; + + world.CancelInputMode(); + yield return ret; + } + + IEnumerable OrderInner(World world, int2 xy, MouseInput mi) + { + // Cannot chronoshift into unexplored location + if (IsValidTarget(xy)) + yield return new Order(order, manager.self, false) + { + TargetLocation = xy, + ExtraLocation = sourceLocation + }; + } + + public void Tick(World world) + { + // Cancel the OG if we can't use the power + if (!manager.Powers.ContainsKey(order)) + world.CancelInputMode(); + } + + public void RenderAfterWorld(WorldRenderer wr, World world) + { + foreach (var unit in power.UnitsInRange(sourceLocation)) + wr.DrawSelectionBox(unit, Color.Red); + } + + public void RenderBeforeWorld(WorldRenderer wr, World world) + { + var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); + + // Source tiles + foreach (var t in world.FindTilesInCircle(sourceLocation, range)) + sourceTile.DrawAt( wr, Game.CellSize * t, "terrain" ); + + // Destination tiles + foreach (var t in world.FindTilesInCircle(xy, range)) + sourceTile.DrawAt( wr, Game.CellSize * t, "terrain" ); + + // Unit previews + foreach (var unit in power.UnitsInRange(sourceLocation)) + { + var targetCell = unit.Location + xy - sourceLocation; + foreach (var r in unit.Render()) + r.Sprite.DrawAt(r.Pos - Traits.Util.CenterOfCell(unit.Location) + Traits.Util.CenterOfCell(targetCell), + wr.GetPaletteIndex(r.Palette ?? unit.Owner.Palette), + r.Scale*r.Sprite.size); + } + + // Unit tiles + foreach (var unit in power.UnitsInRange(sourceLocation)) + { + var targetCell = unit.Location + xy - sourceLocation; + var canEnter = unit.Trait().CanChronoshiftTo(unit,targetCell, false); + var tile = canEnter ? validTile : invalidTile; + tile.DrawAt( wr, Game.CellSize * targetCell, "terrain" ); + } + } + + bool IsValidTarget(int2 xy) + { + var canTeleport = false; + foreach (var unit in power.UnitsInRange(sourceLocation)) + { + var targetCell = unit.Location + xy - sourceLocation; + if (unit.Trait().CanChronoshiftTo(unit,targetCell, false)) + { + canTeleport = true; + break; + } + } + return canTeleport; + } + + public string GetCursor(World world, int2 xy, MouseInput mi) + { + return IsValidTarget(xy) ? "chrono-target" : "move-blocked"; + } + } + } +} diff --git a/OpenRA.Mods.RA/SupportPowers/GpsPower.cs b/OpenRA.Mods.RA/SupportPowers/GpsPower.cs index 770fdc774d..6f49873b56 100755 --- a/OpenRA.Mods.RA/SupportPowers/GpsPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/GpsPower.cs @@ -1,68 +1,68 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Effects; -using OpenRA.Mods.RA.Effects; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class GpsPowerInfo : SupportPowerInfo - { - public readonly int RevealDelay = 0; - - public override object Create(ActorInitializer init) { return new GpsPower(init.self, this); } - } - - class GpsPower : SupportPower, INotifyDamage, ISync - { - public GpsPower(Actor self, GpsPowerInfo info) : base(self, info) { } - - [Sync] - public bool Granted; - - public override void Charged(Actor self, string key) - { - self.Owner.PlayerActor.Trait().Powers[key].Activate(new Order()); - } - - public override void Activate(Actor self, Order order) - { - self.World.AddFrameEndTask(w => - { - Sound.PlayToPlayer(self.Owner, Info.LaunchSound); - - w.Add(new SatelliteLaunch(self)); - - /* there is only one shroud, but it is misleadingly available through Player.Shroud */ - w.Add(new DelayedAction((Info as GpsPowerInfo).RevealDelay * 25, - () => { Granted = true; RefreshGps(self); })); - }); - } - - public void Damaged(Actor self, AttackInfo e) - { - if (e.DamageState == DamageState.Dead) - { - Granted = false; - RefreshGps(self); - } - } - - void RefreshGps(Actor self) - { - if (self.World.LocalPlayer != null) - self.World.LocalShroud.Disabled = self.World.Queries.WithTrait() - .Any(p => p.Actor.Owner.Stances[self.World.LocalPlayer] == Stance.Ally && - p.Trait.Granted); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Effects; +using OpenRA.Mods.RA.Effects; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class GpsPowerInfo : SupportPowerInfo + { + public readonly int RevealDelay = 0; + + public override object Create(ActorInitializer init) { return new GpsPower(init.self, this); } + } + + class GpsPower : SupportPower, INotifyDamage, ISync + { + public GpsPower(Actor self, GpsPowerInfo info) : base(self, info) { } + + [Sync] + public bool Granted; + + public override void Charged(Actor self, string key) + { + self.Owner.PlayerActor.Trait().Powers[key].Activate(new Order()); + } + + public override void Activate(Actor self, Order order) + { + self.World.AddFrameEndTask(w => + { + Sound.PlayToPlayer(self.Owner, Info.LaunchSound); + + w.Add(new SatelliteLaunch(self)); + + /* there is only one shroud, but it is misleadingly available through Player.Shroud */ + w.Add(new DelayedAction((Info as GpsPowerInfo).RevealDelay * 25, + () => { Granted = true; RefreshGps(self); })); + }); + } + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageState == DamageState.Dead) + { + Granted = false; + RefreshGps(self); + } + } + + void RefreshGps(Actor self) + { + if (self.World.LocalPlayer != null) + self.World.LocalShroud.Disabled = self.World.Queries.WithTrait() + .Any(p => p.Actor.Owner.Stances[self.World.LocalPlayer] == Stance.Ally && + p.Trait.Granted); + } + } +} diff --git a/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs b/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs index 99442db0b1..674fe2d16d 100755 --- a/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/IronCurtainPower.cs @@ -1,111 +1,111 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Effects; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; -using TUtil = OpenRA.Traits.Util; - -namespace OpenRA.Mods.RA -{ - class IronCurtainPowerInfo : SupportPowerInfo - { - public readonly int Duration = 10; // Seconds - public readonly int Range = 1; // Range in cells - - public override object Create(ActorInitializer init) { return new IronCurtainPower(init.self, this); } - } - - class IronCurtainPower : SupportPower - { - public IronCurtainPower(Actor self, IronCurtainPowerInfo info) : base(self, info) { } - public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager) - { - Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound); - return new SelectTarget(order, manager, this); - } - - public override void Activate(Actor self, Order order) - { - self.Trait().PlayCustomAnim(self, "active"); - - Sound.Play("ironcur9.aud", Game.CellSize * order.TargetLocation); - foreach (var target in UnitsInRange(order.TargetLocation)) - target.Trait().Activate(target, (Info as IronCurtainPowerInfo).Duration * 25); - } - - public IEnumerable UnitsInRange(int2 xy) - { - int range = (Info as IronCurtainPowerInfo).Range; - var uim = self.World.WorldActor.Trait(); - var tiles = self.World.FindTilesInCircle(xy, range); - var units = new List(); - foreach (var t in tiles) - units.AddRange(uim.GetUnitsAt(t)); - - return units.Distinct().Where(a => a.HasTrait()); - } - - class SelectTarget : IOrderGenerator - { - readonly IronCurtainPower power; - readonly int range; - readonly Sprite tile; - readonly SupportPowerManager manager; - readonly string order; - - public SelectTarget(string order, SupportPowerManager manager, IronCurtainPower power) - { - this.manager = manager; - this.order = order; - this.power = power; - this.range = (power.Info as IronCurtainPowerInfo).Range; - tile = UiOverlay.SynthesizeTile(0x04); - } - - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - world.CancelInputMode(); - if (mi.Button == MouseButton.Left && power.UnitsInRange(xy).Any()) - yield return new Order(order, manager.self, false) { TargetLocation = xy }; - } - - public void Tick(World world) - { - // Cancel the OG if we can't use the power - if (!manager.Powers.ContainsKey(order)) - world.CancelInputMode(); - } - - public void RenderAfterWorld(WorldRenderer wr, World world) - { - var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); - foreach (var unit in power.UnitsInRange(xy)) - wr.DrawSelectionBox(unit, Color.Red); - } - - public void RenderBeforeWorld(WorldRenderer wr, World world) - { - var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); - foreach (var t in world.FindTilesInCircle(xy, range)) - tile.DrawAt( wr, Game.CellSize * t, "terrain" ); - } - - public string GetCursor(World world, int2 xy, MouseInput mi) - { - return power.UnitsInRange(xy).Any() ? "ability" : "move-blocked"; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Effects; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; +using TUtil = OpenRA.Traits.Util; + +namespace OpenRA.Mods.RA +{ + class IronCurtainPowerInfo : SupportPowerInfo + { + public readonly int Duration = 10; // Seconds + public readonly int Range = 1; // Range in cells + + public override object Create(ActorInitializer init) { return new IronCurtainPower(init.self, this); } + } + + class IronCurtainPower : SupportPower + { + public IronCurtainPower(Actor self, IronCurtainPowerInfo info) : base(self, info) { } + public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager) + { + Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound); + return new SelectTarget(order, manager, this); + } + + public override void Activate(Actor self, Order order) + { + self.Trait().PlayCustomAnim(self, "active"); + + Sound.Play("ironcur9.aud", Game.CellSize * order.TargetLocation); + foreach (var target in UnitsInRange(order.TargetLocation)) + target.Trait().Activate(target, (Info as IronCurtainPowerInfo).Duration * 25); + } + + public IEnumerable UnitsInRange(int2 xy) + { + int range = (Info as IronCurtainPowerInfo).Range; + var uim = self.World.WorldActor.Trait(); + var tiles = self.World.FindTilesInCircle(xy, range); + var units = new List(); + foreach (var t in tiles) + units.AddRange(uim.GetUnitsAt(t)); + + return units.Distinct().Where(a => a.HasTrait()); + } + + class SelectTarget : IOrderGenerator + { + readonly IronCurtainPower power; + readonly int range; + readonly Sprite tile; + readonly SupportPowerManager manager; + readonly string order; + + public SelectTarget(string order, SupportPowerManager manager, IronCurtainPower power) + { + this.manager = manager; + this.order = order; + this.power = power; + this.range = (power.Info as IronCurtainPowerInfo).Range; + tile = UiOverlay.SynthesizeTile(0x04); + } + + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + world.CancelInputMode(); + if (mi.Button == MouseButton.Left && power.UnitsInRange(xy).Any()) + yield return new Order(order, manager.self, false) { TargetLocation = xy }; + } + + public void Tick(World world) + { + // Cancel the OG if we can't use the power + if (!manager.Powers.ContainsKey(order)) + world.CancelInputMode(); + } + + public void RenderAfterWorld(WorldRenderer wr, World world) + { + var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); + foreach (var unit in power.UnitsInRange(xy)) + wr.DrawSelectionBox(unit, Color.Red); + } + + public void RenderBeforeWorld(WorldRenderer wr, World world) + { + var xy = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); + foreach (var t in world.FindTilesInCircle(xy, range)) + tile.DrawAt( wr, Game.CellSize * t, "terrain" ); + } + + public string GetCursor(World world, int2 xy, MouseInput mi) + { + return power.UnitsInRange(xy).Any() ? "ability" : "move-blocked"; + } + } + } +} diff --git a/OpenRA.Mods.RA/SupportPowers/NukePower.cs b/OpenRA.Mods.RA/SupportPowers/NukePower.cs index e9eef62c57..8c048c1d7d 100755 --- a/OpenRA.Mods.RA/SupportPowers/NukePower.cs +++ b/OpenRA.Mods.RA/SupportPowers/NukePower.cs @@ -1,49 +1,49 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Effects; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class NukePowerInfo : SupportPowerInfo - { - [WeaponReference] - public readonly string MissileWeapon = ""; - public readonly int2 SpawnOffset = int2.Zero; - - public override object Create(ActorInitializer init) { return new NukePower(init.self, this); } - } - - class NukePower : SupportPower - { - public NukePower(Actor self, NukePowerInfo info) : base(self, info) { } - public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager) - { - Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound); - return new SelectGenericPowerTarget(order, manager, "nuke", MouseButton.Left); - } - - public override void Activate(Actor self, Order order) - { - // Play to everyone but the current player - if (self.Owner != self.World.LocalPlayer) - Sound.Play(Info.LaunchSound); - - var npi = Info as NukePowerInfo; - - self.Trait().PlayCustomAnim(self, "active"); - self.World.AddFrameEndTask(w => w.Add( - new NukeLaunch(self.Owner, self, npi.MissileWeapon, npi.SpawnOffset, - order.TargetLocation))); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Effects; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class NukePowerInfo : SupportPowerInfo + { + [WeaponReference] + public readonly string MissileWeapon = ""; + public readonly int2 SpawnOffset = int2.Zero; + + public override object Create(ActorInitializer init) { return new NukePower(init.self, this); } + } + + class NukePower : SupportPower + { + public NukePower(Actor self, NukePowerInfo info) : base(self, info) { } + public override IOrderGenerator OrderGenerator(string order, SupportPowerManager manager) + { + Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound); + return new SelectGenericPowerTarget(order, manager, "nuke", MouseButton.Left); + } + + public override void Activate(Actor self, Order order) + { + // Play to everyone but the current player + if (self.Owner != self.World.LocalPlayer) + Sound.Play(Info.LaunchSound); + + var npi = Info as NukePowerInfo; + + self.Trait().PlayCustomAnim(self, "active"); + self.World.AddFrameEndTask(w => w.Add( + new NukeLaunch(self.Owner, self, npi.MissileWeapon, npi.SpawnOffset, + order.TargetLocation))); + } + } +} diff --git a/OpenRA.Mods.RA/SupportPowers/ParatroopersPower.cs b/OpenRA.Mods.RA/SupportPowers/ParatroopersPower.cs index 4bb6fa7a4c..df6fab3347 100755 --- a/OpenRA.Mods.RA/SupportPowers/ParatroopersPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/ParatroopersPower.cs @@ -1,67 +1,67 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Activities; -using OpenRA.Orders; -using OpenRA.Traits; -using OpenRA.FileFormats; -using OpenRA.Mods.RA.Air; - -namespace OpenRA.Mods.RA -{ - public class ParatroopersPowerInfo : SupportPowerInfo - { - [ActorReference] - public string[] DropItems = { }; - [ActorReference] - public string UnitType = "badr"; - [ActorReference] - public string FlareType = "flare"; - - public override object Create(ActorInitializer init) { return new ParatroopersPower(init.self, this); } - } - - public class ParatroopersPower : SupportPower - { - public ParatroopersPower(Actor self, ParatroopersPowerInfo info) : base(self, info) { } - - public override void Activate(Actor self, Order order) - { - var items = (Info as ParatroopersPowerInfo).DropItems; - var startPos = self.World.ChooseRandomEdgeCell(); - - self.World.AddFrameEndTask(w => - { - var info = (Info as ParatroopersPowerInfo); - var flare = info.FlareType != null ? w.CreateActor(info.FlareType, new TypeDictionary - { - new LocationInit( order.TargetLocation ), - new OwnerInit( self.Owner ), - }) : null; - - var a = w.CreateActor(info.UnitType, new TypeDictionary - { - new LocationInit( startPos ), - new OwnerInit( self.Owner ), - new FacingInit( Util.GetFacing(order.TargetLocation - startPos, 0) ), - new AltitudeInit( Rules.Info[info.UnitType].Traits.Get().CruiseAltitude ), - }); - - a.CancelActivity(); - a.QueueActivity(new FlyCircle(order.TargetLocation)); - a.Trait().SetLZ(order.TargetLocation, flare); - - var cargo = a.Trait(); - foreach (var i in items) - cargo.Load(a, self.World.CreateActor(false, i.ToLowerInvariant(), new TypeDictionary { new OwnerInit( a.Owner ) })); - }); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Activities; +using OpenRA.Orders; +using OpenRA.Traits; +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Air; + +namespace OpenRA.Mods.RA +{ + public class ParatroopersPowerInfo : SupportPowerInfo + { + [ActorReference] + public string[] DropItems = { }; + [ActorReference] + public string UnitType = "badr"; + [ActorReference] + public string FlareType = "flare"; + + public override object Create(ActorInitializer init) { return new ParatroopersPower(init.self, this); } + } + + public class ParatroopersPower : SupportPower + { + public ParatroopersPower(Actor self, ParatroopersPowerInfo info) : base(self, info) { } + + public override void Activate(Actor self, Order order) + { + var items = (Info as ParatroopersPowerInfo).DropItems; + var startPos = self.World.ChooseRandomEdgeCell(); + + self.World.AddFrameEndTask(w => + { + var info = (Info as ParatroopersPowerInfo); + var flare = info.FlareType != null ? w.CreateActor(info.FlareType, new TypeDictionary + { + new LocationInit( order.TargetLocation ), + new OwnerInit( self.Owner ), + }) : null; + + var a = w.CreateActor(info.UnitType, new TypeDictionary + { + new LocationInit( startPos ), + new OwnerInit( self.Owner ), + new FacingInit( Util.GetFacing(order.TargetLocation - startPos, 0) ), + new AltitudeInit( Rules.Info[info.UnitType].Traits.Get().CruiseAltitude ), + }); + + a.CancelActivity(); + a.QueueActivity(new FlyCircle(order.TargetLocation)); + a.Trait().SetLZ(order.TargetLocation, flare); + + var cargo = a.Trait(); + foreach (var i in items) + cargo.Load(a, self.World.CreateActor(false, i.ToLowerInvariant(), new TypeDictionary { new OwnerInit( a.Owner ) })); + }); + } + } +} diff --git a/OpenRA.Mods.RA/SupportPowers/SonarPulsePower.cs b/OpenRA.Mods.RA/SupportPowers/SonarPulsePower.cs index e63d75eefc..b69afa71df 100755 --- a/OpenRA.Mods.RA/SupportPowers/SonarPulsePower.cs +++ b/OpenRA.Mods.RA/SupportPowers/SonarPulsePower.cs @@ -1,31 +1,31 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class SonarPulsePowerInfo : SupportPowerInfo - { - public override object Create(ActorInitializer init) { return new SonarPulsePower(init.self, this); } - } - - public class SonarPulsePower : SupportPower - { - public SonarPulsePower(Actor self, SonarPulsePowerInfo info) : base(self, info) { } - public override void Activate(Actor self, Order order) - { - // TODO: Reveal submarines - - // Should this play for all players? - Sound.Play("sonpulse.aud"); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class SonarPulsePowerInfo : SupportPowerInfo + { + public override object Create(ActorInitializer init) { return new SonarPulsePower(init.self, this); } + } + + public class SonarPulsePower : SupportPower + { + public SonarPulsePower(Actor self, SonarPulsePowerInfo info) : base(self, info) { } + public override void Activate(Actor self, Order order) + { + // TODO: Reveal submarines + + // Should this play for all players? + Sound.Play("sonpulse.aud"); + } + } +} diff --git a/OpenRA.Mods.RA/SupportPowers/SpyPlanePower.cs b/OpenRA.Mods.RA/SupportPowers/SpyPlanePower.cs index 272f291b25..9b53f82d02 100755 --- a/OpenRA.Mods.RA/SupportPowers/SpyPlanePower.cs +++ b/OpenRA.Mods.RA/SupportPowers/SpyPlanePower.cs @@ -1,59 +1,59 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Activities; -using OpenRA.Orders; -using OpenRA.Traits; -using OpenRA.Traits.Activities; -using OpenRA.FileFormats; -using OpenRA.Mods.RA.Air; - -namespace OpenRA.Mods.RA -{ - class SpyPlanePowerInfo : SupportPowerInfo - { - public readonly int RevealTime = 6; // seconds - public override object Create(ActorInitializer init) { return new SpyPlanePower(init.self,this); } - } - - class SpyPlanePower : SupportPower - { - public SpyPlanePower(Actor self, SpyPlanePowerInfo info) : base(self, info) { } - - public override void Activate(Actor self, Order order) - { - var enterCell = self.World.ChooseRandomEdgeCell(); - - var plane = self.World.CreateActor("u2", new TypeDictionary - { - new LocationInit( enterCell ), - new OwnerInit( self.Owner ), - new FacingInit( Util.GetFacing(order.TargetLocation - enterCell, 0) ), - new AltitudeInit( Rules.Info["u2"].Traits.Get().CruiseAltitude ), - }); - - plane.CancelActivity(); - plane.QueueActivity(Fly.ToCell(order.TargetLocation)); - plane.QueueActivity(new CallFunc(() => plane.World.AddFrameEndTask( w => - { - var camera = w.CreateActor("camera", new TypeDictionary - { - new LocationInit( order.TargetLocation ), - new OwnerInit( self.Owner ), - }); - - camera.QueueActivity(new Wait(25 * (Info as SpyPlanePowerInfo).RevealTime)); - camera.QueueActivity(new RemoveSelf()); - }))); - plane.QueueActivity(new FlyOffMap { Interruptible = false }); - plane.QueueActivity(new RemoveSelf()); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Activities; +using OpenRA.Orders; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using OpenRA.FileFormats; +using OpenRA.Mods.RA.Air; + +namespace OpenRA.Mods.RA +{ + class SpyPlanePowerInfo : SupportPowerInfo + { + public readonly int RevealTime = 6; // seconds + public override object Create(ActorInitializer init) { return new SpyPlanePower(init.self,this); } + } + + class SpyPlanePower : SupportPower + { + public SpyPlanePower(Actor self, SpyPlanePowerInfo info) : base(self, info) { } + + public override void Activate(Actor self, Order order) + { + var enterCell = self.World.ChooseRandomEdgeCell(); + + var plane = self.World.CreateActor("u2", new TypeDictionary + { + new LocationInit( enterCell ), + new OwnerInit( self.Owner ), + new FacingInit( Util.GetFacing(order.TargetLocation - enterCell, 0) ), + new AltitudeInit( Rules.Info["u2"].Traits.Get().CruiseAltitude ), + }); + + plane.CancelActivity(); + plane.QueueActivity(Fly.ToCell(order.TargetLocation)); + plane.QueueActivity(new CallFunc(() => plane.World.AddFrameEndTask( w => + { + var camera = w.CreateActor("camera", new TypeDictionary + { + new LocationInit( order.TargetLocation ), + new OwnerInit( self.Owner ), + }); + + camera.QueueActivity(new Wait(25 * (Info as SpyPlanePowerInfo).RevealTime)); + camera.QueueActivity(new RemoveSelf()); + }))); + plane.QueueActivity(new FlyOffMap { Interruptible = false }); + plane.QueueActivity(new RemoveSelf()); + } + } +} diff --git a/OpenRA.Mods.RA/SupportPowers/SupportPower.cs b/OpenRA.Mods.RA/SupportPowers/SupportPower.cs index 1f6e796f9b..19698364a9 100755 --- a/OpenRA.Mods.RA/SupportPowers/SupportPower.cs +++ b/OpenRA.Mods.RA/SupportPowers/SupportPower.cs @@ -1,65 +1,65 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public abstract class SupportPowerInfo : ITraitInfo - { - public readonly int ChargeTime = 0; - public readonly string Image = null; - public readonly string Description = ""; - public readonly string LongDesc = ""; - public readonly bool AllowMultiple = false; - public readonly bool OneShot = false; - - public readonly string BeginChargeSound = null; - public readonly string EndChargeSound = null; - public readonly string SelectTargetSound = null; - public readonly string LaunchSound = null; - - public readonly string OrderName; - public abstract object Create(ActorInitializer init); - - public SupportPowerInfo() { OrderName = GetType().Name + "Order"; } - } - - public class SupportPower - { - public readonly Actor self; - public readonly SupportPowerInfo Info; - - public SupportPower(Actor self, SupportPowerInfo info) - { - Info = info; - this.self = self; - } - - public virtual void Charging(Actor self, string key) - { - Sound.PlayToPlayer(self.Owner, Info.BeginChargeSound); - } - - public virtual void Charged(Actor self, string key) - { - Sound.PlayToPlayer(self.Owner, Info.EndChargeSound); - } - - public virtual void Activate(Actor self, Order order) { } - public virtual IOrderGenerator OrderGenerator(string order, SupportPowerManager manager) - { - Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound); - return new SelectGenericPowerTarget(order, manager, "ability", MouseButton.Left); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public abstract class SupportPowerInfo : ITraitInfo + { + public readonly int ChargeTime = 0; + public readonly string Image = null; + public readonly string Description = ""; + public readonly string LongDesc = ""; + public readonly bool AllowMultiple = false; + public readonly bool OneShot = false; + + public readonly string BeginChargeSound = null; + public readonly string EndChargeSound = null; + public readonly string SelectTargetSound = null; + public readonly string LaunchSound = null; + + public readonly string OrderName; + public abstract object Create(ActorInitializer init); + + public SupportPowerInfo() { OrderName = GetType().Name + "Order"; } + } + + public class SupportPower + { + public readonly Actor self; + public readonly SupportPowerInfo Info; + + public SupportPower(Actor self, SupportPowerInfo info) + { + Info = info; + this.self = self; + } + + public virtual void Charging(Actor self, string key) + { + Sound.PlayToPlayer(self.Owner, Info.BeginChargeSound); + } + + public virtual void Charged(Actor self, string key) + { + Sound.PlayToPlayer(self.Owner, Info.EndChargeSound); + } + + public virtual void Activate(Actor self, Order order) { } + public virtual IOrderGenerator OrderGenerator(string order, SupportPowerManager manager) + { + Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound); + return new SelectGenericPowerTarget(order, manager, "ability", MouseButton.Left); + } + } +} diff --git a/OpenRA.Mods.RA/SupportPowers/SupportPowerManager.cs b/OpenRA.Mods.RA/SupportPowers/SupportPowerManager.cs index 8c74b30aa5..21a912215d 100755 --- a/OpenRA.Mods.RA/SupportPowers/SupportPowerManager.cs +++ b/OpenRA.Mods.RA/SupportPowers/SupportPowerManager.cs @@ -1,205 +1,205 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; -using System.Collections.Generic; -using OpenRA.Graphics; - -namespace OpenRA.Mods.RA -{ - public class SupportPowerManagerInfo : ITraitInfo, ITraitPrerequisite - { - public object Create(ActorInitializer init) { return new SupportPowerManager(init); } - } - - public class SupportPowerManager : ITick, IResolveOrder - { - public readonly Actor self; - public Dictionary Powers = new Dictionary(); - - public readonly DeveloperMode devMode; - public SupportPowerManager(ActorInitializer init) - { - self = init.self; - devMode = init.self.Trait(); - - init.world.ActorAdded += ActorAdded; - init.world.ActorRemoved += ActorRemoved; - } - - void ActorAdded(Actor a) - { - if (a.Owner != self.Owner || !a.HasTrait()) - return; - - foreach (var t in a.TraitsImplementing()) - { - var key = (t.Info.AllowMultiple) ? t.Info.OrderName+"_"+a.ActorID : t.Info.OrderName; - - if (Powers.ContainsKey(key)) - { - Powers[key].Instances.Add(t); - } - else - { - var si = new SupportPowerInstance(key, this) - { - Instances = new List() { t }, - RemainingTime = t.Info.ChargeTime * 25, - TotalTime = t.Info.ChargeTime * 25, - }; - - Powers.Add(key, si); - } - } - } - - void ActorRemoved(Actor a) - { - if (a.Owner != self.Owner || !a.HasTrait()) - return; - - foreach (var t in a.TraitsImplementing()) - { - var key = (t.Info.AllowMultiple) ? t.Info.OrderName+"_"+a.ActorID : t.Info.OrderName; - Powers[key].Instances.Remove(t); - if (Powers[key].Instances.Count == 0 && !Powers[key].Disabled) - Powers.Remove(key); - } - } - - public void Tick(Actor self) - { - foreach(var power in Powers.Values) - power.Tick(); - } - - public void ResolveOrder(Actor self, Order order) - { - // order.OrderString is the key of the support power - if (Powers.ContainsKey(order.OrderString)) - Powers[order.OrderString].Activate(order); - } - - public void Target(string key) - { - if (Powers.ContainsKey(key)) - Powers[key].Target(); - } - - public class SupportPowerInstance - { - readonly SupportPowerManager Manager; - readonly string Key; - - public List Instances; - public int RemainingTime; - public int TotalTime; - public bool Active { get; private set; } - public bool Disabled { get; private set; } - - public SupportPowerInfo Info { get { return Instances.First().Info; } } - public bool Ready { get { return Active && RemainingTime == 0; } } - - public SupportPowerInstance(string key, SupportPowerManager manager) - { - Manager = manager; - Key = key; - } - - bool notifiedCharging; - bool notifiedReady; - public void Tick() - { - Active = !Disabled && Instances.Any(i => !i.self.TraitsImplementing().Any(d => d.Disabled)); - - if (Active) - { - var power = Instances.First(); - if (Manager.devMode.FastCharge && RemainingTime > 25) - RemainingTime = 25; - - if (RemainingTime > 0) --RemainingTime; - if (!notifiedCharging) - { - power.Charging(power.self, Key); - notifiedCharging = true; - } - - if (RemainingTime == 0 - && !notifiedReady) - { - power.Charged(power.self, Key); - notifiedReady = true; - } - } - } - - public void Target() - { - if (!Ready) - return; - - Manager.self.World.OrderGenerator = Instances.First().OrderGenerator(Key, Manager); - } - - public void Activate(Order order) - { - if (!Ready) - return; - - var power = Instances.First(); - // Note: order.Subject is the *player* actor - power.Activate(power.self, order); - RemainingTime = TotalTime; - notifiedCharging = notifiedReady = false; - - if (Info.OneShot) - Disabled = true; - } - } - } - - public class SelectGenericPowerTarget : IOrderGenerator - { - readonly SupportPowerManager manager; - readonly string order; - readonly string cursor; - readonly MouseButton expectedButton; - - public SelectGenericPowerTarget(string order, SupportPowerManager manager, string cursor, MouseButton button) - { - this.manager = manager; - this.order = order; - this.cursor = cursor; - expectedButton = button; - } - - public IEnumerable Order(World world, int2 xy, MouseInput mi) - { - world.CancelInputMode(); - if (mi.Button == expectedButton && world.Map.IsInMap(xy)) - yield return new Order(order, manager.self, false) { TargetLocation = xy }; - } - - public virtual void Tick(World world) - { - // Cancel the OG if we can't use the power - if (!manager.Powers.ContainsKey(order)) - world.CancelInputMode(); - } - - public void RenderBeforeWorld(WorldRenderer wr, World world) { } - public void RenderAfterWorld(WorldRenderer wr, World world) { } - public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; +using System.Collections.Generic; +using OpenRA.Graphics; + +namespace OpenRA.Mods.RA +{ + public class SupportPowerManagerInfo : ITraitInfo, ITraitPrerequisite + { + public object Create(ActorInitializer init) { return new SupportPowerManager(init); } + } + + public class SupportPowerManager : ITick, IResolveOrder + { + public readonly Actor self; + public Dictionary Powers = new Dictionary(); + + public readonly DeveloperMode devMode; + public SupportPowerManager(ActorInitializer init) + { + self = init.self; + devMode = init.self.Trait(); + + init.world.ActorAdded += ActorAdded; + init.world.ActorRemoved += ActorRemoved; + } + + void ActorAdded(Actor a) + { + if (a.Owner != self.Owner || !a.HasTrait()) + return; + + foreach (var t in a.TraitsImplementing()) + { + var key = (t.Info.AllowMultiple) ? t.Info.OrderName+"_"+a.ActorID : t.Info.OrderName; + + if (Powers.ContainsKey(key)) + { + Powers[key].Instances.Add(t); + } + else + { + var si = new SupportPowerInstance(key, this) + { + Instances = new List() { t }, + RemainingTime = t.Info.ChargeTime * 25, + TotalTime = t.Info.ChargeTime * 25, + }; + + Powers.Add(key, si); + } + } + } + + void ActorRemoved(Actor a) + { + if (a.Owner != self.Owner || !a.HasTrait()) + return; + + foreach (var t in a.TraitsImplementing()) + { + var key = (t.Info.AllowMultiple) ? t.Info.OrderName+"_"+a.ActorID : t.Info.OrderName; + Powers[key].Instances.Remove(t); + if (Powers[key].Instances.Count == 0 && !Powers[key].Disabled) + Powers.Remove(key); + } + } + + public void Tick(Actor self) + { + foreach(var power in Powers.Values) + power.Tick(); + } + + public void ResolveOrder(Actor self, Order order) + { + // order.OrderString is the key of the support power + if (Powers.ContainsKey(order.OrderString)) + Powers[order.OrderString].Activate(order); + } + + public void Target(string key) + { + if (Powers.ContainsKey(key)) + Powers[key].Target(); + } + + public class SupportPowerInstance + { + readonly SupportPowerManager Manager; + readonly string Key; + + public List Instances; + public int RemainingTime; + public int TotalTime; + public bool Active { get; private set; } + public bool Disabled { get; private set; } + + public SupportPowerInfo Info { get { return Instances.First().Info; } } + public bool Ready { get { return Active && RemainingTime == 0; } } + + public SupportPowerInstance(string key, SupportPowerManager manager) + { + Manager = manager; + Key = key; + } + + bool notifiedCharging; + bool notifiedReady; + public void Tick() + { + Active = !Disabled && Instances.Any(i => !i.self.TraitsImplementing().Any(d => d.Disabled)); + + if (Active) + { + var power = Instances.First(); + if (Manager.devMode.FastCharge && RemainingTime > 25) + RemainingTime = 25; + + if (RemainingTime > 0) --RemainingTime; + if (!notifiedCharging) + { + power.Charging(power.self, Key); + notifiedCharging = true; + } + + if (RemainingTime == 0 + && !notifiedReady) + { + power.Charged(power.self, Key); + notifiedReady = true; + } + } + } + + public void Target() + { + if (!Ready) + return; + + Manager.self.World.OrderGenerator = Instances.First().OrderGenerator(Key, Manager); + } + + public void Activate(Order order) + { + if (!Ready) + return; + + var power = Instances.First(); + // Note: order.Subject is the *player* actor + power.Activate(power.self, order); + RemainingTime = TotalTime; + notifiedCharging = notifiedReady = false; + + if (Info.OneShot) + Disabled = true; + } + } + } + + public class SelectGenericPowerTarget : IOrderGenerator + { + readonly SupportPowerManager manager; + readonly string order; + readonly string cursor; + readonly MouseButton expectedButton; + + public SelectGenericPowerTarget(string order, SupportPowerManager manager, string cursor, MouseButton button) + { + this.manager = manager; + this.order = order; + this.cursor = cursor; + expectedButton = button; + } + + public IEnumerable Order(World world, int2 xy, MouseInput mi) + { + world.CancelInputMode(); + if (mi.Button == expectedButton && world.Map.IsInMap(xy)) + yield return new Order(order, manager.self, false) { TargetLocation = xy }; + } + + public virtual void Tick(World world) + { + // Cancel the OG if we can't use the power + if (!manager.Powers.ContainsKey(order)) + world.CancelInputMode(); + } + + public void RenderBeforeWorld(WorldRenderer wr, World world) { } + public void RenderAfterWorld(WorldRenderer wr, World world) { } + public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; } + } +} diff --git a/OpenRA.Mods.RA/TakeCover.cs b/OpenRA.Mods.RA/TakeCover.cs index 44e4e78725..d38905eabe 100644 --- a/OpenRA.Mods.RA/TakeCover.cs +++ b/OpenRA.Mods.RA/TakeCover.cs @@ -1,82 +1,82 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.GameRules; -using OpenRA.Traits; -using OpenRA.Mods.RA.Render; - -namespace OpenRA.Mods.RA -{ - class TakeCoverInfo : TraitInfo, ITraitPrerequisite { } - - // infantry prone behavior - class TakeCover : ITick, INotifyDamage, IDamageModifier, ISpeedModifier, ISync - { - const int defaultProneTime = 100; /* ticks, =4s */ - const float proneDamage = .5f; - const decimal proneSpeed = .5m; - - [Sync] - int remainingProneTime = 0; - - public bool IsProne { get { return remainingProneTime > 0; } } - - public void Damaged(Actor self, AttackInfo e) - { - if (e.Damage > 0) /* Don't go prone when healed */ - { - if (e.Warhead == null || !e.Warhead.PreventProne) - remainingProneTime = defaultProneTime; - } - } - - public void Tick(Actor self) - { - if (!IsProne) - return; - - remainingProneTime--; - - var ri = self.Trait(); - - // Mobile.IsMoving isn't set to true until after the first move tick - // so we need a hack here to prevent a single frame of stand state - - if (IsProne && (ri.State == RenderInfantry.AnimationState.Idle || - ri.State == RenderInfantry.AnimationState.Waiting || - ri.anim.CurrentSequence.Name == "stand")) - ri.anim.PlayFetchIndex("crawl", () => 0); - else if (!IsProne && (ri.State == RenderInfantry.AnimationState.Idle || - ri.State == RenderInfantry.AnimationState.Waiting || - ri.anim.CurrentSequence.Name == "stand")) - ri.anim.Play("stand"); - - if (ri.anim.CurrentSequence.Name == "run" && IsProne) - ri.anim.ReplaceAnim("crawl"); - else if (ri.anim.CurrentSequence.Name == "crawl" && !IsProne) - ri.anim.ReplaceAnim("run"); - - if (ri.anim.CurrentSequence.Name == "shoot" && IsProne) - ri.anim.ReplaceAnim("prone-shoot"); - else if (ri.anim.CurrentSequence.Name == "prone-shoot" && !IsProne) - ri.anim.ReplaceAnim("shoot"); - } - - public float GetDamageModifier(Actor attacker, WarheadInfo warhead ) - { - return IsProne ? proneDamage : 1f; - } - - public decimal GetSpeedModifier() - { - return IsProne ? proneSpeed : 1m; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.GameRules; +using OpenRA.Traits; +using OpenRA.Mods.RA.Render; + +namespace OpenRA.Mods.RA +{ + class TakeCoverInfo : TraitInfo, ITraitPrerequisite { } + + // infantry prone behavior + class TakeCover : ITick, INotifyDamage, IDamageModifier, ISpeedModifier, ISync + { + const int defaultProneTime = 100; /* ticks, =4s */ + const float proneDamage = .5f; + const decimal proneSpeed = .5m; + + [Sync] + int remainingProneTime = 0; + + public bool IsProne { get { return remainingProneTime > 0; } } + + public void Damaged(Actor self, AttackInfo e) + { + if (e.Damage > 0) /* Don't go prone when healed */ + { + if (e.Warhead == null || !e.Warhead.PreventProne) + remainingProneTime = defaultProneTime; + } + } + + public void Tick(Actor self) + { + if (!IsProne) + return; + + remainingProneTime--; + + var ri = self.Trait(); + + // Mobile.IsMoving isn't set to true until after the first move tick + // so we need a hack here to prevent a single frame of stand state + + if (IsProne && (ri.State == RenderInfantry.AnimationState.Idle || + ri.State == RenderInfantry.AnimationState.Waiting || + ri.anim.CurrentSequence.Name == "stand")) + ri.anim.PlayFetchIndex("crawl", () => 0); + else if (!IsProne && (ri.State == RenderInfantry.AnimationState.Idle || + ri.State == RenderInfantry.AnimationState.Waiting || + ri.anim.CurrentSequence.Name == "stand")) + ri.anim.Play("stand"); + + if (ri.anim.CurrentSequence.Name == "run" && IsProne) + ri.anim.ReplaceAnim("crawl"); + else if (ri.anim.CurrentSequence.Name == "crawl" && !IsProne) + ri.anim.ReplaceAnim("run"); + + if (ri.anim.CurrentSequence.Name == "shoot" && IsProne) + ri.anim.ReplaceAnim("prone-shoot"); + else if (ri.anim.CurrentSequence.Name == "prone-shoot" && !IsProne) + ri.anim.ReplaceAnim("shoot"); + } + + public float GetDamageModifier(Actor attacker, WarheadInfo warhead ) + { + return IsProne ? proneDamage : 1f; + } + + public decimal GetSpeedModifier() + { + return IsProne ? proneSpeed : 1m; + } + } +} diff --git a/OpenRA.Mods.RA/TargetableBuilding.cs b/OpenRA.Mods.RA/TargetableBuilding.cs index 76ca9d6390..82577f400c 100755 --- a/OpenRA.Mods.RA/TargetableBuilding.cs +++ b/OpenRA.Mods.RA/TargetableBuilding.cs @@ -1,39 +1,39 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Traits; -using System.Linq; - -namespace OpenRA.Mods.RA -{ - class TargetableBuildingInfo : ITraitInfo, ITraitPrerequisite - { - public readonly string[] TargetTypes = { }; - public object Create( ActorInitializer init ) { return new TargetableBuilding( this ); } - } - - class TargetableBuilding : ITargetable - { - readonly TargetableBuildingInfo info; - public TargetableBuilding( TargetableBuildingInfo info ) - { - this.info = info; - } - - public string[] TargetTypes { get { return info.TargetTypes; } } - public bool TargetableBy(Actor self, Actor byActor) { return true; } - public IEnumerable TargetableCells( Actor self ) - { - return self.Trait().OccupiedCells().Select(c => c.First); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Traits; +using System.Linq; + +namespace OpenRA.Mods.RA +{ + class TargetableBuildingInfo : ITraitInfo, ITraitPrerequisite + { + public readonly string[] TargetTypes = { }; + public object Create( ActorInitializer init ) { return new TargetableBuilding( this ); } + } + + class TargetableBuilding : ITargetable + { + readonly TargetableBuildingInfo info; + public TargetableBuilding( TargetableBuildingInfo info ) + { + this.info = info; + } + + public string[] TargetTypes { get { return info.TargetTypes; } } + public bool TargetableBy(Actor self, Actor byActor) { return true; } + public IEnumerable TargetableCells( Actor self ) + { + return self.Trait().OccupiedCells().Select(c => c.First); + } + } +} diff --git a/OpenRA.Mods.RA/TargetableSubmarine.cs b/OpenRA.Mods.RA/TargetableSubmarine.cs index 80491ff7d3..05818e74e1 100644 --- a/OpenRA.Mods.RA/TargetableSubmarine.cs +++ b/OpenRA.Mods.RA/TargetableSubmarine.cs @@ -1,14 +1,14 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion +#endregion -using System.Linq; +using System.Linq; using OpenRA.Traits; namespace OpenRA.Mods.RA diff --git a/OpenRA.Mods.RA/TargetableUnit.cs b/OpenRA.Mods.RA/TargetableUnit.cs index 708ed4253e..38519eb7ce 100755 --- a/OpenRA.Mods.RA/TargetableUnit.cs +++ b/OpenRA.Mods.RA/TargetableUnit.cs @@ -1,61 +1,61 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class TargetableUnitInfo : ITraitInfo - { - public readonly string[] TargetTypes = { }; - public virtual object Create( ActorInitializer init ) { return new TargetableUnit( init.self, this ); } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class TargetableUnitInfo : ITraitInfo + { + public readonly string[] TargetTypes = { }; + public virtual object Create( ActorInitializer init ) { return new TargetableUnit( init.self, this ); } } - public class TargetableUnit : ITargetable - where Info : TargetableUnitInfo - { - protected readonly Info info; - protected Cloak Cloak; - - public TargetableUnit( Actor self, Info info ) - { - this.info = info; - RecievedCloak(self); - } - - // Arbitrary units can recieve cloak via a crate during gameplay - public void RecievedCloak(Actor self) - { - Cloak = self.TraitOrDefault(); - } - - public virtual bool TargetableBy(Actor self, Actor byActor) - { - if (Cloak == null) - return true; - - if (!Cloak.Cloaked || self.Owner == byActor.Owner || self.Owner.Stances[byActor.Owner] == Stance.Ally) - return true; - - return self.World.Queries.WithTrait().Any(a => (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get().Range); - } - - public virtual string[] TargetTypes { get { return info.TargetTypes; } } - - public virtual IEnumerable TargetableCells( Actor self ) - { - yield return Util.CellContaining( self.CenterLocation ); - } - } -} + public class TargetableUnit : ITargetable + where Info : TargetableUnitInfo + { + protected readonly Info info; + protected Cloak Cloak; + + public TargetableUnit( Actor self, Info info ) + { + this.info = info; + RecievedCloak(self); + } + + // Arbitrary units can recieve cloak via a crate during gameplay + public void RecievedCloak(Actor self) + { + Cloak = self.TraitOrDefault(); + } + + public virtual bool TargetableBy(Actor self, Actor byActor) + { + if (Cloak == null) + return true; + + if (!Cloak.Cloaked || self.Owner == byActor.Owner || self.Owner.Stances[byActor.Owner] == Stance.Ally) + return true; + + return self.World.Queries.WithTrait().Any(a => (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get().Range); + } + + public virtual string[] TargetTypes { get { return info.TargetTypes; } } + + public virtual IEnumerable TargetableCells( Actor self ) + { + yield return Util.CellContaining( self.CenterLocation ); + } + } +} diff --git a/OpenRA.Mods.RA/TeslaInstantKills.cs b/OpenRA.Mods.RA/TeslaInstantKills.cs index 457c9ce57a..97d7c73918 100755 --- a/OpenRA.Mods.RA/TeslaInstantKills.cs +++ b/OpenRA.Mods.RA/TeslaInstantKills.cs @@ -1,27 +1,27 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.GameRules; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class TeslaInstantKillsInfo : TraitInfo { } - - class TeslaInstantKills : IDamageModifier - { - public float GetDamageModifier(Actor attacker, WarheadInfo warhead ) - { - if( warhead != null && warhead.InfDeath == 5 ) - return 1000f; - return 1f; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class TeslaInstantKillsInfo : TraitInfo { } + + class TeslaInstantKills : IDamageModifier + { + public float GetDamageModifier(Actor attacker, WarheadInfo warhead ) + { + if( warhead != null && warhead.InfDeath == 5 ) + return 1000f; + return 1f; + } + } +} diff --git a/OpenRA.Mods.RA/ThrowsParticles.cs b/OpenRA.Mods.RA/ThrowsParticles.cs index 2e7827c405..5ccb2f80ac 100644 --- a/OpenRA.Mods.RA/ThrowsParticles.cs +++ b/OpenRA.Mods.RA/ThrowsParticles.cs @@ -1,85 +1,85 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Graphics; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class ThrowsParticleInfo : ITraitInfo - { - public readonly string Anim = null; - public readonly int[] Offset = new[] { 0, 0, 0, 0 }; - public readonly int[] Spread = new[] { 0, 0 }; - public readonly float Speed = 20; - public readonly string AnimKey = null; - public readonly bool UseTurretFacing = true; - public readonly float ROT = 15; - - public object Create(ActorInitializer init) { return new ThrowsParticle(this); } - } - - class ThrowsParticle : ITick - { - ThrowsParticleInfo info; - float2 pos; - float alt; - - float2 v; - float va; - float facing; - float dfacing; - - const float gravity = 1.3f; - - public ThrowsParticle(ThrowsParticleInfo info) { this.info = info; } - public float? InitialFacing = null; - - public void Tick(Actor self) - { - if (info != null) - { - alt = 0; - var ifacing = self.Trait(); - pos = Combat.GetTurretPosition(self, ifacing, new Turret(info.Offset)); - var ru = self.Trait(); - - v = Game.CosmeticRandom.Gauss2D(1) * info.Spread.RelOffset(); - dfacing = Game.CosmeticRandom.Gauss1D(2) * info.ROT; - va = info.Speed; - - if (!info.UseTurretFacing) InitialFacing = null; - facing = InitialFacing ?? ifacing.Facing; - - var anim = new Animation(ru.GetImage(self), () => (int)facing); - anim.PlayRepeating(info.Anim); - - ru.anims.Add(info.AnimKey, new RenderSimple.AnimationWithOffset( - anim, () => pos - new float2(0, alt), null)); - - info = null; - } - - va -= gravity; - alt += va; - - if (alt < 0) alt = 0; - else - { - pos += v; - v = .9f * v; - - facing += dfacing; - dfacing *= .9f; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Graphics; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class ThrowsParticleInfo : ITraitInfo + { + public readonly string Anim = null; + public readonly int[] Offset = new[] { 0, 0, 0, 0 }; + public readonly int[] Spread = new[] { 0, 0 }; + public readonly float Speed = 20; + public readonly string AnimKey = null; + public readonly bool UseTurretFacing = true; + public readonly float ROT = 15; + + public object Create(ActorInitializer init) { return new ThrowsParticle(this); } + } + + class ThrowsParticle : ITick + { + ThrowsParticleInfo info; + float2 pos; + float alt; + + float2 v; + float va; + float facing; + float dfacing; + + const float gravity = 1.3f; + + public ThrowsParticle(ThrowsParticleInfo info) { this.info = info; } + public float? InitialFacing = null; + + public void Tick(Actor self) + { + if (info != null) + { + alt = 0; + var ifacing = self.Trait(); + pos = Combat.GetTurretPosition(self, ifacing, new Turret(info.Offset)); + var ru = self.Trait(); + + v = Game.CosmeticRandom.Gauss2D(1) * info.Spread.RelOffset(); + dfacing = Game.CosmeticRandom.Gauss1D(2) * info.ROT; + va = info.Speed; + + if (!info.UseTurretFacing) InitialFacing = null; + facing = InitialFacing ?? ifacing.Facing; + + var anim = new Animation(ru.GetImage(self), () => (int)facing); + anim.PlayRepeating(info.Anim); + + ru.anims.Add(info.AnimKey, new RenderSimple.AnimationWithOffset( + anim, () => pos - new float2(0, alt), null)); + + info = null; + } + + va -= gravity; + alt += va; + + if (alt < 0) alt = 0; + else + { + pos += v; + v = .9f * v; + + facing += dfacing; + dfacing *= .9f; + } + } + } +} diff --git a/OpenRA.Mods.RA/TraitsInterfaces.cs b/OpenRA.Mods.RA/TraitsInterfaces.cs index fb7a02029f..6901fdec1a 100755 --- a/OpenRA.Mods.RA/TraitsInterfaces.cs +++ b/OpenRA.Mods.RA/TraitsInterfaces.cs @@ -1,27 +1,27 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Mods.RA.Activities; - -namespace OpenRA.Mods.RA -{ - public interface IAcceptOre - { - void OnDock(Actor harv, DeliverResources dockOrder); - void GiveOre(int amount); - bool CanGiveOre(int amount); - int2 DeliverOffset { get; } - } - - public interface IAcceptOreDockAction - { - void OnDock(Actor self, Actor harv, DeliverResources dockOrder); - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Mods.RA.Activities; + +namespace OpenRA.Mods.RA +{ + public interface IAcceptOre + { + void OnDock(Actor harv, DeliverResources dockOrder); + void GiveOre(int amount); + bool CanGiveOre(int amount); + int2 DeliverOffset { get; } + } + + public interface IAcceptOreDockAction + { + void OnDock(Actor self, Actor harv, DeliverResources dockOrder); + } +} diff --git a/OpenRA.Mods.RA/Transforms.cs b/OpenRA.Mods.RA/Transforms.cs index fd4cc82830..930c83ba8a 100644 --- a/OpenRA.Mods.RA/Transforms.cs +++ b/OpenRA.Mods.RA/Transforms.cs @@ -1,86 +1,86 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Mods.RA.Activities; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class TransformsInfo : ITraitInfo - { - [ActorReference] - public readonly string IntoActor = null; - public readonly int2 Offset = int2.Zero; - public readonly int Facing = 96; - public readonly string[] TransformSounds = {}; - public readonly string[] NoTransformSounds = {}; - - public virtual object Create(ActorInitializer init) { return new Transforms(init.self, this); } - } - - class Transforms : IIssueOrder, IResolveOrder, IOrderVoice - { - Actor self; - TransformsInfo Info; - BuildingInfo bi; - - public Transforms(Actor self, TransformsInfo info) - { - this.self = self; - Info = info; - bi = Rules.Info[info.IntoActor].Traits.GetOrDefault(); - } - - public string VoicePhraseForOrder(Actor self, Order order) - { - return (order.OrderString == "DeployTransform") ? "Move" : null; - } - - bool CanDeploy() - { - return (bi == null || self.World.CanPlaceBuilding(Info.IntoActor, bi, self.Location + Info.Offset, self)); - } - - public IEnumerable Orders - { - get { yield return new DeployOrderTargeter( "DeployTransform", 5, () => CanDeploy() ); } - } - - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) - { - if( order.OrderID == "DeployTransform" ) - return new Order( order.OrderID, self, queued ); - - return null; - } - - public void ResolveOrder( Actor self, Order order ) - { - if (order.OrderString == "DeployTransform") - { - if (!CanDeploy()) - { - foreach (var s in Info.NoTransformSounds) - Sound.PlayToPlayer(self.Owner, s); - return; - } - self.CancelActivity(); - - if (self.HasTrait()) - self.QueueActivity(new Turn(Info.Facing)); - - self.QueueActivity(new Transform(self, Info.IntoActor, Info.Offset, Info.Facing, Info.TransformSounds)); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class TransformsInfo : ITraitInfo + { + [ActorReference] + public readonly string IntoActor = null; + public readonly int2 Offset = int2.Zero; + public readonly int Facing = 96; + public readonly string[] TransformSounds = {}; + public readonly string[] NoTransformSounds = {}; + + public virtual object Create(ActorInitializer init) { return new Transforms(init.self, this); } + } + + class Transforms : IIssueOrder, IResolveOrder, IOrderVoice + { + Actor self; + TransformsInfo Info; + BuildingInfo bi; + + public Transforms(Actor self, TransformsInfo info) + { + this.self = self; + Info = info; + bi = Rules.Info[info.IntoActor].Traits.GetOrDefault(); + } + + public string VoicePhraseForOrder(Actor self, Order order) + { + return (order.OrderString == "DeployTransform") ? "Move" : null; + } + + bool CanDeploy() + { + return (bi == null || self.World.CanPlaceBuilding(Info.IntoActor, bi, self.Location + Info.Offset, self)); + } + + public IEnumerable Orders + { + get { yield return new DeployOrderTargeter( "DeployTransform", 5, () => CanDeploy() ); } + } + + public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + { + if( order.OrderID == "DeployTransform" ) + return new Order( order.OrderID, self, queued ); + + return null; + } + + public void ResolveOrder( Actor self, Order order ) + { + if (order.OrderString == "DeployTransform") + { + if (!CanDeploy()) + { + foreach (var s in Info.NoTransformSounds) + Sound.PlayToPlayer(self.Owner, s); + return; + } + self.CancelActivity(); + + if (self.HasTrait()) + self.QueueActivity(new Turn(Info.Facing)); + + self.QueueActivity(new Transform(self, Info.IntoActor, Info.Offset, Info.Facing, Info.TransformSounds)); + } + } + } +} diff --git a/OpenRA.Mods.RA/Turreted.cs b/OpenRA.Mods.RA/Turreted.cs index 4d844a890e..42f8d2f5b8 100755 --- a/OpenRA.Mods.RA/Turreted.cs +++ b/OpenRA.Mods.RA/Turreted.cs @@ -1,45 +1,45 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class TurretedInfo : ITraitInfo - { - public readonly int ROT = 255; - public readonly int InitialFacing = 128; - - public object Create(ActorInitializer init) { return new Turreted(init, this); } - } - - public class Turreted : ITick, ISync - { - [Sync] - public int turretFacing = 0; - public int? desiredFacing; - TurretedInfo info; - IFacing facing; - - public Turreted(ActorInitializer init, TurretedInfo info) - { - this.info = info; - turretFacing = info.InitialFacing; - turretFacing = init.Contains() ? init.Get() : info.InitialFacing; - facing = init.self.TraitOrDefault(); - } - - public void Tick( Actor self ) - { - var df = desiredFacing ?? ( facing != null ? facing.Facing : turretFacing ); - turretFacing = Util.TickFacing(turretFacing, df, info.ROT); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class TurretedInfo : ITraitInfo + { + public readonly int ROT = 255; + public readonly int InitialFacing = 128; + + public object Create(ActorInitializer init) { return new Turreted(init, this); } + } + + public class Turreted : ITick, ISync + { + [Sync] + public int turretFacing = 0; + public int? desiredFacing; + TurretedInfo info; + IFacing facing; + + public Turreted(ActorInitializer init, TurretedInfo info) + { + this.info = info; + turretFacing = info.InitialFacing; + turretFacing = init.Contains() ? init.Get() : info.InitialFacing; + facing = init.self.TraitOrDefault(); + } + + public void Tick( Actor self ) + { + var df = desiredFacing ?? ( facing != null ? facing.Facing : turretFacing ); + turretFacing = Util.TickFacing(turretFacing, df, info.ROT); + } + } +} diff --git a/OpenRA.Mods.RA/Valued.cs b/OpenRA.Mods.RA/Valued.cs index 54fdd77381..1e7c470e57 100755 --- a/OpenRA.Mods.RA/Valued.cs +++ b/OpenRA.Mods.RA/Valued.cs @@ -1,30 +1,30 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ +#endregion + +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ public class ValuedInfo : TraitInfo { public readonly int Cost = 0; } - - public class TooltipInfo : TraitInfo - { - public readonly string Description = ""; - public readonly string Name = ""; - public readonly string Icon = null; - public readonly string[] AlternateName = { }; - } + + public class TooltipInfo : TraitInfo + { + public readonly string Description = ""; + public readonly string Name = ""; + public readonly string Icon = null; + public readonly string[] AlternateName = { }; + } public class Valued { } public class Tooltip { } -} +} diff --git a/OpenRA.Mods.RA/WaterPaletteRotation.cs b/OpenRA.Mods.RA/WaterPaletteRotation.cs index 7ac3796ed7..17c64bc259 100644 --- a/OpenRA.Mods.RA/WaterPaletteRotation.cs +++ b/OpenRA.Mods.RA/WaterPaletteRotation.cs @@ -1,42 +1,42 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using OpenRA.Traits; -using System.Collections.Generic; -using OpenRA.FileFormats; - -namespace OpenRA.Mods.RA -{ - class WaterPaletteRotationInfo : TraitInfo {} - class WaterPaletteRotation : ITick, IPaletteModifier - { - float t = 0; - public void Tick(Actor self) - { - t += .25f; - } - - public void AdjustPalette(Dictionary palettes) - { - var excludePalettes = new List(){"cursor", "chrome", "colorpicker"}; - foreach (var pal in palettes) - { - if (excludePalettes.Contains(pal.Key)) - continue; - - var copy = (uint[])pal.Value.Values.Clone(); - var rotate = (int)t % 7; - for (int i = 0; i < 7; i++) - pal.Value.SetColor(0x60 + (rotate + i) % 7, copy[0x60 + i]); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using OpenRA.Traits; +using System.Collections.Generic; +using OpenRA.FileFormats; + +namespace OpenRA.Mods.RA +{ + class WaterPaletteRotationInfo : TraitInfo {} + class WaterPaletteRotation : ITick, IPaletteModifier + { + float t = 0; + public void Tick(Actor self) + { + t += .25f; + } + + public void AdjustPalette(Dictionary palettes) + { + var excludePalettes = new List(){"cursor", "chrome", "colorpicker"}; + foreach (var pal in palettes) + { + if (excludePalettes.Contains(pal.Key)) + continue; + + var copy = (uint[])pal.Value.Values.Clone(); + var rotate = (int)t % 7; + for (int i = 0; i < 7; i++) + pal.Value.SetColor(0x60 + (rotate + i) % 7, copy[0x60 + i]); + } + } + } +} diff --git a/OpenRA.Mods.RA/Weapon.cs b/OpenRA.Mods.RA/Weapon.cs index 67d418d509..b8b21815d1 100644 --- a/OpenRA.Mods.RA/Weapon.cs +++ b/OpenRA.Mods.RA/Weapon.cs @@ -1,157 +1,157 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.GameRules; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class Barrel - { - public int2 Position; // position in turret space - public int Facing; // deviation from turret facing - } - - public class Turret - { - public float Recoil = 0.0f; // remaining recoil fraction - public int2 UnitSpacePosition; // where, in the unit's local space. - public int2 ScreenSpacePosition; // screen-space hack to make things line up good. - - public Turret(int[] offset) - { - ScreenSpacePosition = offset.AbsOffset().ToInt2(); - UnitSpacePosition = offset.RelOffset().ToInt2(); - } - } - - public class Weapon - { - public WeaponInfo Info; - public int FireDelay = 0; // time (in frames) until the weapon can fire again - public int Burst = 0; // burst counter - - public Barrel[] Barrels; // where projectiles are spawned, in local turret space. - public Turret Turret; // where this weapon is mounted -- possibly shared - - public Weapon(string weaponName, Turret turret, int[] localOffset) - { - Info = Rules.Weapons[weaponName.ToLowerInvariant()]; - Burst = Info.Burst; - Turret = turret; - - var barrels = new List(); - for (var i = 0; i < localOffset.Length / 3; i++) - barrels.Add(new Barrel - { - Position = new int2(localOffset[3 * i], localOffset[3 * i + 1]), - Facing = localOffset[3 * i + 2] - }); - - // if no barrels specified, the default is "turret position; turret facing". - if (barrels.Count == 0) - barrels.Add(new Barrel { Position = int2.Zero, Facing = 0 }); - - Barrels = barrels.ToArray(); - } - - public bool IsReloading { get { return FireDelay > 0; } } - - public void Tick() - { - if (FireDelay > 0) --FireDelay; - Turret.Recoil = Math.Max(0f, Turret.Recoil - .2f); - } - - public bool IsValidAgainst(World world, Target target) - { - if( target.IsActor ) - return Combat.WeaponValidForTarget( Info, target.Actor ); - else - return Combat.WeaponValidForTarget( Info, world, Util.CellContaining( target.CenterLocation ) ); - } - - public void FiredShot() - { - Turret.Recoil = 1; - - if (--Burst > 0) - FireDelay = Info.BurstDelay; - else - { - FireDelay = Info.ROF; - Burst = Info.Burst; - } - } - - public void CheckFire(Actor self, AttackBase attack, IMove move, IFacing facing, Target target) - { - if (FireDelay > 0) return; - - var limitedAmmo = self.TraitOrDefault(); - if (limitedAmmo != null && !limitedAmmo.HasAmmo()) - return; - - if( !Combat.IsInRange( self.CenterLocation, Info.Range, target ) ) - return; - if( Combat.IsInRange( self.CenterLocation, Info.MinRange, target ) ) - return; - - if (!IsValidAgainst(self.World, target)) return; - - var barrel = Barrels[Burst % Barrels.Length]; - var destMove = target.IsActor ? target.Actor.TraitOrDefault() : null; - - var args = new ProjectileArgs - { - weapon = Info, - - firedBy = self, - target = target, - - src = (self.CenterLocation - + Combat.GetTurretPosition(self, facing, Turret) - + Combat.GetBarrelPosition(self, facing, Turret, barrel)).ToInt2(), - srcAltitude = move != null ? move.Altitude : 0, - dest = target.CenterLocation, - destAltitude = destMove != null ? destMove.Altitude : 0, - - facing = barrel.Facing + - (self.HasTrait() ? self.Trait().turretFacing : - facing != null ? facing.Facing : Util.GetFacing(target.CenterLocation - self.CenterLocation, 0)), - - firepowerModifier = self.TraitsImplementing() - .Select(a => a.GetFirepowerModifier()) - .Product() - }; - - attack.ScheduleDelayedAction( attack.FireDelay( self, target, self.Info.Traits.Get() ), () => - { - if (args.weapon.Projectile != null) - { - var projectile = args.weapon.Projectile.Create(args); - if (projectile != null) - self.World.Add(projectile); - - if (!string.IsNullOrEmpty(args.weapon.Report)) - Sound.Play(args.weapon.Report + ".aud", self.CenterLocation); - } - }); - - foreach (var na in self.TraitsImplementing()) - na.Attacking(self, target); - - FiredShot(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class Barrel + { + public int2 Position; // position in turret space + public int Facing; // deviation from turret facing + } + + public class Turret + { + public float Recoil = 0.0f; // remaining recoil fraction + public int2 UnitSpacePosition; // where, in the unit's local space. + public int2 ScreenSpacePosition; // screen-space hack to make things line up good. + + public Turret(int[] offset) + { + ScreenSpacePosition = offset.AbsOffset().ToInt2(); + UnitSpacePosition = offset.RelOffset().ToInt2(); + } + } + + public class Weapon + { + public WeaponInfo Info; + public int FireDelay = 0; // time (in frames) until the weapon can fire again + public int Burst = 0; // burst counter + + public Barrel[] Barrels; // where projectiles are spawned, in local turret space. + public Turret Turret; // where this weapon is mounted -- possibly shared + + public Weapon(string weaponName, Turret turret, int[] localOffset) + { + Info = Rules.Weapons[weaponName.ToLowerInvariant()]; + Burst = Info.Burst; + Turret = turret; + + var barrels = new List(); + for (var i = 0; i < localOffset.Length / 3; i++) + barrels.Add(new Barrel + { + Position = new int2(localOffset[3 * i], localOffset[3 * i + 1]), + Facing = localOffset[3 * i + 2] + }); + + // if no barrels specified, the default is "turret position; turret facing". + if (barrels.Count == 0) + barrels.Add(new Barrel { Position = int2.Zero, Facing = 0 }); + + Barrels = barrels.ToArray(); + } + + public bool IsReloading { get { return FireDelay > 0; } } + + public void Tick() + { + if (FireDelay > 0) --FireDelay; + Turret.Recoil = Math.Max(0f, Turret.Recoil - .2f); + } + + public bool IsValidAgainst(World world, Target target) + { + if( target.IsActor ) + return Combat.WeaponValidForTarget( Info, target.Actor ); + else + return Combat.WeaponValidForTarget( Info, world, Util.CellContaining( target.CenterLocation ) ); + } + + public void FiredShot() + { + Turret.Recoil = 1; + + if (--Burst > 0) + FireDelay = Info.BurstDelay; + else + { + FireDelay = Info.ROF; + Burst = Info.Burst; + } + } + + public void CheckFire(Actor self, AttackBase attack, IMove move, IFacing facing, Target target) + { + if (FireDelay > 0) return; + + var limitedAmmo = self.TraitOrDefault(); + if (limitedAmmo != null && !limitedAmmo.HasAmmo()) + return; + + if( !Combat.IsInRange( self.CenterLocation, Info.Range, target ) ) + return; + if( Combat.IsInRange( self.CenterLocation, Info.MinRange, target ) ) + return; + + if (!IsValidAgainst(self.World, target)) return; + + var barrel = Barrels[Burst % Barrels.Length]; + var destMove = target.IsActor ? target.Actor.TraitOrDefault() : null; + + var args = new ProjectileArgs + { + weapon = Info, + + firedBy = self, + target = target, + + src = (self.CenterLocation + + Combat.GetTurretPosition(self, facing, Turret) + + Combat.GetBarrelPosition(self, facing, Turret, barrel)).ToInt2(), + srcAltitude = move != null ? move.Altitude : 0, + dest = target.CenterLocation, + destAltitude = destMove != null ? destMove.Altitude : 0, + + facing = barrel.Facing + + (self.HasTrait() ? self.Trait().turretFacing : + facing != null ? facing.Facing : Util.GetFacing(target.CenterLocation - self.CenterLocation, 0)), + + firepowerModifier = self.TraitsImplementing() + .Select(a => a.GetFirepowerModifier()) + .Product() + }; + + attack.ScheduleDelayedAction( attack.FireDelay( self, target, self.Info.Traits.Get() ), () => + { + if (args.weapon.Projectile != null) + { + var projectile = args.weapon.Projectile.Create(args); + if (projectile != null) + self.World.Add(projectile); + + if (!string.IsNullOrEmpty(args.weapon.Report)) + Sound.Play(args.weapon.Report + ".aud", self.CenterLocation); + } + }); + + foreach (var na in self.TraitsImplementing()) + na.Attacking(self, target); + + FiredShot(); + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs b/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs index 938ef3d9ee..c906ba0530 100755 --- a/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs +++ b/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs @@ -1,531 +1,531 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Orders; -using OpenRA.Traits; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets -{ - class BuildPaletteWidget : Widget - { - public int Columns = 3; - public int Rows = 5; - - ProductionQueue CurrentQueue; - List VisibleQueues; - - bool paletteOpen = false; - Dictionary iconSprites; - - float2 paletteOpenOrigin = new float2(Game.viewport.Width - 215, 280); - float2 paletteClosedOrigin = new float2(Game.viewport.Width - 16, 280); - float2 paletteOrigin; - - int paletteAnimationLength = 7; - int paletteAnimationFrame = 0; - bool paletteAnimating = false; - - List>> buttons = new List>>(); - List>> tabs = new List>>(); - Animation cantBuild; - Animation ready; - Animation clock; - public readonly string BuildPaletteOpen = "bleep13.aud"; - public readonly string BuildPaletteClose = "bleep13.aud"; - public readonly string TabClick = "ramenu1.aud"; - - readonly WorldRenderer worldRenderer; - readonly World world; - [ObjectCreator.UseCtor] - public BuildPaletteWidget( [ObjectCreator.Param] World world, [ObjectCreator.Param] WorldRenderer worldRenderer ) - { - this.world = world; - this.worldRenderer = worldRenderer; - - cantBuild = new Animation("clock"); - cantBuild.PlayFetchIndex("idle", () => 0); - ready = new Animation("pips"); - ready.PlayRepeating("ready"); - clock = new Animation("clock"); - paletteOrigin = paletteClosedOrigin; - VisibleQueues = new List(); - CurrentQueue = null; - - iconSprites = Rules.Info.Values - .Where(u => u.Traits.Contains() && u.Name[0] != '^') - .ToDictionary( - u => u.Name, - u => Game.modData.SpriteLoader.LoadAllSprites( - u.Traits.Get().Icon ?? (u.Name + "icon"))[0]); - } - - public override Rectangle EventBounds - { - get { return new Rectangle((int)(paletteOrigin.X) - 24, (int)(paletteOrigin.Y), 215, 48 * numActualRows); } - } - - public override void Tick() - { - VisibleQueues.Clear(); - - var queues = world.Queries.WithTrait() - .Where(p => p.Actor.Owner == world.LocalPlayer) - .Select(p => p.Trait); - - if (CurrentQueue != null && CurrentQueue.self.Destroyed) - CurrentQueue = null; - - foreach (var queue in queues) - { - if (queue.AllItems().Count() > 0) - VisibleQueues.Add(queue); - else if (CurrentQueue == queue) - CurrentQueue = null; - } - if (CurrentQueue == null) - CurrentQueue = VisibleQueues.FirstOrDefault(); - - TickPaletteAnimation(world); - - base.Tick(); - } - - void TickPaletteAnimation(World world) - { - if (!paletteAnimating) - return; - - // Increment frame - if (paletteOpen) - paletteAnimationFrame++; - else - paletteAnimationFrame--; - - // Calculate palette position - if (paletteAnimationFrame <= paletteAnimationLength) - paletteOrigin = float2.Lerp(paletteClosedOrigin, paletteOpenOrigin, paletteAnimationFrame * 1.0f / paletteAnimationLength); - - // Play palette-open sound at the start of the activate anim (open) - if (paletteAnimationFrame == 1 && paletteOpen) - Sound.Play(BuildPaletteOpen); - - // Play palette-close sound at the start of the activate anim (close) - if (paletteAnimationFrame == paletteAnimationLength + -1 && !paletteOpen) - Sound.Play(BuildPaletteClose); - - // Animation is complete - if ((paletteAnimationFrame == 0 && !paletteOpen) - || (paletteAnimationFrame == paletteAnimationLength && paletteOpen)) - { - paletteAnimating = false; - } - } - - public void SetCurrentTab(ProductionQueue queue) - { - if (!paletteOpen) - paletteAnimating = true; - - paletteOpen = true; - CurrentQueue = queue; - } - - public override bool HandleKeyPressInner(KeyInput e) - { - if (e.Event == KeyInputEvent.Up || e.Modifiers != Modifiers.None) return false; - - if (e.KeyChar == '\t') - { - TabChange(e.Modifiers.HasModifier(Modifiers.Shift)); - return true; - } - - return DoBuildingHotkey(Char.ToLowerInvariant(e.KeyChar), world); - } - - // TODO: BuildPaletteWidget doesn't support delegate methods for mouse input - public override bool HandleMouseInput(MouseInput mi) - { - if (mi.Event != MouseInputEvent.Down) - return false; - - var action = tabs.Where(a => a.First.Contains(mi.Location)) - .Select(a => a.Second).FirstOrDefault(); - if (action == null && paletteOpen) - action = buttons.Where(a => a.First.Contains(mi.Location)) - .Select(a => a.Second).FirstOrDefault(); - - if (action == null) - return false; - - action(mi); - return true; - } - - public override void DrawInner() - { - if (!IsVisible()) return; - // todo: fix - - int paletteHeight = DrawPalette(CurrentQueue); - DrawBuildTabs(world, paletteHeight); - } - - int numActualRows = 5; - int DrawPalette(ProductionQueue queue) - { - buttons.Clear(); - - string paletteCollection = "palette-" + world.LocalPlayer.Country.Race; - float2 origin = new float2(paletteOrigin.X + 9, paletteOrigin.Y + 9); - var x = 0; - var y = 0; - - if (queue != null) - { - var buildableItems = queue.BuildableItems().OrderBy(a => a.Traits.Get().BuildPaletteOrder); - var allBuildables = queue.AllItems().OrderBy(a => a.Traits.Get().BuildPaletteOrder); - - var overlayBits = new List>(); - numActualRows = Math.Max((allBuildables.Count() + Columns - 1) / Columns, Rows); - - // Palette Background - WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "top"), new float2(origin.X - 9, origin.Y - 9)); - for (var w = 0; w < numActualRows; w++) - WidgetUtils.DrawRGBA( - ChromeProvider.GetImage(paletteCollection, "bg-" + (w % 4).ToString()), - new float2(origin.X - 9, origin.Y + 48 * w)); - WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "bottom"), - new float2(origin.X - 9, origin.Y - 1 + 48 * numActualRows)); - - - // Icons - string tooltipItem = null; - var isBuildingSomething = queue.CurrentItem() != null; - foreach (var item in allBuildables) - { - var rect = new RectangleF(origin.X + x * 64, origin.Y + 48 * y, 64, 48); - var drawPos = new float2(rect.Location); - WidgetUtils.DrawSHP(iconSprites[item.Name], drawPos, worldRenderer); - - var firstOfThis = queue.AllQueued().FirstOrDefault(a => a.Item == item.Name); - - if (rect.Contains(Viewport.LastMousePos)) - tooltipItem = item.Name; - - var overlayPos = drawPos + new float2((64 - ready.Image.size.X) / 2, 2); - - if (firstOfThis != null) - { - clock.PlayFetchIndex("idle", - () => (firstOfThis.TotalTime - firstOfThis.RemainingTime) - * (clock.CurrentSequence.Length - 1) / firstOfThis.TotalTime); - clock.Tick(); - WidgetUtils.DrawSHP(clock.Image, drawPos, worldRenderer); - - if (firstOfThis.Done) - { - ready.Play("ready"); - overlayBits.Add(Pair.New(ready.Image, overlayPos)); - } - else if (firstOfThis.Paused) - { - ready.Play("hold"); - overlayBits.Add(Pair.New(ready.Image, overlayPos)); - } - - var repeats = queue.AllQueued().Count(a => a.Item == item.Name); - if (repeats > 1 || queue.CurrentItem() != firstOfThis) - { - var offset = -22; - var digits = repeats.ToString(); - foreach (var d in digits) - { - ready.PlayFetchIndex("groups", () => d - '0'); - ready.Tick(); - overlayBits.Add(Pair.New(ready.Image, overlayPos + new float2(offset, 0))); - offset += 6; - } - } - } - else - if (!buildableItems.Any(a => a.Name == item.Name) || isBuildingSomething) - overlayBits.Add(Pair.New(cantBuild.Image, drawPos)); - - var closureName = buildableItems.Any(a => a.Name == item.Name) ? item.Name : null; - buttons.Add(Pair.New(new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height), HandleClick(closureName, world))); - - if (++x == Columns) { x = 0; y++; } - } - if (x != 0) y++; - - foreach (var ob in overlayBits) - WidgetUtils.DrawSHP(ob.First, ob.Second, worldRenderer); - - // Tooltip - if (tooltipItem != null && !paletteAnimating && paletteOpen) - DrawProductionTooltip(world, tooltipItem, - new float2(Game.viewport.Width, origin.Y + numActualRows * 48 + 9).ToInt2()); - } - - // Palette Dock - WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-top"), - new float2(Game.viewport.Width - 14, origin.Y - 23)); - - for (int i = 0; i < numActualRows; i++) - WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-" + (i % 4).ToString()), - new float2(Game.viewport.Width - 14, origin.Y + 48 * i)); - - WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-bottom"), - new float2(Game.viewport.Width - 14, origin.Y - 1 + 48 * numActualRows)); - - return 48 * y + 9; - } - - Action HandleClick(string name, World world) - { - return mi => { - Sound.Play(TabClick); - - if (name != null) - HandleBuildPalette(world, name, (mi.Button == MouseButton.Left)); - }; - } - - Action HandleTabClick(ProductionQueue queue, World world) - { - return mi => { - if (mi.Button != MouseButton.Left) - return; - - Sound.Play(TabClick); - var wasOpen = paletteOpen; - paletteOpen = (CurrentQueue == queue && wasOpen) ? false : true; - CurrentQueue = queue; - if (wasOpen != paletteOpen) - paletteAnimating = true; - }; - } - - static string Description( string a ) - { - if( a[ 0 ] == '@' ) - return "any " + a.Substring( 1 ); - else - return Rules.Info[ a.ToLowerInvariant() ].Traits.Get().Name; - } - - void HandleBuildPalette( World world, string item, bool isLmb ) - { - var unit = Rules.Info[item]; - var producing = CurrentQueue.AllQueued().FirstOrDefault( a => a.Item == item ); - - if (isLmb) - { - if (producing != null && producing == CurrentQueue.CurrentItem()) - { - if (producing.Done) - { - if (unit.Traits.Contains()) - world.OrderGenerator = new PlaceBuildingOrderGenerator(CurrentQueue.self, item); - else - StartProduction( world, item ); - return; - } - - if (producing.Paused) - { - world.IssueOrder(Order.PauseProduction(CurrentQueue.self, item, false)); - return; - } - } - - StartProduction(world, item); - } - else - { - if (producing != null) - { - // instant cancel of things we havent really started yet, and things that are finished - if (producing.Paused || producing.Done || producing.TotalCost == producing.RemainingCost) - { - Sound.Play(CurrentQueue.Info.CancelledAudio); - int numberToCancel = Game.GetModifierKeys().HasModifier(Modifiers.Shift) ? 5 : 1; - if (Game.GetModifierKeys().HasModifier(Modifiers.Shift) && - Game.GetModifierKeys().HasModifier(Modifiers.Ctrl)) - { - numberToCancel = -1; //cancel all - } - world.IssueOrder(Order.CancelProduction(CurrentQueue.self, item, numberToCancel)); - } - else - { - Sound.Play(CurrentQueue.Info.OnHoldAudio); - world.IssueOrder(Order.PauseProduction(CurrentQueue.self, item, true)); - } - } - } - } - - void StartProduction( World world, string item ) - { - Sound.Play(CurrentQueue.Info.QueuedAudio); - world.IssueOrder(Order.StartProduction(CurrentQueue.self, item, - Game.GetModifierKeys().HasModifier(Modifiers.Shift) ? 5 : 1)); - } - - void DrawBuildTabs( World world, int paletteHeight) - { - const int tabWidth = 24; - const int tabHeight = 40; - var x = paletteOrigin.X - tabWidth; - var y = paletteOrigin.Y + 9; - - tabs.Clear(); - - foreach (var queue in VisibleQueues) - { - string[] tabKeys = { "normal", "ready", "selected" }; - var producing = queue.CurrentItem(); - var index = queue == CurrentQueue ? 2 : (producing != null && producing.Done) ? 1 : 0; - - var race = world.LocalPlayer.Country.Race; - WidgetUtils.DrawRGBA(ChromeProvider.GetImage("tabs-"+tabKeys[index], race+"-"+queue.Info.Type), new float2(x, y)); - - var rect = new Rectangle((int)x,(int)y,(int)tabWidth,(int)tabHeight); - tabs.Add(Pair.New(rect, HandleTabClick(queue, world))); - - if (rect.Contains(Viewport.LastMousePos)) - { - var text = queue.Info.Type; - var sz = Game.Renderer.BoldFont.Measure(text); - WidgetUtils.DrawPanelPartial("dialog4", - Rectangle.FromLTRB((int)rect.Left - sz.X - 30, (int)rect.Top, (int)rect.Left - 5, (int)rect.Bottom), - PanelSides.All); - - Game.Renderer.BoldFont.DrawText(text, - new float2(rect.Left - sz.X - 20, rect.Top + 12), Color.White); - } - - y += tabHeight; - } - } - - void DrawRightAligned(string text, int2 pos, Color c) - { - Game.Renderer.BoldFont.DrawText(text, - pos - new int2(Game.Renderer.BoldFont.Measure(text).X, 0), c); - } - - void DrawProductionTooltip(World world, string unit, int2 pos) - { - pos.Y += 15; - - var pl = world.LocalPlayer; - var p = pos.ToFloat2() - new float2(297, -3); - - var info = Rules.Info[unit]; - var tooltip = info.Traits.Get(); - var buildable = info.Traits.Get(); - var cost = info.Traits.Get().Cost; - var canBuildThis = CurrentQueue.CanBuild(info); - - var longDescSize = Game.Renderer.RegularFont.Measure(tooltip.Description.Replace("\\n", "\n")).Y; - if (!canBuildThis) longDescSize += 8; - - WidgetUtils.DrawPanel("dialog4", new Rectangle(Game.viewport.Width - 300, pos.Y, 300, longDescSize + 65)); - - Game.Renderer.BoldFont.DrawText( - tooltip.Name + ((buildable.Hotkey != null)? " ({0})".F(buildable.Hotkey.ToUpper()) : ""), - p.ToInt2() + new int2(5, 5), Color.White); - - var resources = pl.PlayerActor.Trait(); - var power = pl.PlayerActor.Trait(); - - DrawRightAligned("${0}".F(cost), pos + new int2(-5, 5), - (resources.DisplayCash + resources.DisplayOre >= cost ? Color.White : Color.Red )); - - var lowpower = power.PowerState != PowerState.Normal; - var time = CurrentQueue.GetBuildTime(info.Name) - * ((lowpower)? CurrentQueue.Info.LowPowerSlowdown : 1); - DrawRightAligned(WidgetUtils.FormatTime(time), pos + new int2(-5, 35), lowpower ? Color.Red: Color.White); - - var bi = info.Traits.GetOrDefault(); - if (bi != null) - DrawRightAligned("{1}{0}".F(bi.Power, bi.Power > 0 ? "+" : ""), pos + new int2(-5, 20), - ((power.PowerProvided - power.PowerDrained) >= -bi.Power || bi.Power > 0)? Color.White: Color.Red); - - p += new int2(5, 35); - if (!canBuildThis) - { - var prereqs = buildable.Prerequisites - .Select( a => Description( a ) ); - Game.Renderer.RegularFont.DrawText( - "Requires {0}".F(string.Join(", ", prereqs.ToArray())), - p.ToInt2(), - Color.White); - - p += new int2(0, 8); - } - - p += new int2(0, 15); - Game.Renderer.RegularFont.DrawText(tooltip.Description.Replace("\\n", "\n"), - p.ToInt2(), Color.White); - } - - bool DoBuildingHotkey(char c, World world) - { - if (!paletteOpen) return false; - if (CurrentQueue == null) return false; - - var toBuild = CurrentQueue.BuildableItems().FirstOrDefault(b => b.Traits.Get().Hotkey == c.ToString()); - - if ( toBuild != null ) - { - Sound.Play(TabClick); - HandleBuildPalette(world, toBuild.Name, true); - return true; - } - - return false; - } - - void TabChange(bool shift) - { - int size = VisibleQueues.Count(); - if (size > 0) - { - int current = VisibleQueues.IndexOf(CurrentQueue); - if (!shift) - { - if (current + 1 >= size) - SetCurrentTab(VisibleQueues.FirstOrDefault()); - else - SetCurrentTab(VisibleQueues[current + 1]); - } - else - { - if (current - 1 < 0) - SetCurrentTab(VisibleQueues.LastOrDefault()); - else - SetCurrentTab(VisibleQueues[current - 1]); - } - } - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Orders; +using OpenRA.Traits; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets +{ + class BuildPaletteWidget : Widget + { + public int Columns = 3; + public int Rows = 5; + + ProductionQueue CurrentQueue; + List VisibleQueues; + + bool paletteOpen = false; + Dictionary iconSprites; + + float2 paletteOpenOrigin = new float2(Game.viewport.Width - 215, 280); + float2 paletteClosedOrigin = new float2(Game.viewport.Width - 16, 280); + float2 paletteOrigin; + + int paletteAnimationLength = 7; + int paletteAnimationFrame = 0; + bool paletteAnimating = false; + + List>> buttons = new List>>(); + List>> tabs = new List>>(); + Animation cantBuild; + Animation ready; + Animation clock; + public readonly string BuildPaletteOpen = "bleep13.aud"; + public readonly string BuildPaletteClose = "bleep13.aud"; + public readonly string TabClick = "ramenu1.aud"; + + readonly WorldRenderer worldRenderer; + readonly World world; + [ObjectCreator.UseCtor] + public BuildPaletteWidget( [ObjectCreator.Param] World world, [ObjectCreator.Param] WorldRenderer worldRenderer ) + { + this.world = world; + this.worldRenderer = worldRenderer; + + cantBuild = new Animation("clock"); + cantBuild.PlayFetchIndex("idle", () => 0); + ready = new Animation("pips"); + ready.PlayRepeating("ready"); + clock = new Animation("clock"); + paletteOrigin = paletteClosedOrigin; + VisibleQueues = new List(); + CurrentQueue = null; + + iconSprites = Rules.Info.Values + .Where(u => u.Traits.Contains() && u.Name[0] != '^') + .ToDictionary( + u => u.Name, + u => Game.modData.SpriteLoader.LoadAllSprites( + u.Traits.Get().Icon ?? (u.Name + "icon"))[0]); + } + + public override Rectangle EventBounds + { + get { return new Rectangle((int)(paletteOrigin.X) - 24, (int)(paletteOrigin.Y), 215, 48 * numActualRows); } + } + + public override void Tick() + { + VisibleQueues.Clear(); + + var queues = world.Queries.WithTrait() + .Where(p => p.Actor.Owner == world.LocalPlayer) + .Select(p => p.Trait); + + if (CurrentQueue != null && CurrentQueue.self.Destroyed) + CurrentQueue = null; + + foreach (var queue in queues) + { + if (queue.AllItems().Count() > 0) + VisibleQueues.Add(queue); + else if (CurrentQueue == queue) + CurrentQueue = null; + } + if (CurrentQueue == null) + CurrentQueue = VisibleQueues.FirstOrDefault(); + + TickPaletteAnimation(world); + + base.Tick(); + } + + void TickPaletteAnimation(World world) + { + if (!paletteAnimating) + return; + + // Increment frame + if (paletteOpen) + paletteAnimationFrame++; + else + paletteAnimationFrame--; + + // Calculate palette position + if (paletteAnimationFrame <= paletteAnimationLength) + paletteOrigin = float2.Lerp(paletteClosedOrigin, paletteOpenOrigin, paletteAnimationFrame * 1.0f / paletteAnimationLength); + + // Play palette-open sound at the start of the activate anim (open) + if (paletteAnimationFrame == 1 && paletteOpen) + Sound.Play(BuildPaletteOpen); + + // Play palette-close sound at the start of the activate anim (close) + if (paletteAnimationFrame == paletteAnimationLength + -1 && !paletteOpen) + Sound.Play(BuildPaletteClose); + + // Animation is complete + if ((paletteAnimationFrame == 0 && !paletteOpen) + || (paletteAnimationFrame == paletteAnimationLength && paletteOpen)) + { + paletteAnimating = false; + } + } + + public void SetCurrentTab(ProductionQueue queue) + { + if (!paletteOpen) + paletteAnimating = true; + + paletteOpen = true; + CurrentQueue = queue; + } + + public override bool HandleKeyPressInner(KeyInput e) + { + if (e.Event == KeyInputEvent.Up || e.Modifiers != Modifiers.None) return false; + + if (e.KeyChar == '\t') + { + TabChange(e.Modifiers.HasModifier(Modifiers.Shift)); + return true; + } + + return DoBuildingHotkey(Char.ToLowerInvariant(e.KeyChar), world); + } + + // TODO: BuildPaletteWidget doesn't support delegate methods for mouse input + public override bool HandleMouseInput(MouseInput mi) + { + if (mi.Event != MouseInputEvent.Down) + return false; + + var action = tabs.Where(a => a.First.Contains(mi.Location)) + .Select(a => a.Second).FirstOrDefault(); + if (action == null && paletteOpen) + action = buttons.Where(a => a.First.Contains(mi.Location)) + .Select(a => a.Second).FirstOrDefault(); + + if (action == null) + return false; + + action(mi); + return true; + } + + public override void DrawInner() + { + if (!IsVisible()) return; + // todo: fix + + int paletteHeight = DrawPalette(CurrentQueue); + DrawBuildTabs(world, paletteHeight); + } + + int numActualRows = 5; + int DrawPalette(ProductionQueue queue) + { + buttons.Clear(); + + string paletteCollection = "palette-" + world.LocalPlayer.Country.Race; + float2 origin = new float2(paletteOrigin.X + 9, paletteOrigin.Y + 9); + var x = 0; + var y = 0; + + if (queue != null) + { + var buildableItems = queue.BuildableItems().OrderBy(a => a.Traits.Get().BuildPaletteOrder); + var allBuildables = queue.AllItems().OrderBy(a => a.Traits.Get().BuildPaletteOrder); + + var overlayBits = new List>(); + numActualRows = Math.Max((allBuildables.Count() + Columns - 1) / Columns, Rows); + + // Palette Background + WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "top"), new float2(origin.X - 9, origin.Y - 9)); + for (var w = 0; w < numActualRows; w++) + WidgetUtils.DrawRGBA( + ChromeProvider.GetImage(paletteCollection, "bg-" + (w % 4).ToString()), + new float2(origin.X - 9, origin.Y + 48 * w)); + WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "bottom"), + new float2(origin.X - 9, origin.Y - 1 + 48 * numActualRows)); + + + // Icons + string tooltipItem = null; + var isBuildingSomething = queue.CurrentItem() != null; + foreach (var item in allBuildables) + { + var rect = new RectangleF(origin.X + x * 64, origin.Y + 48 * y, 64, 48); + var drawPos = new float2(rect.Location); + WidgetUtils.DrawSHP(iconSprites[item.Name], drawPos, worldRenderer); + + var firstOfThis = queue.AllQueued().FirstOrDefault(a => a.Item == item.Name); + + if (rect.Contains(Viewport.LastMousePos)) + tooltipItem = item.Name; + + var overlayPos = drawPos + new float2((64 - ready.Image.size.X) / 2, 2); + + if (firstOfThis != null) + { + clock.PlayFetchIndex("idle", + () => (firstOfThis.TotalTime - firstOfThis.RemainingTime) + * (clock.CurrentSequence.Length - 1) / firstOfThis.TotalTime); + clock.Tick(); + WidgetUtils.DrawSHP(clock.Image, drawPos, worldRenderer); + + if (firstOfThis.Done) + { + ready.Play("ready"); + overlayBits.Add(Pair.New(ready.Image, overlayPos)); + } + else if (firstOfThis.Paused) + { + ready.Play("hold"); + overlayBits.Add(Pair.New(ready.Image, overlayPos)); + } + + var repeats = queue.AllQueued().Count(a => a.Item == item.Name); + if (repeats > 1 || queue.CurrentItem() != firstOfThis) + { + var offset = -22; + var digits = repeats.ToString(); + foreach (var d in digits) + { + ready.PlayFetchIndex("groups", () => d - '0'); + ready.Tick(); + overlayBits.Add(Pair.New(ready.Image, overlayPos + new float2(offset, 0))); + offset += 6; + } + } + } + else + if (!buildableItems.Any(a => a.Name == item.Name) || isBuildingSomething) + overlayBits.Add(Pair.New(cantBuild.Image, drawPos)); + + var closureName = buildableItems.Any(a => a.Name == item.Name) ? item.Name : null; + buttons.Add(Pair.New(new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height), HandleClick(closureName, world))); + + if (++x == Columns) { x = 0; y++; } + } + if (x != 0) y++; + + foreach (var ob in overlayBits) + WidgetUtils.DrawSHP(ob.First, ob.Second, worldRenderer); + + // Tooltip + if (tooltipItem != null && !paletteAnimating && paletteOpen) + DrawProductionTooltip(world, tooltipItem, + new float2(Game.viewport.Width, origin.Y + numActualRows * 48 + 9).ToInt2()); + } + + // Palette Dock + WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-top"), + new float2(Game.viewport.Width - 14, origin.Y - 23)); + + for (int i = 0; i < numActualRows; i++) + WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-" + (i % 4).ToString()), + new float2(Game.viewport.Width - 14, origin.Y + 48 * i)); + + WidgetUtils.DrawRGBA(ChromeProvider.GetImage(paletteCollection, "dock-bottom"), + new float2(Game.viewport.Width - 14, origin.Y - 1 + 48 * numActualRows)); + + return 48 * y + 9; + } + + Action HandleClick(string name, World world) + { + return mi => { + Sound.Play(TabClick); + + if (name != null) + HandleBuildPalette(world, name, (mi.Button == MouseButton.Left)); + }; + } + + Action HandleTabClick(ProductionQueue queue, World world) + { + return mi => { + if (mi.Button != MouseButton.Left) + return; + + Sound.Play(TabClick); + var wasOpen = paletteOpen; + paletteOpen = (CurrentQueue == queue && wasOpen) ? false : true; + CurrentQueue = queue; + if (wasOpen != paletteOpen) + paletteAnimating = true; + }; + } + + static string Description( string a ) + { + if( a[ 0 ] == '@' ) + return "any " + a.Substring( 1 ); + else + return Rules.Info[ a.ToLowerInvariant() ].Traits.Get().Name; + } + + void HandleBuildPalette( World world, string item, bool isLmb ) + { + var unit = Rules.Info[item]; + var producing = CurrentQueue.AllQueued().FirstOrDefault( a => a.Item == item ); + + if (isLmb) + { + if (producing != null && producing == CurrentQueue.CurrentItem()) + { + if (producing.Done) + { + if (unit.Traits.Contains()) + world.OrderGenerator = new PlaceBuildingOrderGenerator(CurrentQueue.self, item); + else + StartProduction( world, item ); + return; + } + + if (producing.Paused) + { + world.IssueOrder(Order.PauseProduction(CurrentQueue.self, item, false)); + return; + } + } + + StartProduction(world, item); + } + else + { + if (producing != null) + { + // instant cancel of things we havent really started yet, and things that are finished + if (producing.Paused || producing.Done || producing.TotalCost == producing.RemainingCost) + { + Sound.Play(CurrentQueue.Info.CancelledAudio); + int numberToCancel = Game.GetModifierKeys().HasModifier(Modifiers.Shift) ? 5 : 1; + if (Game.GetModifierKeys().HasModifier(Modifiers.Shift) && + Game.GetModifierKeys().HasModifier(Modifiers.Ctrl)) + { + numberToCancel = -1; //cancel all + } + world.IssueOrder(Order.CancelProduction(CurrentQueue.self, item, numberToCancel)); + } + else + { + Sound.Play(CurrentQueue.Info.OnHoldAudio); + world.IssueOrder(Order.PauseProduction(CurrentQueue.self, item, true)); + } + } + } + } + + void StartProduction( World world, string item ) + { + Sound.Play(CurrentQueue.Info.QueuedAudio); + world.IssueOrder(Order.StartProduction(CurrentQueue.self, item, + Game.GetModifierKeys().HasModifier(Modifiers.Shift) ? 5 : 1)); + } + + void DrawBuildTabs( World world, int paletteHeight) + { + const int tabWidth = 24; + const int tabHeight = 40; + var x = paletteOrigin.X - tabWidth; + var y = paletteOrigin.Y + 9; + + tabs.Clear(); + + foreach (var queue in VisibleQueues) + { + string[] tabKeys = { "normal", "ready", "selected" }; + var producing = queue.CurrentItem(); + var index = queue == CurrentQueue ? 2 : (producing != null && producing.Done) ? 1 : 0; + + var race = world.LocalPlayer.Country.Race; + WidgetUtils.DrawRGBA(ChromeProvider.GetImage("tabs-"+tabKeys[index], race+"-"+queue.Info.Type), new float2(x, y)); + + var rect = new Rectangle((int)x,(int)y,(int)tabWidth,(int)tabHeight); + tabs.Add(Pair.New(rect, HandleTabClick(queue, world))); + + if (rect.Contains(Viewport.LastMousePos)) + { + var text = queue.Info.Type; + var sz = Game.Renderer.BoldFont.Measure(text); + WidgetUtils.DrawPanelPartial("dialog4", + Rectangle.FromLTRB((int)rect.Left - sz.X - 30, (int)rect.Top, (int)rect.Left - 5, (int)rect.Bottom), + PanelSides.All); + + Game.Renderer.BoldFont.DrawText(text, + new float2(rect.Left - sz.X - 20, rect.Top + 12), Color.White); + } + + y += tabHeight; + } + } + + void DrawRightAligned(string text, int2 pos, Color c) + { + Game.Renderer.BoldFont.DrawText(text, + pos - new int2(Game.Renderer.BoldFont.Measure(text).X, 0), c); + } + + void DrawProductionTooltip(World world, string unit, int2 pos) + { + pos.Y += 15; + + var pl = world.LocalPlayer; + var p = pos.ToFloat2() - new float2(297, -3); + + var info = Rules.Info[unit]; + var tooltip = info.Traits.Get(); + var buildable = info.Traits.Get(); + var cost = info.Traits.Get().Cost; + var canBuildThis = CurrentQueue.CanBuild(info); + + var longDescSize = Game.Renderer.RegularFont.Measure(tooltip.Description.Replace("\\n", "\n")).Y; + if (!canBuildThis) longDescSize += 8; + + WidgetUtils.DrawPanel("dialog4", new Rectangle(Game.viewport.Width - 300, pos.Y, 300, longDescSize + 65)); + + Game.Renderer.BoldFont.DrawText( + tooltip.Name + ((buildable.Hotkey != null)? " ({0})".F(buildable.Hotkey.ToUpper()) : ""), + p.ToInt2() + new int2(5, 5), Color.White); + + var resources = pl.PlayerActor.Trait(); + var power = pl.PlayerActor.Trait(); + + DrawRightAligned("${0}".F(cost), pos + new int2(-5, 5), + (resources.DisplayCash + resources.DisplayOre >= cost ? Color.White : Color.Red )); + + var lowpower = power.PowerState != PowerState.Normal; + var time = CurrentQueue.GetBuildTime(info.Name) + * ((lowpower)? CurrentQueue.Info.LowPowerSlowdown : 1); + DrawRightAligned(WidgetUtils.FormatTime(time), pos + new int2(-5, 35), lowpower ? Color.Red: Color.White); + + var bi = info.Traits.GetOrDefault(); + if (bi != null) + DrawRightAligned("{1}{0}".F(bi.Power, bi.Power > 0 ? "+" : ""), pos + new int2(-5, 20), + ((power.PowerProvided - power.PowerDrained) >= -bi.Power || bi.Power > 0)? Color.White: Color.Red); + + p += new int2(5, 35); + if (!canBuildThis) + { + var prereqs = buildable.Prerequisites + .Select( a => Description( a ) ); + Game.Renderer.RegularFont.DrawText( + "Requires {0}".F(string.Join(", ", prereqs.ToArray())), + p.ToInt2(), + Color.White); + + p += new int2(0, 8); + } + + p += new int2(0, 15); + Game.Renderer.RegularFont.DrawText(tooltip.Description.Replace("\\n", "\n"), + p.ToInt2(), Color.White); + } + + bool DoBuildingHotkey(char c, World world) + { + if (!paletteOpen) return false; + if (CurrentQueue == null) return false; + + var toBuild = CurrentQueue.BuildableItems().FirstOrDefault(b => b.Traits.Get().Hotkey == c.ToString()); + + if ( toBuild != null ) + { + Sound.Play(TabClick); + HandleBuildPalette(world, toBuild.Name, true); + return true; + } + + return false; + } + + void TabChange(bool shift) + { + int size = VisibleQueues.Count(); + if (size > 0) + { + int current = VisibleQueues.IndexOf(CurrentQueue); + if (!shift) + { + if (current + 1 >= size) + SetCurrentTab(VisibleQueues.FirstOrDefault()); + else + SetCurrentTab(VisibleQueues[current + 1]); + } + else + { + if (current - 1 < 0) + SetCurrentTab(VisibleQueues.LastOrDefault()); + else + SetCurrentTab(VisibleQueues[current - 1]); + } + } + } + } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/Widgets/Delegates/ConnectionDialogsDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/ConnectionDialogsDelegate.cs index 753fc00408..a7702cc2a2 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/ConnectionDialogsDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/ConnectionDialogsDelegate.cs @@ -1,56 +1,56 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Network; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class ConnectionDialogsDelegate : IWidgetDelegate - { - [ObjectCreator.UseCtor] - public ConnectionDialogsDelegate( - [ObjectCreator.Param] Widget widget, - [ObjectCreator.Param] string host, - [ObjectCreator.Param] int port ) - { - widget.GetWidget("CONNECTION_BUTTON_ABORT").OnMouseUp = mi => { - widget.GetWidget("CONNECTION_BUTTON_ABORT").Parent.Visible = false; - Game.Disconnect(); - return true; - }; - - widget.GetWidget("CONNECTING_DESC").GetText = () => - "Connecting to {0}:{1}...".F(host, port); - } - } - - public class ConnectionFailedDelegate : IWidgetDelegate - { - [ObjectCreator.UseCtor] - public ConnectionFailedDelegate( - [ObjectCreator.Param] Widget widget, - [ObjectCreator.Param] OrderManager orderManager) - { - widget.GetWidget("CONNECTION_BUTTON_CANCEL").OnMouseUp = mi => { - widget.GetWidget("CONNECTION_BUTTON_CANCEL").Parent.Visible = false; - Game.Disconnect(); - return true; - }; - widget.GetWidget("CONNECTION_BUTTON_RETRY").OnMouseUp = mi => { - Game.JoinServer(orderManager.Host, orderManager.Port); - return true; - }; - - widget.GetWidget("CONNECTION_FAILED_DESC").GetText = () => string.IsNullOrEmpty(orderManager.ServerError) ? - "Could not connect to {0}:{1}".F(orderManager.Host, orderManager.Port) : orderManager.ServerError; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Network; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class ConnectionDialogsDelegate : IWidgetDelegate + { + [ObjectCreator.UseCtor] + public ConnectionDialogsDelegate( + [ObjectCreator.Param] Widget widget, + [ObjectCreator.Param] string host, + [ObjectCreator.Param] int port ) + { + widget.GetWidget("CONNECTION_BUTTON_ABORT").OnMouseUp = mi => { + widget.GetWidget("CONNECTION_BUTTON_ABORT").Parent.Visible = false; + Game.Disconnect(); + return true; + }; + + widget.GetWidget("CONNECTING_DESC").GetText = () => + "Connecting to {0}:{1}...".F(host, port); + } + } + + public class ConnectionFailedDelegate : IWidgetDelegate + { + [ObjectCreator.UseCtor] + public ConnectionFailedDelegate( + [ObjectCreator.Param] Widget widget, + [ObjectCreator.Param] OrderManager orderManager) + { + widget.GetWidget("CONNECTION_BUTTON_CANCEL").OnMouseUp = mi => { + widget.GetWidget("CONNECTION_BUTTON_CANCEL").Parent.Visible = false; + Game.Disconnect(); + return true; + }; + widget.GetWidget("CONNECTION_BUTTON_RETRY").OnMouseUp = mi => { + Game.JoinServer(orderManager.Host, orderManager.Port); + return true; + }; + + widget.GetWidget("CONNECTION_FAILED_DESC").GetText = () => string.IsNullOrEmpty(orderManager.ServerError) ? + "Could not connect to {0}:{1}".F(orderManager.Host, orderManager.Port) : orderManager.ServerError; + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Delegates/CreateServerMenuDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/CreateServerMenuDelegate.cs index ab39ad30f9..2bed8feb11 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/CreateServerMenuDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/CreateServerMenuDelegate.cs @@ -1,50 +1,50 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using System.Net; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class CreateServerMenuDelegate : IWidgetDelegate - { - [ObjectCreator.UseCtor] - public CreateServerMenuDelegate( [ObjectCreator.Param( "widget" )] Widget cs ) - { - var settings = Game.Settings; - - cs.GetWidget("BUTTON_CANCEL").OnMouseUp = mi => { - Widget.CloseWindow(); - return true; - }; - - cs.GetWidget("BUTTON_START").OnMouseUp = mi => { - var map = Game.modData.AvailableMaps.FirstOrDefault(m => m.Value.Selectable).Key; - - settings.Server.Name = cs.GetWidget("GAME_TITLE").Text; - settings.Server.ListenPort = int.Parse(cs.GetWidget("LISTEN_PORT").Text); - settings.Server.ExternalPort = int.Parse(cs.GetWidget("EXTERNAL_PORT").Text); - settings.Save(); - - Game.CreateAndJoinServer(settings, map); - return true; - }; - - cs.GetWidget("GAME_TITLE").Text = settings.Server.Name; - cs.GetWidget("LISTEN_PORT").Text = settings.Server.ListenPort.ToString(); - cs.GetWidget("EXTERNAL_PORT").Text = settings.Server.ExternalPort.ToString(); - cs.GetWidget("CHECKBOX_ONLINE").Bind(settings.Server, "AdvertiseOnline"); - cs.GetWidget("CHECKBOX_ONLINE").OnChange += _ => settings.Save(); - cs.GetWidget("CHECKBOX_CHEATS").Bind(settings.Server, "AllowCheats"); - cs.GetWidget("CHECKBOX_CHEATS").OnChange += _ => settings.Save(); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using System.Net; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class CreateServerMenuDelegate : IWidgetDelegate + { + [ObjectCreator.UseCtor] + public CreateServerMenuDelegate( [ObjectCreator.Param( "widget" )] Widget cs ) + { + var settings = Game.Settings; + + cs.GetWidget("BUTTON_CANCEL").OnMouseUp = mi => { + Widget.CloseWindow(); + return true; + }; + + cs.GetWidget("BUTTON_START").OnMouseUp = mi => { + var map = Game.modData.AvailableMaps.FirstOrDefault(m => m.Value.Selectable).Key; + + settings.Server.Name = cs.GetWidget("GAME_TITLE").Text; + settings.Server.ListenPort = int.Parse(cs.GetWidget("LISTEN_PORT").Text); + settings.Server.ExternalPort = int.Parse(cs.GetWidget("EXTERNAL_PORT").Text); + settings.Save(); + + Game.CreateAndJoinServer(settings, map); + return true; + }; + + cs.GetWidget("GAME_TITLE").Text = settings.Server.Name; + cs.GetWidget("LISTEN_PORT").Text = settings.Server.ListenPort.ToString(); + cs.GetWidget("EXTERNAL_PORT").Text = settings.Server.ExternalPort.ToString(); + cs.GetWidget("CHECKBOX_ONLINE").Bind(settings.Server, "AdvertiseOnline"); + cs.GetWidget("CHECKBOX_ONLINE").OnChange += _ => settings.Save(); + cs.GetWidget("CHECKBOX_CHEATS").Bind(settings.Server, "AllowCheats"); + cs.GetWidget("CHECKBOX_CHEATS").OnChange += _ => settings.Save(); + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Delegates/DiplomacyDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/DiplomacyDelegate.cs index eda7086398..50107b3dd8 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/DiplomacyDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/DiplomacyDelegate.cs @@ -1,145 +1,145 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.Traits; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class DiplomacyDelegate : IWidgetDelegate - { - static List controls = new List(); - - int validPlayers = 0; +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Traits; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class DiplomacyDelegate : IWidgetDelegate + { + static List controls = new List(); + + int validPlayers = 0; readonly World world; [ObjectCreator.UseCtor] public DiplomacyDelegate( [ObjectCreator.Param] World world ) - { + { this.world = world; - var root = Widget.RootWidget.GetWidget("INGAME_ROOT"); - var diplomacyBG = root.GetWidget("DIPLOMACY_BG"); - var diplomacy = root.GetWidget("INGAME_DIPLOMACY_BUTTON"); - diplomacy.OnMouseUp = mi => - { - diplomacyBG.Visible = !diplomacyBG.Visible; - if (diplomacyBG.IsVisible()) - LayoutDialog(diplomacyBG); - return true; - }; - - Game.AfterGameStart += _ => validPlayers = world.players.Values.Where(a => a != world.LocalPlayer && !a.NonCombatant).Count(); - diplomacy.IsVisible = () => (validPlayers > 0); - } - - void LayoutDialog(Widget bg) - { - bg.Children.RemoveAll(w => controls.Contains(w)); - controls.Clear(); - - var y = 50; - var margin = 20; - var labelWidth = (bg.Bounds.Width - 3 * margin) / 3; - - var ts = new LabelWidget - { - Bold = true, - Bounds = new Rectangle(margin + labelWidth + 10, y, labelWidth, 25), - Text = "Their Stance", - Align = LabelWidget.TextAlign.Left, - }; - - bg.AddChild(ts); - controls.Add(ts); - - var ms = new LabelWidget - { - Bold = true, - Bounds = new Rectangle(margin + 2 * labelWidth + 20, y, labelWidth, 25), - Text = "My Stance", - Align = LabelWidget.TextAlign.Left, - }; - - bg.AddChild(ms); - controls.Add(ms); - - y += 35; - - foreach (var p in world.players.Values.Where(a => a != world.LocalPlayer && !a.NonCombatant)) - { - var pp = p; - var label = new LabelWidget - { - Bounds = new Rectangle(margin, y, labelWidth, 25), - Id = "DIPLOMACY_PLAYER_LABEL_{0}".F(p.Index), - Text = p.PlayerName, - Align = LabelWidget.TextAlign.Left, - Bold = true, - }; - - bg.AddChild(label); - controls.Add(label); - - var theirStance = new LabelWidget - { - Bounds = new Rectangle( margin + labelWidth + 10, y, labelWidth, 25), - Id = "DIPLOMACY_PLAYER_LABEL_THEIR_{0}".F(p.Index), - Text = p.PlayerName, - Align = LabelWidget.TextAlign.Left, - Bold = false, - - GetText = () => pp.Stances[ world.LocalPlayer ].ToString(), - }; - - bg.AddChild(theirStance); - controls.Add(theirStance); - - var myStance = new DropDownButtonWidget - { - Bounds = new Rectangle( margin + 2 * labelWidth + 20, y, labelWidth, 25), - Id = "DIPLOMACY_PLAYER_LABEL_MY_{0}".F(p.Index), - GetText = () => world.LocalPlayer.Stances[ pp ].ToString(), - }; - - myStance.OnMouseDown = mi => { ShowDropDown(pp, myStance); return true; }; - - bg.AddChild(myStance); - controls.Add(myStance); - - y += 35; - } - } - - void ShowDropDown(Player p, Widget w) - { - DropDownButtonWidget.ShowDropDown(w, Enum.GetValues(typeof(Stance)).OfType(), - (s, width) => new LabelWidget - { - Bounds = new Rectangle(0, 0, width, 24), - Text = " {0}".F(s), - OnMouseUp = mi => { SetStance((ButtonWidget)w, p, s); return true; }, - }); - } - - void SetStance(ButtonWidget bw, Player p, Stance ss) - { - if (p.World.LobbyInfo.GlobalSettings.LockTeams) - return; // team changes are banned - - world.IssueOrder(new Order("SetStance", world.LocalPlayer.PlayerActor, - false) { TargetLocation = new int2(p.Index, (int)ss) }); - - bw.Text = ss.ToString(); - } - } -} + var root = Widget.RootWidget.GetWidget("INGAME_ROOT"); + var diplomacyBG = root.GetWidget("DIPLOMACY_BG"); + var diplomacy = root.GetWidget("INGAME_DIPLOMACY_BUTTON"); + diplomacy.OnMouseUp = mi => + { + diplomacyBG.Visible = !diplomacyBG.Visible; + if (diplomacyBG.IsVisible()) + LayoutDialog(diplomacyBG); + return true; + }; + + Game.AfterGameStart += _ => validPlayers = world.players.Values.Where(a => a != world.LocalPlayer && !a.NonCombatant).Count(); + diplomacy.IsVisible = () => (validPlayers > 0); + } + + void LayoutDialog(Widget bg) + { + bg.Children.RemoveAll(w => controls.Contains(w)); + controls.Clear(); + + var y = 50; + var margin = 20; + var labelWidth = (bg.Bounds.Width - 3 * margin) / 3; + + var ts = new LabelWidget + { + Bold = true, + Bounds = new Rectangle(margin + labelWidth + 10, y, labelWidth, 25), + Text = "Their Stance", + Align = LabelWidget.TextAlign.Left, + }; + + bg.AddChild(ts); + controls.Add(ts); + + var ms = new LabelWidget + { + Bold = true, + Bounds = new Rectangle(margin + 2 * labelWidth + 20, y, labelWidth, 25), + Text = "My Stance", + Align = LabelWidget.TextAlign.Left, + }; + + bg.AddChild(ms); + controls.Add(ms); + + y += 35; + + foreach (var p in world.players.Values.Where(a => a != world.LocalPlayer && !a.NonCombatant)) + { + var pp = p; + var label = new LabelWidget + { + Bounds = new Rectangle(margin, y, labelWidth, 25), + Id = "DIPLOMACY_PLAYER_LABEL_{0}".F(p.Index), + Text = p.PlayerName, + Align = LabelWidget.TextAlign.Left, + Bold = true, + }; + + bg.AddChild(label); + controls.Add(label); + + var theirStance = new LabelWidget + { + Bounds = new Rectangle( margin + labelWidth + 10, y, labelWidth, 25), + Id = "DIPLOMACY_PLAYER_LABEL_THEIR_{0}".F(p.Index), + Text = p.PlayerName, + Align = LabelWidget.TextAlign.Left, + Bold = false, + + GetText = () => pp.Stances[ world.LocalPlayer ].ToString(), + }; + + bg.AddChild(theirStance); + controls.Add(theirStance); + + var myStance = new DropDownButtonWidget + { + Bounds = new Rectangle( margin + 2 * labelWidth + 20, y, labelWidth, 25), + Id = "DIPLOMACY_PLAYER_LABEL_MY_{0}".F(p.Index), + GetText = () => world.LocalPlayer.Stances[ pp ].ToString(), + }; + + myStance.OnMouseDown = mi => { ShowDropDown(pp, myStance); return true; }; + + bg.AddChild(myStance); + controls.Add(myStance); + + y += 35; + } + } + + void ShowDropDown(Player p, Widget w) + { + DropDownButtonWidget.ShowDropDown(w, Enum.GetValues(typeof(Stance)).OfType(), + (s, width) => new LabelWidget + { + Bounds = new Rectangle(0, 0, width, 24), + Text = " {0}".F(s), + OnMouseUp = mi => { SetStance((ButtonWidget)w, p, s); return true; }, + }); + } + + void SetStance(ButtonWidget bw, Player p, Stance ss) + { + if (p.World.LobbyInfo.GlobalSettings.LockTeams) + return; // team changes are banned + + world.IssueOrder(new Order("SetStance", world.LocalPlayer.PlayerActor, + false) { TargetLocation = new int2(p.Index, (int)ss) }); + + bw.Text = ss.ToString(); + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Delegates/GameInitDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/GameInitDelegate.cs index e5abde0161..bf9ff5d450 100755 --- a/OpenRA.Mods.RA/Widgets/Delegates/GameInitDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/GameInitDelegate.cs @@ -1,221 +1,222 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.FileFormats; -using OpenRA.Network; -using OpenRA.Server; -using OpenRA.Widgets; -using System.Diagnostics; -using System; -using System.Net; -using System.ComponentModel; -using System.IO; -using System.Threading; -using System.Drawing; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class GameInitDelegate : IWidgetDelegate - { - GameInitInfoWidget Info; - - [ObjectCreator.UseCtor] - public GameInitDelegate([ObjectCreator.Param] Widget widget) - { - Info = (widget as GameInitInfoWidget); - - Game.ConnectionStateChanged += orderManager => - { - Widget.CloseWindow(); - switch( orderManager.Connection.ConnectionState ) - { - case ConnectionState.PreConnecting: - Widget.OpenWindow("MAINMENU_BG"); - break; - case ConnectionState.Connecting: - Widget.OpenWindow( "CONNECTING_BG", - new Dictionary { { "host", orderManager.Host }, { "port", orderManager.Port } } ); - break; - case ConnectionState.NotConnected: - Widget.OpenWindow( "CONNECTION_FAILED_BG", - new Dictionary { { "orderManager", orderManager } } ); - break; - case ConnectionState.Connected: - var lobby = Game.OpenWindow(orderManager.world, "SERVER_LOBBY"); - lobby.GetWidget("CHAT_DISPLAY").ClearChat(); - lobby.GetWidget("CHANGEMAP_BUTTON").Visible = true; - lobby.GetWidget("LOCKTEAMS_CHECKBOX").Visible = true; - lobby.GetWidget("DISCONNECT_BUTTON").Visible = true; - break; - } - }; - - if (FileSystem.Exists(Info.TestFile)) - ContinueLoading(widget); - else - { - MainMenuButtonsDelegate.DisplayModSelector(); - ShowInstallMethodDialog(); - } - } - - void ShowInstallMethodDialog() - { - var window = Widget.OpenWindow("INIT_CHOOSEINSTALL"); - window.GetWidget("DOWNLOAD").OnMouseUp = mi => { ShowDownloadDialog(); return true; }; - window.GetWidget("FROMCD").OnMouseUp = mi => PromptForCD(); - - window.GetWidget("QUIT").OnMouseUp = mi => { Game.Exit(); return true; }; - } - - bool PromptForCD() - { - Game.Utilities.PromptFilepathAsync("Select MAIN.MIX on the CD", path => - { - if (!string.IsNullOrEmpty(path)) - Game.RunAfterTick(() => InstallFromCD(Path.GetDirectoryName(path))); - }); - return true; - } - - void InstallFromCD(string path) - { - var window = Widget.OpenWindow("INIT_COPY"); - var status = window.GetWidget("STATUS"); - var progress = window.GetWidget("PROGRESS"); - progress.Indeterminate = true; - - // TODO: Handle cancelling copy - window.GetWidget("CANCEL").IsVisible = () => false; - window.GetWidget("CANCEL").OnMouseUp = mi => { ShowInstallMethodDialog(); return true; }; - window.GetWidget("RETRY").OnMouseUp = mi => PromptForCD(); - - status.GetText = () => "Copying..."; - var error = false; - Action parseOutput = s => - { - if (s.Substring(0,5) == "Error") - { - error = true; - ShowDownloadError(window, s); - } - if (s.Substring(0,6) == "Status") - window.GetWidget("STATUS").GetText = () => s.Substring(7).Trim(); - }; - - Action onComplete = () => - { - if (!error) - Game.RunAfterTick(() => ContinueLoading(Info)); - }; - - if (Info.InstallMode == "ra") - Game.Utilities.InstallRAFilesAsync(path, FileSystem.SpecialPackageRoot+Info.PackagePath, parseOutput, onComplete); - else - ShowDownloadError(window, "Installing from CD not supported"); - } - - void ShowDownloadDialog() - { - var window = Widget.OpenWindow("INIT_DOWNLOAD"); - var status = window.GetWidget("STATUS"); - status.GetText = () => "Initializing..."; - var progress = window.GetWidget("PROGRESS"); - // Save the package to a temp file - var file = Path.GetTempPath() + Path.DirectorySeparatorChar + Path.GetRandomFileName(); - Action onDownloadChange = i => - { - status.GetText = () => "Downloading {1}/{2} kB ({0}%)".F(i.ProgressPercentage, i.BytesReceived/1024, i.TotalBytesToReceive/1024); - progress.Percentage = i.ProgressPercentage; - }; - - Action onDownloadComplete = (i, cancelled) => - { - if (i.Error != null) - ShowDownloadError(window, i.Error.Message); - else if (!cancelled) - { - // Automatically extract - status.GetText = () => "Extracting..."; - progress.Indeterminate = true; - var error = false; - Action parseOutput = s => - { - if (s.Substring(0,5) == "Error") - { - error = true; - ShowDownloadError(window, s); - } - if (s.Substring(0,6) == "Status") - window.GetWidget("STATUS").GetText = () => s.Substring(7).Trim(); - }; - - Action onComplete = () => - { - if (!error) - Game.RunAfterTick(() => ContinueLoading(Info)); - }; - - Game.RunAfterTick(() => Game.Utilities.ExtractZipAsync(file, FileSystem.SpecialPackageRoot+Info.PackagePath, parseOutput, onComplete)); - } - }; - - var dl = new Download(Info.PackageURL, file, onDownloadChange, onDownloadComplete); - window.GetWidget("CANCEL").OnMouseUp = mi => { dl.Cancel(); ShowInstallMethodDialog(); return true; }; - window.GetWidget("RETRY").OnMouseUp = mi => { dl.Cancel(); ShowDownloadDialog(); return true; }; - } - - void ShowDownloadError(Widget window, string e) - { - if (window.GetWidget("STATUS") != null) /* ugh */ - { - window.GetWidget("STATUS").GetText = () => e; - window.GetWidget("RETRY").IsVisible = () => true; - window.GetWidget("CANCEL").IsVisible = () => true; - } - } - - void ContinueLoading(Widget widget) - { - Game.LoadShellMap(); - Widget.RootWidget.RemoveChildren(); - Widget.OpenWindow("MAINMENU_BG"); - } - - // General support methods - public class Download - { - WebClient wc; - bool cancelled; - - public Download(string url, string path, Action onProgress, Action onComplete) - { - wc = new WebClient(); - wc.Proxy = null; - - wc.DownloadProgressChanged += (_,a) => onProgress(a); - wc.DownloadFileCompleted += (_,a) => onComplete(a, cancelled); - - Game.OnQuit += () => Cancel(); - wc.DownloadFileCompleted += (_,a) => {Game.OnQuit -= () => Cancel();}; - - wc.DownloadFileAsync(new Uri(url), path); - } - - public void Cancel() - { - Game.OnQuit -= () => Cancel(); - wc.CancelAsync(); - cancelled = true; - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.FileFormats; +using OpenRA.Network; +using OpenRA.Server; +using OpenRA.Widgets; +using System.Diagnostics; +using System; +using System.Net; +using System.ComponentModel; +using System.IO; +using System.Threading; +using System.Drawing; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class GameInitDelegate : IWidgetDelegate + { + GameInitInfoWidget Info; + + [ObjectCreator.UseCtor] + public GameInitDelegate([ObjectCreator.Param] Widget widget) + { + Info = (widget as GameInitInfoWidget); + + Game.ConnectionStateChanged += orderManager => + { + Widget.CloseWindow(); + switch( orderManager.Connection.ConnectionState ) + { + case ConnectionState.PreConnecting: + Widget.OpenWindow("MAINMENU_BG"); + break; + case ConnectionState.Connecting: + Widget.OpenWindow( "CONNECTING_BG", + new Dictionary { { "host", orderManager.Host }, { "port", orderManager.Port } } ); + break; + case ConnectionState.NotConnected: + Widget.OpenWindow( "CONNECTION_FAILED_BG", + new Dictionary { { "orderManager", orderManager } } ); + break; + case ConnectionState.Connected: + var lobby = Game.OpenWindow(orderManager.world, "SERVER_LOBBY"); + lobby.GetWidget("CHAT_DISPLAY").ClearChat(); + lobby.GetWidget("CHANGEMAP_BUTTON").Visible = true; + lobby.GetWidget("LOCKTEAMS_CHECKBOX").Visible = true; + lobby.GetWidget("DISCONNECT_BUTTON").Visible = true; + break; + } + }; + + if (FileSystem.Exists(Info.TestFile)) + ContinueLoading(widget); + else + { + MainMenuButtonsDelegate.DisplayModSelector(); + ShowInstallMethodDialog(); + } + } + + void ShowInstallMethodDialog() + { + var window = Widget.OpenWindow("INIT_CHOOSEINSTALL"); + window.GetWidget("DOWNLOAD").OnMouseUp = mi => { ShowDownloadDialog(); return true; }; + window.GetWidget("FROMCD").OnMouseUp = mi => PromptForCD(); + + window.GetWidget("QUIT").OnMouseUp = mi => { Game.Exit(); return true; }; + } + + bool PromptForCD() + { + Game.Utilities.PromptFilepathAsync("Select MAIN.MIX on the CD", path => + { + if (!string.IsNullOrEmpty(path)) + Game.RunAfterTick(() => InstallFromCD(Path.GetDirectoryName(path))); + }); + return true; + } + + void InstallFromCD(string path) + { + var window = Widget.OpenWindow("INIT_COPY"); + var status = window.GetWidget("STATUS"); + var progress = window.GetWidget("PROGRESS"); + progress.Indeterminate = true; + + // TODO: Handle cancelling copy + window.GetWidget("CANCEL").IsVisible = () => false; + window.GetWidget("CANCEL").OnMouseUp = mi => { ShowInstallMethodDialog(); return true; }; + window.GetWidget("RETRY").OnMouseUp = mi => PromptForCD(); + + status.GetText = () => "Copying..."; + var error = false; + Action parseOutput = s => + { + if (s.Substring(0,5) == "Error") + { + error = true; + ShowDownloadError(window, s); + } + if (s.Substring(0,6) == "Status") + window.GetWidget("STATUS").GetText = () => s.Substring(7).Trim(); + }; + + Action onComplete = () => + { + if (!error) + Game.RunAfterTick(() => ContinueLoading(Info)); + }; + + if (Info.InstallMode == "ra") + Game.Utilities.InstallRAFilesAsync(path, FileSystem.SpecialPackageRoot+Info.PackagePath, parseOutput, onComplete); + else + ShowDownloadError(window, "Installing from CD not supported"); + } + + void ShowDownloadDialog() + { + var window = Widget.OpenWindow("INIT_DOWNLOAD"); + var status = window.GetWidget("STATUS"); + status.GetText = () => "Initializing..."; + var progress = window.GetWidget("PROGRESS"); + + // Save the package to a temp file + var file = Path.GetTempPath() + Path.DirectorySeparatorChar + Path.GetRandomFileName(); + Action onDownloadChange = i => + { + status.GetText = () => "Downloading {1}/{2} kB ({0}%)".F(i.ProgressPercentage, i.BytesReceived/1024, i.TotalBytesToReceive/1024); + progress.Percentage = i.ProgressPercentage; + }; + + Action onDownloadComplete = (i, cancelled) => + { + if (i.Error != null) + ShowDownloadError(window, i.Error.Message); + else if (!cancelled) + { + // Automatically extract + status.GetText = () => "Extracting..."; + progress.Indeterminate = true; + var error = false; + Action parseOutput = s => + { + if (s.Substring(0,5) == "Error") + { + error = true; + ShowDownloadError(window, s); + } + if (s.Substring(0,6) == "Status") + window.GetWidget("STATUS").GetText = () => s.Substring(7).Trim(); + }; + + Action onComplete = () => + { + if (!error) + Game.RunAfterTick(() => ContinueLoading(Info)); + }; + + Game.RunAfterTick(() => Game.Utilities.ExtractZipAsync(file, FileSystem.SpecialPackageRoot+Info.PackagePath, parseOutput, onComplete)); + } + }; + + var dl = new Download(Info.PackageURL, file, onDownloadChange, onDownloadComplete); + window.GetWidget("CANCEL").OnMouseUp = mi => { dl.Cancel(); ShowInstallMethodDialog(); return true; }; + window.GetWidget("RETRY").OnMouseUp = mi => { dl.Cancel(); ShowDownloadDialog(); return true; }; + } + + void ShowDownloadError(Widget window, string e) + { + if (window.GetWidget("STATUS") != null) /* ugh */ + { + window.GetWidget("STATUS").GetText = () => e; + window.GetWidget("RETRY").IsVisible = () => true; + window.GetWidget("CANCEL").IsVisible = () => true; + } + } + + void ContinueLoading(Widget widget) + { + Game.LoadShellMap(); + Widget.RootWidget.RemoveChildren(); + Widget.OpenWindow("MAINMENU_BG"); + } + + // General support methods + public class Download + { + WebClient wc; + bool cancelled; + + public Download(string url, string path, Action onProgress, Action onComplete) + { + wc = new WebClient(); + wc.Proxy = null; + + wc.DownloadProgressChanged += (_,a) => onProgress(a); + wc.DownloadFileCompleted += (_,a) => onComplete(a, cancelled); + + Game.OnQuit += () => Cancel(); + wc.DownloadFileCompleted += (_,a) => {Game.OnQuit -= () => Cancel();}; + + wc.DownloadFileAsync(new Uri(url), path); + } + + public void Cancel() + { + Game.OnQuit -= () => Cancel(); + wc.CancelAsync(); + cancelled = true; + } + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Delegates/IngameChromeDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/IngameChromeDelegate.cs index fb6ee419f9..58d1c61389 100755 --- a/OpenRA.Mods.RA/Widgets/Delegates/IngameChromeDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/IngameChromeDelegate.cs @@ -1,33 +1,33 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Widgets; - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Widgets; + namespace OpenRA.Mods.RA.Widgets.Delegates { public class IngameChromeDelegate : IWidgetDelegate { [ObjectCreator.UseCtor] public IngameChromeDelegate( [ObjectCreator.Param] World world ) - { + { var r = Widget.RootWidget; - var gameRoot = r.GetWidget("INGAME_ROOT"); + var gameRoot = r.GetWidget("INGAME_ROOT"); var optionsBG = gameRoot.GetWidget("INGAME_OPTIONS_BG"); - r.GetWidget("INGAME_OPTIONS_BUTTON").OnMouseUp = mi => { + r.GetWidget("INGAME_OPTIONS_BUTTON").OnMouseUp = mi => { optionsBG.Visible = !optionsBG.Visible; return true; }; - optionsBG.GetWidget("DISCONNECT").OnMouseUp = mi => { + optionsBG.GetWidget("DISCONNECT").OnMouseUp = mi => { optionsBG.Visible = false; Game.Disconnect(); return true; @@ -36,25 +36,25 @@ namespace OpenRA.Mods.RA.Widgets.Delegates optionsBG.GetWidget("SETTINGS").OnMouseUp = mi => { Widget.OpenWindow("SETTINGS_MENU"); return true; - }; - - optionsBG.GetWidget("MUSIC").OnMouseUp = mi => { - Widget.OpenWindow("MUSIC_MENU"); - return true; - }; - - optionsBG.GetWidget("RESUME").OnMouseUp = mi => - { - optionsBG.Visible = false; - return true; - }; - - optionsBG.GetWidget("SURRENDER").OnMouseUp = mi => - { - world.IssueOrder(new Order("Surrender", world.LocalPlayer.PlayerActor, false)); - return true; }; - + + optionsBG.GetWidget("MUSIC").OnMouseUp = mi => { + Widget.OpenWindow("MUSIC_MENU"); + return true; + }; + + optionsBG.GetWidget("RESUME").OnMouseUp = mi => + { + optionsBG.Visible = false; + return true; + }; + + optionsBG.GetWidget("SURRENDER").OnMouseUp = mi => + { + world.IssueOrder(new Order("Surrender", world.LocalPlayer.PlayerActor, false)); + return true; + }; + optionsBG.GetWidget("SURRENDER").IsVisible = () => (world.LocalPlayer != null && world.LocalPlayer.WinState == WinState.Undefined); optionsBG.GetWidget("QUIT").OnMouseUp = mi => { @@ -62,22 +62,22 @@ namespace OpenRA.Mods.RA.Widgets.Delegates return true; }; - Game.AddChatLine += gameRoot.GetWidget("CHAT_DISPLAY").AddLine; - - - var postgameBG = gameRoot.GetWidget("POSTGAME_BG"); - var postgameText = postgameBG.GetWidget("TEXT"); - postgameBG.IsVisible = () => - { - return world.LocalPlayer != null && world.LocalPlayer.WinState != WinState.Undefined; - }; - - postgameText.GetText = () => - { - var state = world.LocalPlayer.WinState; - return (state == WinState.Undefined)? "" : - ((state == WinState.Lost)? "YOU ARE DEFEATED" : "YOU ARE VICTORIOUS"); + Game.AddChatLine += gameRoot.GetWidget("CHAT_DISPLAY").AddLine; + + + var postgameBG = gameRoot.GetWidget("POSTGAME_BG"); + var postgameText = postgameBG.GetWidget("TEXT"); + postgameBG.IsVisible = () => + { + return world.LocalPlayer != null && world.LocalPlayer.WinState != WinState.Undefined; }; - } + + postgameText.GetText = () => + { + var state = world.LocalPlayer.WinState; + return (state == WinState.Undefined)? "" : + ((state == WinState.Lost)? "YOU ARE DEFEATED" : "YOU ARE VICTORIOUS"); + }; + } } } diff --git a/OpenRA.Mods.RA/Widgets/Delegates/IngameObserverChromeDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/IngameObserverChromeDelegate.cs index 28db774303..e78f41c1a8 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/IngameObserverChromeDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/IngameObserverChromeDelegate.cs @@ -1,33 +1,33 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Traits; -using OpenRA.Widgets; - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Traits; +using OpenRA.Widgets; + namespace OpenRA.Mods.RA.Widgets.Delegates { public class IngameObserverChromeDelegate : IWidgetDelegate { - [ObjectCreator.UseCtor] + [ObjectCreator.UseCtor] public IngameObserverChromeDelegate([ObjectCreator.Param] World world) - { - var r = Widget.RootWidget; - var gameRoot = r.GetWidget("OBSERVER_ROOT"); + { + var r = Widget.RootWidget; + var gameRoot = r.GetWidget("OBSERVER_ROOT"); var optionsBG = gameRoot.GetWidget("INGAME_OPTIONS_BG"); - r.GetWidget("INGAME_OPTIONS_BUTTON").OnMouseUp = mi => { + r.GetWidget("INGAME_OPTIONS_BUTTON").OnMouseUp = mi => { optionsBG.Visible = !optionsBG.Visible; return true; }; - optionsBG.GetWidget("DISCONNECT").OnMouseUp = mi => { + optionsBG.GetWidget("DISCONNECT").OnMouseUp = mi => { optionsBG.Visible = false; Game.Disconnect(); return true; @@ -36,25 +36,25 @@ namespace OpenRA.Mods.RA.Widgets.Delegates optionsBG.GetWidget("SETTINGS").OnMouseUp = mi => { Widget.OpenWindow("SETTINGS_MENU"); return true; - }; - - optionsBG.GetWidget("MUSIC").OnMouseUp = mi => { - Widget.OpenWindow("MUSIC_MENU"); - return true; - }; - - optionsBG.GetWidget("RESUME").OnMouseUp = mi => - { - optionsBG.Visible = false; - return true; - }; - /* - optionsBG.GetWidget("SURRENDER").OnMouseUp = mi => - { - world.IssueOrder(new Order("Surrender", world.LocalPlayer.PlayerActor)); - return true; }; - */ + + optionsBG.GetWidget("MUSIC").OnMouseUp = mi => { + Widget.OpenWindow("MUSIC_MENU"); + return true; + }; + + optionsBG.GetWidget("RESUME").OnMouseUp = mi => + { + optionsBG.Visible = false; + return true; + }; + /* + optionsBG.GetWidget("SURRENDER").OnMouseUp = mi => + { + world.IssueOrder(new Order("Surrender", world.LocalPlayer.PlayerActor)); + return true; + }; + */ optionsBG.GetWidget("SURRENDER").IsVisible = () => false; optionsBG.GetWidget("QUIT").OnMouseUp = mi => { @@ -62,24 +62,24 @@ namespace OpenRA.Mods.RA.Widgets.Delegates return true; }; - Game.AddChatLine += gameRoot.GetWidget("CHAT_DISPLAY").AddLine; - - /* - var postgameBG = gameRoot.GetWidget("POSTGAME_BG"); - var postgameText = postgameBG.GetWidget("TEXT"); - postgameBG.IsVisible = () => - { - return world.LocalPlayer != null && world.LocalPlayer.WinState != WinState.Undefined; - }; - - postgameText.GetText = () => - { - if (world.LocalPlayer == null) - return ""; - var state = world.LocalPlayer.WinState; - return (state == WinState.Undefined)? "" : - ((state == WinState.Lost)? "YOU ARE DEFEATED" : "YOU ARE VICTORIOUS"); + Game.AddChatLine += gameRoot.GetWidget("CHAT_DISPLAY").AddLine; + + /* + var postgameBG = gameRoot.GetWidget("POSTGAME_BG"); + var postgameText = postgameBG.GetWidget("TEXT"); + postgameBG.IsVisible = () => + { + return world.LocalPlayer != null && world.LocalPlayer.WinState != WinState.Undefined; + }; + + postgameText.GetText = () => + { + if (world.LocalPlayer == null) + return ""; + var state = world.LocalPlayer.WinState; + return (state == WinState.Undefined)? "" : + ((state == WinState.Lost)? "YOU ARE DEFEATED" : "YOU ARE VICTORIOUS"); };*/ - } + } } } diff --git a/OpenRA.Mods.RA/Widgets/Delegates/LobbyDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/LobbyDelegate.cs index 45116bd2ed..532b7c9fba 100755 --- a/OpenRA.Mods.RA/Widgets/Delegates/LobbyDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/LobbyDelegate.cs @@ -1,467 +1,467 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Network; -using OpenRA.Traits; -using OpenRA.Widgets; -using OpenRA.Graphics; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class LobbyDelegate : IWidgetDelegate - { - Widget LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost; - ScrollPanelWidget Players; - Dictionary CountryNames; - string MapUid; - Map Map; - - public static ColorRamp CurrentColorPreview; - - readonly OrderManager orderManager; - readonly WorldRenderer worldRenderer; - [ObjectCreator.UseCtor] - internal LobbyDelegate( [ObjectCreator.Param( "widget" )] Widget lobby, [ObjectCreator.Param] OrderManager orderManager, [ObjectCreator.Param] WorldRenderer worldRenderer) - { - this.orderManager = orderManager; - this.worldRenderer = worldRenderer; - - Game.LobbyInfoChanged += UpdateCurrentMap; - UpdateCurrentMap(); - - CurrentColorPreview = Game.Settings.Player.ColorRamp; - - Players = lobby.GetWidget("PLAYERS"); - LocalPlayerTemplate = Players.GetWidget("TEMPLATE_LOCAL"); - RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE"); - EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY"); - EmptySlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_HOST"); - - var mapPreview = lobby.GetWidget("LOBBY_MAP_PREVIEW"); - mapPreview.Map = () => Map; - mapPreview.OnMouseDown = mi => - { - var map = mapPreview.Map(); - if (map == null || mi.Button != MouseButton.Left - || orderManager.LocalClient.State == Session.ClientState.Ready) - return false; - - var p = map.SpawnPoints - .Select((sp, i) => Pair.New(mapPreview.ConvertToPreview(map, sp), i)) - .Where(a => (a.First - mi.Location).LengthSquared < 64) - .Select(a => a.Second + 1) - .FirstOrDefault(); - - var owned = orderManager.LobbyInfo.Clients.Any(c => c.SpawnPoint == p); - if (p == 0 || !owned) - orderManager.IssueOrder(Order.Command("spawn {0}".F(p))); - - return true; - }; - - mapPreview.SpawnColors = () => - { - var spawns = Map.SpawnPoints; - var sc = new Dictionary(); - - for (int i = 1; i <= spawns.Count(); i++) - { - var client = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.SpawnPoint == i); - if (client == null) - continue; - sc.Add(spawns.ElementAt(i - 1), client.ColorRamp.GetColor(0)); - } - return sc; - }; - - CountryNames = Rules.Info["world"].Traits.WithInterface().ToDictionary(a => a.Race, a => a.Name); - CountryNames.Add("random", "Random"); - - var mapButton = lobby.GetWidget("CHANGEMAP_BUTTON"); - mapButton.OnMouseUp = mi => - { - Widget.OpenWindow( "MAP_CHOOSER", new Dictionary { { "orderManager", orderManager }, { "mapName", MapUid } } ); - return true; - }; - - mapButton.IsVisible = () => mapButton.Visible && Game.IsHost; - - var disconnectButton = lobby.GetWidget("DISCONNECT_BUTTON"); - disconnectButton.OnMouseUp = mi => - { - Game.Disconnect(); - return true; - }; - - var lockTeamsCheckbox = lobby.GetWidget("LOCKTEAMS_CHECKBOX"); - lockTeamsCheckbox.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.LockTeams; - lockTeamsCheckbox.OnChange += _ => - { - if (Game.IsHost) - orderManager.IssueOrder(Order.Command( - "lockteams {0}".F(!orderManager.LobbyInfo.GlobalSettings.LockTeams))); - }; - - var startGameButton = lobby.GetWidget("START_GAME_BUTTON"); - startGameButton.OnMouseUp = mi => - { - mapButton.Visible = false; - disconnectButton.Visible = false; - lockTeamsCheckbox.Visible = false; - orderManager.IssueOrder(Order.Command("startgame")); - return true; - }; - - // Todo: Only show if the map requirements are met for player slots - startGameButton.IsVisible = () => Game.IsHost; - Game.LobbyInfoChanged += UpdatePlayerList; - - Game.AddChatLine += lobby.GetWidget("CHAT_DISPLAY").AddLine; - - bool teamChat = false; - var chatLabel = lobby.GetWidget("LABEL_CHATTYPE"); - var chatTextField = lobby.GetWidget("CHAT_TEXTFIELD"); - chatTextField.OnEnterKey = () => - { - if (chatTextField.Text.Length == 0) - return true; - - var order = (teamChat) ? Order.TeamChat(chatTextField.Text) : Order.Chat(chatTextField.Text); - orderManager.IssueOrder(order); - chatTextField.Text = ""; - return true; - }; - - chatTextField.OnTabKey = () => - { - teamChat ^= true; - chatLabel.Text = (teamChat) ? "Team:" : "Chat:"; - return true; - }; - } - - void UpdatePlayerColor(float hf, float sf, float lf, float r) - { - var ramp = new ColorRamp((byte) (hf*255), (byte) (sf*255), (byte) (lf*255), (byte)(r*255)); - Game.Settings.Player.ColorRamp = ramp; - Game.Settings.Save(); - orderManager.IssueOrder(Order.Command("color {0}".F(ramp))); - } - - void UpdateColorPreview(float hf, float sf, float lf, float r) - { - CurrentColorPreview = new ColorRamp((byte)(hf * 255), (byte)(sf * 255), (byte)(lf * 255), (byte)(r * 255)); - } - - void UpdateCurrentMap() - { - if (MapUid == orderManager.LobbyInfo.GlobalSettings.Map) return; - MapUid = orderManager.LobbyInfo.GlobalSettings.Map; - Map = new Map(Game.modData.AvailableMaps[MapUid].Path); - - var title = Widget.RootWidget.GetWidget("LOBBY_TITLE"); - title.Text = "OpenRA Multiplayer Lobby - " + orderManager.LobbyInfo.GlobalSettings.ServerName; - } - - Session.Client GetClientInSlot(Session.Slot slot) - { - return orderManager.LobbyInfo.ClientInSlot( slot ); - } - - bool ShowSlotDropDown(Session.Slot slot, ButtonWidget name, bool showBotOptions) - { - var dropDownOptions = new List> - { - new Pair( "Open", - () => orderManager.IssueOrder( Order.Command( "slot_open " + slot.Index ) )), - new Pair( "Closed", - () => orderManager.IssueOrder( Order.Command( "slot_close " + slot.Index ) )), - }; - - if (showBotOptions) - { - var bots = Rules.Info["player"].Traits.WithInterface().Select(t => t.Name); - bots.Do(bot => - dropDownOptions.Add(new Pair("Bot: {0}".F(bot), - () => orderManager.IssueOrder(Order.Command("slot_bot {0} {1}".F(slot.Index, bot)))))); - } - - DropDownButtonWidget.ShowDropDown( name, - dropDownOptions, - (ac, w) => new LabelWidget - { - Bounds = new Rectangle(0, 0, w, 24), - Text = " {0}".F(ac.First), - OnMouseUp = mi => { ac.Second(); return true; }, - }); - return true; - } - - bool ShowRaceDropDown(Session.Slot s, ButtonWidget race) - { - if (Map.Players[s.MapPlayer].LockRace) - return false; - - var dropDownOptions = new List>(); - foreach (var c in CountryNames) - { - var cc = c; - dropDownOptions.Add(new Pair( cc.Key, - () => orderManager.IssueOrder( Order.Command("race "+cc.Key) )) ); - }; - - DropDownButtonWidget.ShowDropDown( race, - dropDownOptions, - (ac, w) => - { - var ret = new LabelWidget - { - Bounds = new Rectangle(0, 0, w, 24), - Text = " {0}".F(CountryNames[ac.First]), - OnMouseUp = mi => { ac.Second(); return true; }, - }; - - ret.AddChild(new ImageWidget - { - Bounds = new Rectangle(5, 5, 40, 15), - GetImageName = () => ac.First, - GetImageCollection = () => "flags", - }); - return ret; - }); - return true; - } - - bool ShowTeamDropDown(ButtonWidget team) - { - var dropDownOptions = new List>(); - for (int i = 0; i <= Map.PlayerCount; i++) - { - var ii = i; - dropDownOptions.Add(new Pair( ii == 0 ? "-" : ii.ToString(), - () => orderManager.IssueOrder( Order.Command("team "+ii) )) ); - }; - - DropDownButtonWidget.ShowDropDown( team, - dropDownOptions, - (ac, w) => new LabelWidget - { - Bounds = new Rectangle(0, 0, w, 24), - Text = " {0}".F(ac.First), - OnMouseUp = mi => { ac.Second(); return true; }, - }); - return true; - } - - bool ShowColorDropDown(Session.Slot s, ButtonWidget color) - { - if (Map.Players[s.MapPlayer].LockColor) - return false; - - var colorChooser = Game.modData.WidgetLoader.LoadWidget( new Dictionary() { {"worldRenderer", worldRenderer} }, null, "COLOR_CHOOSER" ); - var hueSlider = colorChooser.GetWidget("HUE_SLIDER"); - hueSlider.SetOffset(orderManager.LocalClient.ColorRamp.H / 255f); - - var satSlider = colorChooser.GetWidget("SAT_SLIDER"); - satSlider.SetOffset(orderManager.LocalClient.ColorRamp.S / 255f); - - var lumSlider = colorChooser.GetWidget("LUM_SLIDER"); - lumSlider.SetOffset(orderManager.LocalClient.ColorRamp.L / 255f); - - var rangeSlider = colorChooser.GetWidget("RANGE_SLIDER"); - rangeSlider.SetOffset(orderManager.LocalClient.ColorRamp.R / 255f); - - hueSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); - satSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); - lumSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); - rangeSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); - UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); - - DropDownButtonWidget.ShowDropPanel(color, colorChooser, new List() {colorChooser.GetWidget("BUTTON_OK")}, () => { - UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); - UpdatePlayerColor(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); - return true; - }); - return true; - } - - void UpdatePlayerList() - { - // This causes problems for people who are in the process of editing their names (the widgets vanish from beneath them) - // Todo: handle this nicer - Players.RemoveChildren(); - - foreach (var slot in orderManager.LobbyInfo.Slots) - { - var s = slot; - var c = GetClientInSlot(s); - Widget template; - - if (c == null) - { - if (Game.IsHost) - { - if (slot.Spectator) - { - template = EmptySlotTemplateHost.Clone(); - var name = template.GetWidget("NAME"); - name.GetText = () => s.Closed ? "Closed" : "Open"; - name.OnMouseDown = _ => ShowSlotDropDown(s, name, false); - var btn = template.GetWidget("JOIN"); - btn.GetText = () => "Spectate in this slot"; - } - else - { - template = EmptySlotTemplateHost.Clone(); - var name = template.GetWidget("NAME"); - name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot; - name.OnMouseDown = _ => ShowSlotDropDown(s, name, Map.Players[ s.MapPlayer ].AllowBots); - } - } - else - { - template = EmptySlotTemplate.Clone(); - var name = template.GetWidget("NAME"); - name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot; - - if (slot.Spectator) - { - var btn = template.GetWidget("JOIN"); - btn.GetText = () => "Spectate in this slot"; - } - } - - var join = template.GetWidget("JOIN"); - if (join != null) - { - join.OnMouseUp = _ => { orderManager.IssueOrder(Order.Command("slot " + s.Index)); return true; }; - join.IsVisible = () => !s.Closed && s.Bot == null && orderManager.LocalClient.State != Session.ClientState.Ready; - } - - var bot = template.GetWidget("BOT"); - if (bot != null) - bot.IsVisible = () => s.Bot != null; - } - else if (c.Index == orderManager.LocalClient.Index && c.State != Session.ClientState.Ready) - { - template = LocalPlayerTemplate.Clone(); - var name = template.GetWidget("NAME"); - name.Text = c.Name; - name.OnEnterKey = () => - { - name.Text = name.Text.Trim(); - if (name.Text.Length == 0) - name.Text = c.Name; - - name.LoseFocus(); - if (name.Text == c.Name) - return true; - - orderManager.IssueOrder(Order.Command("name " + name.Text)); - Game.Settings.Player.Name = name.Text; - Game.Settings.Save(); - return true; - }; - name.OnLoseFocus = () => name.OnEnterKey(); - - var color = template.GetWidget("COLOR"); - color.OnMouseUp = _ => ShowColorDropDown(s, color); - - var colorBlock = color.GetWidget("COLORBLOCK"); - colorBlock.GetColor = () => c.ColorRamp.GetColor(0); - - var faction = template.GetWidget("FACTION"); - faction.OnMouseDown = _ => ShowRaceDropDown(s, faction); - - var factionname = faction.GetWidget("FACTIONNAME"); - factionname.GetText = () => CountryNames[c.Country]; - var factionflag = faction.GetWidget("FACTIONFLAG"); - factionflag.GetImageName = () => c.Country; - factionflag.GetImageCollection = () => "flags"; - - var team = template.GetWidget("TEAM"); - team.OnMouseDown = _ => ShowTeamDropDown(team); - team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString(); - - var status = template.GetWidget("STATUS"); - status.IsChecked = () => c.State == Session.ClientState.Ready; - status.OnChange += CycleReady; - - var spectator = template.GetWidget("SPECTATOR"); - - Session.Slot slot1 = slot; - color.IsVisible = () => !slot1.Spectator; - colorBlock.IsVisible = () => !slot1.Spectator; - faction.IsVisible = () => !slot1.Spectator; - factionname.IsVisible = () => !slot1.Spectator; - factionflag.IsVisible = () => !slot1.Spectator; - team.IsVisible = () => !slot1.Spectator; - spectator.IsVisible = () => slot1.Spectator || slot1.Bot != null; - } - else - { - template = RemotePlayerTemplate.Clone(); - template.GetWidget("NAME").GetText = () => c.Name; - var color = template.GetWidget("COLOR"); - color.GetColor = () => c.ColorRamp.GetColor(0); - - var faction = template.GetWidget("FACTION"); - var factionname = faction.GetWidget("FACTIONNAME"); - factionname.GetText = () => CountryNames[c.Country]; - var factionflag = faction.GetWidget("FACTIONFLAG"); - factionflag.GetImageName = () => c.Country; - factionflag.GetImageCollection = () => "flags"; - - var team = template.GetWidget("TEAM"); - team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString(); - - var status = template.GetWidget("STATUS"); - status.IsChecked = () => c.State == Session.ClientState.Ready; - if (c.Index == orderManager.LocalClient.Index) - status.OnChange += CycleReady; - - var spectator = template.GetWidget("SPECTATOR"); - - Session.Slot slot1 = slot; - color.IsVisible = () => !slot1.Spectator; - faction.IsVisible = () => !slot1.Spectator; - factionname.IsVisible = () => !slot1.Spectator; - factionflag.IsVisible = () => !slot1.Spectator; - team.IsVisible = () => !slot1.Spectator; - spectator.IsVisible = () => slot1.Spectator || slot1.Bot != null; - - var kickButton = template.GetWidget("KICK"); - kickButton.IsVisible = () => Game.IsHost && c.Index != orderManager.LocalClient.Index; - kickButton.OnMouseUp = mi => - { - orderManager.IssueOrder(Order.Command("kick " + c.Slot)); - return true; - }; - } - - template.Id = "SLOT_{0}".F(s.Index); - template.IsVisible = () => true; - Players.AddChild(template); - } - } - - bool SpawnPointAvailable(int index) { return (index == 0) || orderManager.LobbyInfo.Clients.All(c => c.SpawnPoint != index); } - - void CycleReady(bool ready) - { - orderManager.IssueOrder(Order.Command("ready")); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Network; +using OpenRA.Traits; +using OpenRA.Widgets; +using OpenRA.Graphics; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class LobbyDelegate : IWidgetDelegate + { + Widget LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost; + ScrollPanelWidget Players; + Dictionary CountryNames; + string MapUid; + Map Map; + + public static ColorRamp CurrentColorPreview; + + readonly OrderManager orderManager; + readonly WorldRenderer worldRenderer; + [ObjectCreator.UseCtor] + internal LobbyDelegate( [ObjectCreator.Param( "widget" )] Widget lobby, [ObjectCreator.Param] OrderManager orderManager, [ObjectCreator.Param] WorldRenderer worldRenderer) + { + this.orderManager = orderManager; + this.worldRenderer = worldRenderer; + + Game.LobbyInfoChanged += UpdateCurrentMap; + UpdateCurrentMap(); + + CurrentColorPreview = Game.Settings.Player.ColorRamp; + + Players = lobby.GetWidget("PLAYERS"); + LocalPlayerTemplate = Players.GetWidget("TEMPLATE_LOCAL"); + RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE"); + EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY"); + EmptySlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_HOST"); + + var mapPreview = lobby.GetWidget("LOBBY_MAP_PREVIEW"); + mapPreview.Map = () => Map; + mapPreview.OnMouseDown = mi => + { + var map = mapPreview.Map(); + if (map == null || mi.Button != MouseButton.Left + || orderManager.LocalClient.State == Session.ClientState.Ready) + return false; + + var p = map.SpawnPoints + .Select((sp, i) => Pair.New(mapPreview.ConvertToPreview(map, sp), i)) + .Where(a => (a.First - mi.Location).LengthSquared < 64) + .Select(a => a.Second + 1) + .FirstOrDefault(); + + var owned = orderManager.LobbyInfo.Clients.Any(c => c.SpawnPoint == p); + if (p == 0 || !owned) + orderManager.IssueOrder(Order.Command("spawn {0}".F(p))); + + return true; + }; + + mapPreview.SpawnColors = () => + { + var spawns = Map.SpawnPoints; + var sc = new Dictionary(); + + for (int i = 1; i <= spawns.Count(); i++) + { + var client = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.SpawnPoint == i); + if (client == null) + continue; + sc.Add(spawns.ElementAt(i - 1), client.ColorRamp.GetColor(0)); + } + return sc; + }; + + CountryNames = Rules.Info["world"].Traits.WithInterface().ToDictionary(a => a.Race, a => a.Name); + CountryNames.Add("random", "Random"); + + var mapButton = lobby.GetWidget("CHANGEMAP_BUTTON"); + mapButton.OnMouseUp = mi => + { + Widget.OpenWindow( "MAP_CHOOSER", new Dictionary { { "orderManager", orderManager }, { "mapName", MapUid } } ); + return true; + }; + + mapButton.IsVisible = () => mapButton.Visible && Game.IsHost; + + var disconnectButton = lobby.GetWidget("DISCONNECT_BUTTON"); + disconnectButton.OnMouseUp = mi => + { + Game.Disconnect(); + return true; + }; + + var lockTeamsCheckbox = lobby.GetWidget("LOCKTEAMS_CHECKBOX"); + lockTeamsCheckbox.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.LockTeams; + lockTeamsCheckbox.OnChange += _ => + { + if (Game.IsHost) + orderManager.IssueOrder(Order.Command( + "lockteams {0}".F(!orderManager.LobbyInfo.GlobalSettings.LockTeams))); + }; + + var startGameButton = lobby.GetWidget("START_GAME_BUTTON"); + startGameButton.OnMouseUp = mi => + { + mapButton.Visible = false; + disconnectButton.Visible = false; + lockTeamsCheckbox.Visible = false; + orderManager.IssueOrder(Order.Command("startgame")); + return true; + }; + + // Todo: Only show if the map requirements are met for player slots + startGameButton.IsVisible = () => Game.IsHost; + Game.LobbyInfoChanged += UpdatePlayerList; + + Game.AddChatLine += lobby.GetWidget("CHAT_DISPLAY").AddLine; + + bool teamChat = false; + var chatLabel = lobby.GetWidget("LABEL_CHATTYPE"); + var chatTextField = lobby.GetWidget("CHAT_TEXTFIELD"); + chatTextField.OnEnterKey = () => + { + if (chatTextField.Text.Length == 0) + return true; + + var order = (teamChat) ? Order.TeamChat(chatTextField.Text) : Order.Chat(chatTextField.Text); + orderManager.IssueOrder(order); + chatTextField.Text = ""; + return true; + }; + + chatTextField.OnTabKey = () => + { + teamChat ^= true; + chatLabel.Text = (teamChat) ? "Team:" : "Chat:"; + return true; + }; + } + + void UpdatePlayerColor(float hf, float sf, float lf, float r) + { + var ramp = new ColorRamp((byte) (hf*255), (byte) (sf*255), (byte) (lf*255), (byte)(r*255)); + Game.Settings.Player.ColorRamp = ramp; + Game.Settings.Save(); + orderManager.IssueOrder(Order.Command("color {0}".F(ramp))); + } + + void UpdateColorPreview(float hf, float sf, float lf, float r) + { + CurrentColorPreview = new ColorRamp((byte)(hf * 255), (byte)(sf * 255), (byte)(lf * 255), (byte)(r * 255)); + } + + void UpdateCurrentMap() + { + if (MapUid == orderManager.LobbyInfo.GlobalSettings.Map) return; + MapUid = orderManager.LobbyInfo.GlobalSettings.Map; + Map = new Map(Game.modData.AvailableMaps[MapUid].Path); + + var title = Widget.RootWidget.GetWidget("LOBBY_TITLE"); + title.Text = "OpenRA Multiplayer Lobby - " + orderManager.LobbyInfo.GlobalSettings.ServerName; + } + + Session.Client GetClientInSlot(Session.Slot slot) + { + return orderManager.LobbyInfo.ClientInSlot( slot ); + } + + bool ShowSlotDropDown(Session.Slot slot, ButtonWidget name, bool showBotOptions) + { + var dropDownOptions = new List> + { + new Pair( "Open", + () => orderManager.IssueOrder( Order.Command( "slot_open " + slot.Index ) )), + new Pair( "Closed", + () => orderManager.IssueOrder( Order.Command( "slot_close " + slot.Index ) )), + }; + + if (showBotOptions) + { + var bots = Rules.Info["player"].Traits.WithInterface().Select(t => t.Name); + bots.Do(bot => + dropDownOptions.Add(new Pair("Bot: {0}".F(bot), + () => orderManager.IssueOrder(Order.Command("slot_bot {0} {1}".F(slot.Index, bot)))))); + } + + DropDownButtonWidget.ShowDropDown( name, + dropDownOptions, + (ac, w) => new LabelWidget + { + Bounds = new Rectangle(0, 0, w, 24), + Text = " {0}".F(ac.First), + OnMouseUp = mi => { ac.Second(); return true; }, + }); + return true; + } + + bool ShowRaceDropDown(Session.Slot s, ButtonWidget race) + { + if (Map.Players[s.MapPlayer].LockRace) + return false; + + var dropDownOptions = new List>(); + foreach (var c in CountryNames) + { + var cc = c; + dropDownOptions.Add(new Pair( cc.Key, + () => orderManager.IssueOrder( Order.Command("race "+cc.Key) )) ); + }; + + DropDownButtonWidget.ShowDropDown( race, + dropDownOptions, + (ac, w) => + { + var ret = new LabelWidget + { + Bounds = new Rectangle(0, 0, w, 24), + Text = " {0}".F(CountryNames[ac.First]), + OnMouseUp = mi => { ac.Second(); return true; }, + }; + + ret.AddChild(new ImageWidget + { + Bounds = new Rectangle(5, 5, 40, 15), + GetImageName = () => ac.First, + GetImageCollection = () => "flags", + }); + return ret; + }); + return true; + } + + bool ShowTeamDropDown(ButtonWidget team) + { + var dropDownOptions = new List>(); + for (int i = 0; i <= Map.PlayerCount; i++) + { + var ii = i; + dropDownOptions.Add(new Pair( ii == 0 ? "-" : ii.ToString(), + () => orderManager.IssueOrder( Order.Command("team "+ii) )) ); + }; + + DropDownButtonWidget.ShowDropDown( team, + dropDownOptions, + (ac, w) => new LabelWidget + { + Bounds = new Rectangle(0, 0, w, 24), + Text = " {0}".F(ac.First), + OnMouseUp = mi => { ac.Second(); return true; }, + }); + return true; + } + + bool ShowColorDropDown(Session.Slot s, ButtonWidget color) + { + if (Map.Players[s.MapPlayer].LockColor) + return false; + + var colorChooser = Game.modData.WidgetLoader.LoadWidget( new Dictionary() { {"worldRenderer", worldRenderer} }, null, "COLOR_CHOOSER" ); + var hueSlider = colorChooser.GetWidget("HUE_SLIDER"); + hueSlider.SetOffset(orderManager.LocalClient.ColorRamp.H / 255f); + + var satSlider = colorChooser.GetWidget("SAT_SLIDER"); + satSlider.SetOffset(orderManager.LocalClient.ColorRamp.S / 255f); + + var lumSlider = colorChooser.GetWidget("LUM_SLIDER"); + lumSlider.SetOffset(orderManager.LocalClient.ColorRamp.L / 255f); + + var rangeSlider = colorChooser.GetWidget("RANGE_SLIDER"); + rangeSlider.SetOffset(orderManager.LocalClient.ColorRamp.R / 255f); + + hueSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); + satSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); + lumSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); + rangeSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); + UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); + + DropDownButtonWidget.ShowDropPanel(color, colorChooser, new List() {colorChooser.GetWidget("BUTTON_OK")}, () => { + UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); + UpdatePlayerColor(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset()); + return true; + }); + return true; + } + + void UpdatePlayerList() + { + // This causes problems for people who are in the process of editing their names (the widgets vanish from beneath them) + // Todo: handle this nicer + Players.RemoveChildren(); + + foreach (var slot in orderManager.LobbyInfo.Slots) + { + var s = slot; + var c = GetClientInSlot(s); + Widget template; + + if (c == null) + { + if (Game.IsHost) + { + if (slot.Spectator) + { + template = EmptySlotTemplateHost.Clone(); + var name = template.GetWidget("NAME"); + name.GetText = () => s.Closed ? "Closed" : "Open"; + name.OnMouseDown = _ => ShowSlotDropDown(s, name, false); + var btn = template.GetWidget("JOIN"); + btn.GetText = () => "Spectate in this slot"; + } + else + { + template = EmptySlotTemplateHost.Clone(); + var name = template.GetWidget("NAME"); + name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot; + name.OnMouseDown = _ => ShowSlotDropDown(s, name, Map.Players[ s.MapPlayer ].AllowBots); + } + } + else + { + template = EmptySlotTemplate.Clone(); + var name = template.GetWidget("NAME"); + name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot; + + if (slot.Spectator) + { + var btn = template.GetWidget("JOIN"); + btn.GetText = () => "Spectate in this slot"; + } + } + + var join = template.GetWidget("JOIN"); + if (join != null) + { + join.OnMouseUp = _ => { orderManager.IssueOrder(Order.Command("slot " + s.Index)); return true; }; + join.IsVisible = () => !s.Closed && s.Bot == null && orderManager.LocalClient.State != Session.ClientState.Ready; + } + + var bot = template.GetWidget("BOT"); + if (bot != null) + bot.IsVisible = () => s.Bot != null; + } + else if (c.Index == orderManager.LocalClient.Index && c.State != Session.ClientState.Ready) + { + template = LocalPlayerTemplate.Clone(); + var name = template.GetWidget("NAME"); + name.Text = c.Name; + name.OnEnterKey = () => + { + name.Text = name.Text.Trim(); + if (name.Text.Length == 0) + name.Text = c.Name; + + name.LoseFocus(); + if (name.Text == c.Name) + return true; + + orderManager.IssueOrder(Order.Command("name " + name.Text)); + Game.Settings.Player.Name = name.Text; + Game.Settings.Save(); + return true; + }; + name.OnLoseFocus = () => name.OnEnterKey(); + + var color = template.GetWidget("COLOR"); + color.OnMouseUp = _ => ShowColorDropDown(s, color); + + var colorBlock = color.GetWidget("COLORBLOCK"); + colorBlock.GetColor = () => c.ColorRamp.GetColor(0); + + var faction = template.GetWidget("FACTION"); + faction.OnMouseDown = _ => ShowRaceDropDown(s, faction); + + var factionname = faction.GetWidget("FACTIONNAME"); + factionname.GetText = () => CountryNames[c.Country]; + var factionflag = faction.GetWidget("FACTIONFLAG"); + factionflag.GetImageName = () => c.Country; + factionflag.GetImageCollection = () => "flags"; + + var team = template.GetWidget("TEAM"); + team.OnMouseDown = _ => ShowTeamDropDown(team); + team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString(); + + var status = template.GetWidget("STATUS"); + status.IsChecked = () => c.State == Session.ClientState.Ready; + status.OnChange += CycleReady; + + var spectator = template.GetWidget("SPECTATOR"); + + Session.Slot slot1 = slot; + color.IsVisible = () => !slot1.Spectator; + colorBlock.IsVisible = () => !slot1.Spectator; + faction.IsVisible = () => !slot1.Spectator; + factionname.IsVisible = () => !slot1.Spectator; + factionflag.IsVisible = () => !slot1.Spectator; + team.IsVisible = () => !slot1.Spectator; + spectator.IsVisible = () => slot1.Spectator || slot1.Bot != null; + } + else + { + template = RemotePlayerTemplate.Clone(); + template.GetWidget("NAME").GetText = () => c.Name; + var color = template.GetWidget("COLOR"); + color.GetColor = () => c.ColorRamp.GetColor(0); + + var faction = template.GetWidget("FACTION"); + var factionname = faction.GetWidget("FACTIONNAME"); + factionname.GetText = () => CountryNames[c.Country]; + var factionflag = faction.GetWidget("FACTIONFLAG"); + factionflag.GetImageName = () => c.Country; + factionflag.GetImageCollection = () => "flags"; + + var team = template.GetWidget("TEAM"); + team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString(); + + var status = template.GetWidget("STATUS"); + status.IsChecked = () => c.State == Session.ClientState.Ready; + if (c.Index == orderManager.LocalClient.Index) + status.OnChange += CycleReady; + + var spectator = template.GetWidget("SPECTATOR"); + + Session.Slot slot1 = slot; + color.IsVisible = () => !slot1.Spectator; + faction.IsVisible = () => !slot1.Spectator; + factionname.IsVisible = () => !slot1.Spectator; + factionflag.IsVisible = () => !slot1.Spectator; + team.IsVisible = () => !slot1.Spectator; + spectator.IsVisible = () => slot1.Spectator || slot1.Bot != null; + + var kickButton = template.GetWidget("KICK"); + kickButton.IsVisible = () => Game.IsHost && c.Index != orderManager.LocalClient.Index; + kickButton.OnMouseUp = mi => + { + orderManager.IssueOrder(Order.Command("kick " + c.Slot)); + return true; + }; + } + + template.Id = "SLOT_{0}".F(s.Index); + template.IsVisible = () => true; + Players.AddChild(template); + } + } + + bool SpawnPointAvailable(int index) { return (index == 0) || orderManager.LobbyInfo.Clients.All(c => c.SpawnPoint != index); } + + void CycleReady(bool ready) + { + orderManager.IssueOrder(Order.Command("ready")); + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Delegates/MainMenuButtonsDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/MainMenuButtonsDelegate.cs index 51c4bd8297..034e5116e0 100755 --- a/OpenRA.Mods.RA/Widgets/Delegates/MainMenuButtonsDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/MainMenuButtonsDelegate.cs @@ -1,90 +1,90 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.FileFormats; -using OpenRA.Network; -using OpenRA.Server; -using OpenRA.Widgets; -using System; -using System.Drawing; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class MainMenuButtonsDelegate : IWidgetDelegate - { - [ObjectCreator.UseCtor] - public MainMenuButtonsDelegate([ObjectCreator.Param] Widget widget) - { - Game.modData.WidgetLoader.LoadWidget( new Dictionary(), Widget.RootWidget, "PERF_BG" ); - widget.GetWidget("MAINMENU_BUTTON_JOIN").OnMouseUp = mi => { Widget.OpenWindow("JOINSERVER_BG"); return true; }; - widget.GetWidget("MAINMENU_BUTTON_CREATE").OnMouseUp = mi => { Widget.OpenWindow("CREATESERVER_BG"); return true; }; - widget.GetWidget("MAINMENU_BUTTON_SETTINGS").OnMouseUp = mi => { Widget.OpenWindow("SETTINGS_MENU"); return true; }; - widget.GetWidget("MAINMENU_BUTTON_MUSIC").OnMouseUp = mi => { Widget.OpenWindow("MUSIC_MENU"); return true; }; - widget.GetWidget("MAINMENU_BUTTON_REPLAY_VIEWER").OnMouseUp = mi => { Widget.OpenWindow("REPLAYBROWSER_BG"); return true; }; - widget.GetWidget("MAINMENU_BUTTON_QUIT").OnMouseUp = mi => { Game.Exit(); return true; }; - - DisplayModSelector(); - } - - public static void DisplayModSelector() - { - var selector = Game.modData.WidgetLoader.LoadWidget( new Dictionary(), Widget.RootWidget, "QUICKMODSWITCHER" ); - var switcher = selector.GetWidget("SWITCHER"); - switcher.OnMouseDown = _ => ShowModsDropDown(switcher); - switcher.GetText = ActiveModTitle; - selector.GetWidget("VERSION").GetText = ActiveModVersion; - } - - - static string ActiveModTitle() - { - var mod = Game.modData.Manifest.Mods[0]; - return Mod.AllMods[mod].Title; - } - - static string ActiveModVersion() - { - var mod = Game.modData.Manifest.Mods[0]; - return Mod.AllMods[mod].Version; - } - - static bool ShowModsDropDown(ButtonWidget selector) - { - var dropDownOptions = new List>(); - - foreach (var kv in Mod.AllMods) - { - var modList = new List() { kv.Key }; - var m = kv.Key; - while (!string.IsNullOrEmpty(Mod.AllMods[m].Requires)) - { - m = Mod.AllMods[m].Requires; - modList.Add(m); - } - - dropDownOptions.Add(new Pair( kv.Value.Title, - () => Game.RunAfterTick(() => Game.InitializeWithMods( modList.ToArray() ) ))); - } - - DropDownButtonWidget.ShowDropDown( selector, - dropDownOptions, - (ac, w) => new LabelWidget - { - Bounds = new Rectangle(0, 0, w, 24), - Text = " {0}".F(ac.First), - OnMouseUp = mi => { ac.Second(); return true; }, - }); - return true; - } - - } - -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.FileFormats; +using OpenRA.Network; +using OpenRA.Server; +using OpenRA.Widgets; +using System; +using System.Drawing; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class MainMenuButtonsDelegate : IWidgetDelegate + { + [ObjectCreator.UseCtor] + public MainMenuButtonsDelegate([ObjectCreator.Param] Widget widget) + { + Game.modData.WidgetLoader.LoadWidget( new Dictionary(), Widget.RootWidget, "PERF_BG" ); + widget.GetWidget("MAINMENU_BUTTON_JOIN").OnMouseUp = mi => { Widget.OpenWindow("JOINSERVER_BG"); return true; }; + widget.GetWidget("MAINMENU_BUTTON_CREATE").OnMouseUp = mi => { Widget.OpenWindow("CREATESERVER_BG"); return true; }; + widget.GetWidget("MAINMENU_BUTTON_SETTINGS").OnMouseUp = mi => { Widget.OpenWindow("SETTINGS_MENU"); return true; }; + widget.GetWidget("MAINMENU_BUTTON_MUSIC").OnMouseUp = mi => { Widget.OpenWindow("MUSIC_MENU"); return true; }; + widget.GetWidget("MAINMENU_BUTTON_REPLAY_VIEWER").OnMouseUp = mi => { Widget.OpenWindow("REPLAYBROWSER_BG"); return true; }; + widget.GetWidget("MAINMENU_BUTTON_QUIT").OnMouseUp = mi => { Game.Exit(); return true; }; + + DisplayModSelector(); + } + + public static void DisplayModSelector() + { + var selector = Game.modData.WidgetLoader.LoadWidget( new Dictionary(), Widget.RootWidget, "QUICKMODSWITCHER" ); + var switcher = selector.GetWidget("SWITCHER"); + switcher.OnMouseDown = _ => ShowModsDropDown(switcher); + switcher.GetText = ActiveModTitle; + selector.GetWidget("VERSION").GetText = ActiveModVersion; + } + + + static string ActiveModTitle() + { + var mod = Game.modData.Manifest.Mods[0]; + return Mod.AllMods[mod].Title; + } + + static string ActiveModVersion() + { + var mod = Game.modData.Manifest.Mods[0]; + return Mod.AllMods[mod].Version; + } + + static bool ShowModsDropDown(ButtonWidget selector) + { + var dropDownOptions = new List>(); + + foreach (var kv in Mod.AllMods) + { + var modList = new List() { kv.Key }; + var m = kv.Key; + while (!string.IsNullOrEmpty(Mod.AllMods[m].Requires)) + { + m = Mod.AllMods[m].Requires; + modList.Add(m); + } + + dropDownOptions.Add(new Pair( kv.Value.Title, + () => Game.RunAfterTick(() => Game.InitializeWithMods( modList.ToArray() ) ))); + } + + DropDownButtonWidget.ShowDropDown( selector, + dropDownOptions, + (ac, w) => new LabelWidget + { + Bounds = new Rectangle(0, 0, w, 24), + Text = " {0}".F(ac.First), + OnMouseUp = mi => { ac.Second(); return true; }, + }); + return true; + } + + } + +} diff --git a/OpenRA.Mods.RA/Widgets/Delegates/MapChooserDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/MapChooserDelegate.cs index 41ac16ed24..801f385abd 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/MapChooserDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/MapChooserDelegate.cs @@ -1,116 +1,116 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + using System.Drawing; using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Network; -using OpenRA.Widgets; -using System.IO; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class MapChooserDelegate : IWidgetDelegate - { - Map Map = null; - Widget scrollpanel; - Widget itemTemplate; - - [ObjectCreator.UseCtor] - internal MapChooserDelegate( - [ObjectCreator.Param( "widget" )] Widget bg, - [ObjectCreator.Param] OrderManager orderManager, - [ObjectCreator.Param] string mapName ) - { - if (mapName != null) - Map = Game.modData.AvailableMaps[mapName]; - else - Map = Game.modData.AvailableMaps.FirstOrDefault(m => m.Value.Selectable).Value; - - bg.GetWidget("MAPCHOOSER_MAP_PREVIEW").Map = () => Map; - bg.GetWidget("CURMAP_TITLE").GetText = () => Map.Title; - bg.GetWidget("CURMAP_AUTHOR").GetText = () => Map.Author; - bg.GetWidget("CURMAP_DESC").GetText = () => Map.Description; - bg.GetWidget("CURMAP_DESC_LABEL").IsVisible = () => Map.Description != null; - bg.GetWidget("CURMAP_SIZE").GetText = () => "{0}x{1}".F(Map.Bounds.Width, Map.Bounds.Height); - bg.GetWidget("CURMAP_THEATER").GetText = () => Rules.TileSets[Map.Tileset].Name; - bg.GetWidget("CURMAP_PLAYERS").GetText = () => Map.PlayerCount.ToString(); - - bg.GetWidget("BUTTON_OK").OnMouseUp = mi => - { - orderManager.IssueOrder(Order.Command("map " + Map.Uid)); - Widget.CloseWindow(); - return true; - }; - - bg.GetWidget("BUTTON_CANCEL").OnMouseUp = mi => - { - Widget.CloseWindow(); - return true; - }; - - bg.GetWidget("BUTTON_INSTALL").IsVisible = () => false; - //bg.GetWidget("BUTTON_INSTALL").OnMouseUp = mi => InstallMap(); - scrollpanel = bg.GetWidget("MAP_LIST"); - itemTemplate = scrollpanel.GetWidget("MAP_TEMPLATE"); - EnumerateMaps(); - } - - void EnumerateMaps() - { - scrollpanel.RemoveChildren(); - foreach (var kv in Game.modData.AvailableMaps.OrderBy(kv => kv.Value.Title).OrderBy(kv => kv.Value.PlayerCount)) - { - var map = kv.Value; - if (!map.Selectable) - continue; - - var template = itemTemplate.Clone() as ContainerWidget; - template.Id = "MAP_{0}".F(map.Uid); - template.GetBackground = () => ((Map == map) ? "dialog2" : null); - template.OnMouseDown = mi => { if (mi.Button != MouseButton.Left) return false; Map = map; return true; }; - template.IsVisible = () => true; - template.GetWidget("TITLE").GetText = () => map.Title; - template.GetWidget("PLAYERS").GetText = () => "{0}".F(map.PlayerCount); - template.GetWidget("TYPE").GetText = () => map.Type; - scrollpanel.AddChild(template); - } - } - - bool InstallMap() - { - Game.Utilities.PromptFilepathAsync("Select an OpenRA map file", path => - { - if (!string.IsNullOrEmpty(path)) - Game.RunAfterTick(() => InstallMapInner(path)); - }); - return true; - } - - void InstallMapInner(string path) - { - var toPath = "{0}{1}maps{1}{2}{1}{3}" - .F(Game.SupportDir,Path.DirectorySeparatorChar, - Game.modData.Manifest.Mods[0], - Path.GetFileName(path)); - - // Create directory if required - var dir = Path.GetDirectoryName(toPath); - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); - - // TODO: Attempt to mount the map and verify that - // it is a valid Game.modData.Manifest.Mods[0] map. - File.Copy(path, toPath, true); - Game.modData.ReloadMaps(); - EnumerateMaps(); - } - } +using OpenRA.FileFormats; +using OpenRA.Network; +using OpenRA.Widgets; +using System.IO; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class MapChooserDelegate : IWidgetDelegate + { + Map Map = null; + Widget scrollpanel; + Widget itemTemplate; + + [ObjectCreator.UseCtor] + internal MapChooserDelegate( + [ObjectCreator.Param( "widget" )] Widget bg, + [ObjectCreator.Param] OrderManager orderManager, + [ObjectCreator.Param] string mapName ) + { + if (mapName != null) + Map = Game.modData.AvailableMaps[mapName]; + else + Map = Game.modData.AvailableMaps.FirstOrDefault(m => m.Value.Selectable).Value; + + bg.GetWidget("MAPCHOOSER_MAP_PREVIEW").Map = () => Map; + bg.GetWidget("CURMAP_TITLE").GetText = () => Map.Title; + bg.GetWidget("CURMAP_AUTHOR").GetText = () => Map.Author; + bg.GetWidget("CURMAP_DESC").GetText = () => Map.Description; + bg.GetWidget("CURMAP_DESC_LABEL").IsVisible = () => Map.Description != null; + bg.GetWidget("CURMAP_SIZE").GetText = () => "{0}x{1}".F(Map.Bounds.Width, Map.Bounds.Height); + bg.GetWidget("CURMAP_THEATER").GetText = () => Rules.TileSets[Map.Tileset].Name; + bg.GetWidget("CURMAP_PLAYERS").GetText = () => Map.PlayerCount.ToString(); + + bg.GetWidget("BUTTON_OK").OnMouseUp = mi => + { + orderManager.IssueOrder(Order.Command("map " + Map.Uid)); + Widget.CloseWindow(); + return true; + }; + + bg.GetWidget("BUTTON_CANCEL").OnMouseUp = mi => + { + Widget.CloseWindow(); + return true; + }; + + bg.GetWidget("BUTTON_INSTALL").IsVisible = () => false; + //bg.GetWidget("BUTTON_INSTALL").OnMouseUp = mi => InstallMap(); + scrollpanel = bg.GetWidget("MAP_LIST"); + itemTemplate = scrollpanel.GetWidget("MAP_TEMPLATE"); + EnumerateMaps(); + } + + void EnumerateMaps() + { + scrollpanel.RemoveChildren(); + foreach (var kv in Game.modData.AvailableMaps.OrderBy(kv => kv.Value.Title).OrderBy(kv => kv.Value.PlayerCount)) + { + var map = kv.Value; + if (!map.Selectable) + continue; + + var template = itemTemplate.Clone() as ContainerWidget; + template.Id = "MAP_{0}".F(map.Uid); + template.GetBackground = () => ((Map == map) ? "dialog2" : null); + template.OnMouseDown = mi => { if (mi.Button != MouseButton.Left) return false; Map = map; return true; }; + template.IsVisible = () => true; + template.GetWidget("TITLE").GetText = () => map.Title; + template.GetWidget("PLAYERS").GetText = () => "{0}".F(map.PlayerCount); + template.GetWidget("TYPE").GetText = () => map.Type; + scrollpanel.AddChild(template); + } + } + + bool InstallMap() + { + Game.Utilities.PromptFilepathAsync("Select an OpenRA map file", path => + { + if (!string.IsNullOrEmpty(path)) + Game.RunAfterTick(() => InstallMapInner(path)); + }); + return true; + } + + void InstallMapInner(string path) + { + var toPath = "{0}{1}maps{1}{2}{1}{3}" + .F(Game.SupportDir,Path.DirectorySeparatorChar, + Game.modData.Manifest.Mods[0], + Path.GetFileName(path)); + + // Create directory if required + var dir = Path.GetDirectoryName(toPath); + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + + // TODO: Attempt to mount the map and verify that + // it is a valid Game.modData.Manifest.Mods[0] map. + File.Copy(path, toPath, true); + Game.modData.ReloadMaps(); + EnumerateMaps(); + } + } } diff --git a/OpenRA.Mods.RA/Widgets/Delegates/MusicPlayerDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/MusicPlayerDelegate.cs index c82e53f553..6d6192034a 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/MusicPlayerDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/MusicPlayerDelegate.cs @@ -1,162 +1,162 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Support; -using OpenRA.Widgets; - +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Support; +using OpenRA.Widgets; + namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class MusicPlayerDelegate : IWidgetDelegate - { - string CurrentSong = null; - public MusicPlayerDelegate() - { - var bg = Widget.RootWidget.GetWidget("MUSIC_MENU"); - CurrentSong = GetNextSong(); - - bg.GetWidget("BUTTON_CLOSE").OnMouseUp = mi => { - Game.Settings.Save(); - Widget.CloseWindow(); - return true; - }; - - var installed = Rules.Music.Count(m => m.Value.Exists) > 1; - /* - // Hack around some mix packages including hellmarch for ra - bg.GetWidget("BUTTON_INSTALL").IsVisible = () => !installed; - bg.GetWidget("BUTTON_INSTALL").OnMouseUp = mi => { - return true; - }; - */ - bg.GetWidget("BUTTON_INSTALL").IsVisible = () => false; - - bg.GetWidget("BUTTON_PLAY").OnMouseUp = mi => - { - if (CurrentSong == null) - return true; - - Sound.PlayMusicThen(Rules.Music[CurrentSong].Filename, - () => bg.GetWidget(Game.Settings.Sound.Repeat ? "BUTTON_PLAY" : "BUTTON_NEXT").OnMouseUp(new MouseInput())); - bg.GetWidget("BUTTON_PLAY").Visible = false; - bg.GetWidget("BUTTON_PAUSE").Visible = true; - - return true; - }; - - bg.GetWidget("BUTTON_PAUSE").OnMouseUp = mi => - { - Sound.PauseMusic(); - bg.GetWidget("BUTTON_PAUSE").Visible = false; - bg.GetWidget("BUTTON_PLAY").Visible = true; - return true; - }; - - bg.GetWidget("BUTTON_STOP").OnMouseUp = mi => - { - Sound.StopMusic(); - bg.GetWidget("BUTTON_PAUSE").Visible = false; - bg.GetWidget("BUTTON_PLAY").Visible = true; - - return true; - }; - - bg.GetWidget("BUTTON_NEXT").OnMouseUp = mi => - { - CurrentSong = GetNextSong(); - return bg.GetWidget("BUTTON_PLAY").OnMouseUp(mi); - }; - - bg.GetWidget("BUTTON_PREV").OnMouseUp = mi => - { - CurrentSong = GetPrevSong(); - return bg.GetWidget("BUTTON_PLAY").OnMouseUp(mi); - }; - - bg.GetWidget("SHUFFLE").Bind(Game.Settings.Sound, "Shuffle"); - bg.GetWidget("REPEAT").Bind(Game.Settings.Sound, "Repeat"); - - bg.GetWidget("TIME").GetText = () => - { - if (CurrentSong == null) - return ""; - return "{0:D2}:{1:D2} / {2:D2}:{3:D2}".F((int)Sound.MusicSeekPosition / 60, (int)Sound.MusicSeekPosition % 60, - Rules.Music[CurrentSong].Length / 60, Rules.Music[CurrentSong].Length % 60); - }; - - var ml = bg.GetWidget("MUSIC_LIST"); - var itemTemplate = ml.GetWidget("MUSIC_TEMPLATE"); - - if (!Rules.Music.Where(m => m.Value.Exists).Any()) - { - itemTemplate.IsVisible = () => true; - itemTemplate.GetWidget("TITLE").GetText = () => "No Music Installed"; - itemTemplate.GetWidget("TITLE").Align = LabelWidget.TextAlign.Center; - } - - foreach (var kv in Rules.Music.Where(m => m.Value.Exists)) - { - var song = kv.Key; - if (CurrentSong == null) - CurrentSong = song; - - var template = itemTemplate.Clone() as LabelWidget; - template.Id = "SONG_{0}".F(song); - template.GetBackground = () => ((song == CurrentSong) ? "dialog2" : null); - template.OnMouseDown = mi => - { - if (mi.Button != MouseButton.Left) return false; - CurrentSong = song; - bg.GetWidget("BUTTON_PLAY").OnMouseUp(mi); - return true; - }; - - template.IsVisible = () => true; - template.GetWidget("TITLE").GetText = () => " " + Rules.Music[song].Title; - template.GetWidget("LENGTH").GetText = () => "{0:D1}:{1:D2}".F(Rules.Music[song].Length / 60, Rules.Music[song].Length % 60); - - ml.AddChild(template); - } - } - - string GetNextSong() - { - var songs = Rules.Music.Where(a => a.Value.Exists) - .Select(a => a.Key); - - if (!songs.Any()) - return null; - - if (Game.Settings.Sound.Shuffle) - return songs.Random(Game.CosmeticRandom); - - return songs.SkipWhile(m => m != CurrentSong) - .Skip(1).FirstOrDefault() ?? songs.FirstOrDefault(); - - } - - string GetPrevSong() - { - var songs = Rules.Music.Where(a => a.Value.Exists) - .Select(a => a.Key).Reverse(); - - if (!songs.Any()) - return null; - - if (Game.Settings.Sound.Shuffle) - return songs.Random(Game.CosmeticRandom); - - return songs.SkipWhile(m => m != CurrentSong) - .Skip(1).FirstOrDefault() ?? songs.FirstOrDefault(); - } +{ + public class MusicPlayerDelegate : IWidgetDelegate + { + string CurrentSong = null; + public MusicPlayerDelegate() + { + var bg = Widget.RootWidget.GetWidget("MUSIC_MENU"); + CurrentSong = GetNextSong(); + + bg.GetWidget("BUTTON_CLOSE").OnMouseUp = mi => { + Game.Settings.Save(); + Widget.CloseWindow(); + return true; + }; + + var installed = Rules.Music.Count(m => m.Value.Exists) > 1; + /* + // Hack around some mix packages including hellmarch for ra + bg.GetWidget("BUTTON_INSTALL").IsVisible = () => !installed; + bg.GetWidget("BUTTON_INSTALL").OnMouseUp = mi => { + return true; + }; + */ + bg.GetWidget("BUTTON_INSTALL").IsVisible = () => false; + + bg.GetWidget("BUTTON_PLAY").OnMouseUp = mi => + { + if (CurrentSong == null) + return true; + + Sound.PlayMusicThen(Rules.Music[CurrentSong].Filename, + () => bg.GetWidget(Game.Settings.Sound.Repeat ? "BUTTON_PLAY" : "BUTTON_NEXT").OnMouseUp(new MouseInput())); + bg.GetWidget("BUTTON_PLAY").Visible = false; + bg.GetWidget("BUTTON_PAUSE").Visible = true; + + return true; + }; + + bg.GetWidget("BUTTON_PAUSE").OnMouseUp = mi => + { + Sound.PauseMusic(); + bg.GetWidget("BUTTON_PAUSE").Visible = false; + bg.GetWidget("BUTTON_PLAY").Visible = true; + return true; + }; + + bg.GetWidget("BUTTON_STOP").OnMouseUp = mi => + { + Sound.StopMusic(); + bg.GetWidget("BUTTON_PAUSE").Visible = false; + bg.GetWidget("BUTTON_PLAY").Visible = true; + + return true; + }; + + bg.GetWidget("BUTTON_NEXT").OnMouseUp = mi => + { + CurrentSong = GetNextSong(); + return bg.GetWidget("BUTTON_PLAY").OnMouseUp(mi); + }; + + bg.GetWidget("BUTTON_PREV").OnMouseUp = mi => + { + CurrentSong = GetPrevSong(); + return bg.GetWidget("BUTTON_PLAY").OnMouseUp(mi); + }; + + bg.GetWidget("SHUFFLE").Bind(Game.Settings.Sound, "Shuffle"); + bg.GetWidget("REPEAT").Bind(Game.Settings.Sound, "Repeat"); + + bg.GetWidget("TIME").GetText = () => + { + if (CurrentSong == null) + return ""; + return "{0:D2}:{1:D2} / {2:D2}:{3:D2}".F((int)Sound.MusicSeekPosition / 60, (int)Sound.MusicSeekPosition % 60, + Rules.Music[CurrentSong].Length / 60, Rules.Music[CurrentSong].Length % 60); + }; + + var ml = bg.GetWidget("MUSIC_LIST"); + var itemTemplate = ml.GetWidget("MUSIC_TEMPLATE"); + + if (!Rules.Music.Where(m => m.Value.Exists).Any()) + { + itemTemplate.IsVisible = () => true; + itemTemplate.GetWidget("TITLE").GetText = () => "No Music Installed"; + itemTemplate.GetWidget("TITLE").Align = LabelWidget.TextAlign.Center; + } + + foreach (var kv in Rules.Music.Where(m => m.Value.Exists)) + { + var song = kv.Key; + if (CurrentSong == null) + CurrentSong = song; + + var template = itemTemplate.Clone() as LabelWidget; + template.Id = "SONG_{0}".F(song); + template.GetBackground = () => ((song == CurrentSong) ? "dialog2" : null); + template.OnMouseDown = mi => + { + if (mi.Button != MouseButton.Left) return false; + CurrentSong = song; + bg.GetWidget("BUTTON_PLAY").OnMouseUp(mi); + return true; + }; + + template.IsVisible = () => true; + template.GetWidget("TITLE").GetText = () => " " + Rules.Music[song].Title; + template.GetWidget("LENGTH").GetText = () => "{0:D1}:{1:D2}".F(Rules.Music[song].Length / 60, Rules.Music[song].Length % 60); + + ml.AddChild(template); + } + } + + string GetNextSong() + { + var songs = Rules.Music.Where(a => a.Value.Exists) + .Select(a => a.Key); + + if (!songs.Any()) + return null; + + if (Game.Settings.Sound.Shuffle) + return songs.Random(Game.CosmeticRandom); + + return songs.SkipWhile(m => m != CurrentSong) + .Skip(1).FirstOrDefault() ?? songs.FirstOrDefault(); + + } + + string GetPrevSong() + { + var songs = Rules.Music.Where(a => a.Value.Exists) + .Select(a => a.Key).Reverse(); + + if (!songs.Any()) + return null; + + if (Game.Settings.Sound.Shuffle) + return songs.Random(Game.CosmeticRandom); + + return songs.SkipWhile(m => m != CurrentSong) + .Skip(1).FirstOrDefault() ?? songs.FirstOrDefault(); + } } } diff --git a/OpenRA.Mods.RA/Widgets/Delegates/OrderButtonsChromeDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/OrderButtonsChromeDelegate.cs index 2b83c3acd4..69e1f41533 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/OrderButtonsChromeDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/OrderButtonsChromeDelegate.cs @@ -1,24 +1,24 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using OpenRA; -using OpenRA.Mods.RA.Orders; +#endregion + +using OpenRA; +using OpenRA.Mods.RA.Orders; using OpenRA.Widgets; namespace OpenRA.Mods.RA.Widgets.Delegates { public class OrderButtonsChromeDelegate : IWidgetDelegate - { + { [ObjectCreator.UseCtor] public OrderButtonsChromeDelegate( [ObjectCreator.Param] World world ) - { + { var r = Widget.RootWidget; var gameRoot = r.GetWidget("INGAME_ROOT"); diff --git a/OpenRA.Mods.RA/Widgets/Delegates/PerfDebugDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/PerfDebugDelegate.cs index 3ff7a7d8fa..9a9769fcbb 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/PerfDebugDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/PerfDebugDelegate.cs @@ -1,35 +1,35 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ #endregion - -using OpenRA.Support; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class PerfDebugDelegate : IWidgetDelegate - { - public PerfDebugDelegate() - { - var r = Widget.RootWidget; - var perfRoot = r.GetWidget("PERF_BG"); - perfRoot.IsVisible = () => perfRoot.Visible && Game.Settings.Debug.PerfGraph; - - // Perf text - var perfText = perfRoot.GetWidget("TEXT"); - perfText.GetText = () => "Render {0} ({5}={2:F1} ms)\nTick {4} ({3:F1} ms)".F( - Game.RenderFrame, - Game.NetFrameNumber, - PerfHistory.items["render"].LastValue, - PerfHistory.items["tick_time"].LastValue, - Game.LocalTick, - PerfHistory.items["batches"].LastValue); - } - } + +using OpenRA.Support; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class PerfDebugDelegate : IWidgetDelegate + { + public PerfDebugDelegate() + { + var r = Widget.RootWidget; + var perfRoot = r.GetWidget("PERF_BG"); + perfRoot.IsVisible = () => perfRoot.Visible && Game.Settings.Debug.PerfGraph; + + // Perf text + var perfText = perfRoot.GetWidget("TEXT"); + perfText.GetText = () => "Render {0} ({5}={2:F1} ms)\nTick {4} ({3:F1} ms)".F( + Game.RenderFrame, + Game.NetFrameNumber, + PerfHistory.items["render"].LastValue, + PerfHistory.items["tick_time"].LastValue, + Game.LocalTick, + PerfHistory.items["batches"].LastValue); + } + } } diff --git a/OpenRA.Mods.RA/Widgets/Delegates/ReplayBrowserDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/ReplayBrowserDelegate.cs index 9416d748be..121b4076c2 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/ReplayBrowserDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/ReplayBrowserDelegate.cs @@ -1,150 +1,150 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using System.IO; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Network; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class ReplayBrowserDelegate : IWidgetDelegate - { - Widget widget; - - [ObjectCreator.UseCtor] - public ReplayBrowserDelegate( [ObjectCreator.Param] Widget widget ) - { - this.widget = widget; - - widget.GetWidget("CANCEL_BUTTON").OnMouseUp = mi => - { - Widget.CloseWindow(); - return true; - }; - - /* find some replays? */ - var rl = widget.GetWidget("REPLAY_LIST"); - var replayDir = Path.Combine(Game.SupportDir, "Replays"); - - var template = widget.GetWidget("REPLAY_TEMPLATE"); - CurrentReplay = null; - - rl.RemoveChildren(); - foreach (var replayFile in Directory.GetFiles(replayDir, "*.rep").Reverse()) - AddReplay(rl, replayFile, template); - - widget.GetWidget("WATCH_BUTTON").OnMouseUp = mi => - { - if (currentReplay != null) - { - Widget.CloseWindow(); - Game.JoinReplay(CurrentReplay); - } - return true; - }; - - widget.GetWidget("REPLAY_INFO").IsVisible = () => currentReplay != null; - } - - Map MapFromSummary(ReplaySummary rs) - { - if (rs.LobbyInfo == null) - return null; - - var map = rs.LobbyInfo.GlobalSettings.Map; - if (!Game.modData.AvailableMaps.ContainsKey(map)) - return null; - - return Game.modData.AvailableMaps[map]; - } - - string currentReplay = null; - string CurrentReplay - { - get { return currentReplay; } - set - { - currentReplay = value; - if (currentReplay != null) - { - try - { - var summary = new ReplaySummary(currentReplay); - var mapStub = MapFromSummary(summary); - - widget.GetWidget("DURATION").GetText = - () => WidgetUtils.FormatTime(summary.Duration * 3 /* todo: 3:1 ratio isnt always true. */); - widget.GetWidget("MAP_PREVIEW").Map = () => mapStub; - widget.GetWidget("MAP_TITLE").GetText = - () => mapStub != null ? mapStub.Title : "(Unknown Map)"; - } - catch(Exception e) - { - Log.Write("debug", "Exception while parsing replay: {0}", e.ToString()); - currentReplay = null; - } - } - } - } - - void AddReplay(ScrollPanelWidget list, string filename, LabelWidget template) - { - var entry = template.Clone() as LabelWidget; - entry.Id = "REPLAY_"; - entry.GetText = () => " {0}".F(Path.GetFileName(filename)); - entry.GetBackground = () => (CurrentReplay == filename) ? "dialog2" : null; - entry.OnMouseDown = mi => { if (mi.Button != MouseButton.Left) return false; CurrentReplay = filename; return true; }; - entry.IsVisible = () => true; - list.AddChild(entry); - } - } - - /* a maze of twisty little hacks,... */ - class ReplaySummary - { - public readonly int Duration; - public readonly Session LobbyInfo; - - public ReplaySummary(string filename) - { - var lastFrame = 0; - var hasSeenGameStart = false; - var lobbyInfo = null as Session; - using (var conn = new ReplayConnection(filename)) - conn.Receive((client, packet) => - { - var frame = BitConverter.ToInt32(packet, 0); - if (packet.Length == 5 && packet[4] == 0xBF) - return; // disconnect - else if (packet.Length >= 5 && packet[4] == 0x65) - return; // sync - else if (frame == 0) - { - /* decode this to recover lobbyinfo, etc */ - var orders = packet.ToOrderList(null); - foreach (var o in orders) - if (o.OrderString == "StartGame") - hasSeenGameStart = true; - else if (o.OrderString == "SyncInfo" && !hasSeenGameStart) - lobbyInfo = Session.Deserialize(o.TargetString); - } - else - lastFrame = Math.Max(lastFrame, frame); - }); - - Duration = lastFrame; - LobbyInfo = lobbyInfo; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using System.IO; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Network; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class ReplayBrowserDelegate : IWidgetDelegate + { + Widget widget; + + [ObjectCreator.UseCtor] + public ReplayBrowserDelegate( [ObjectCreator.Param] Widget widget ) + { + this.widget = widget; + + widget.GetWidget("CANCEL_BUTTON").OnMouseUp = mi => + { + Widget.CloseWindow(); + return true; + }; + + /* find some replays? */ + var rl = widget.GetWidget("REPLAY_LIST"); + var replayDir = Path.Combine(Game.SupportDir, "Replays"); + + var template = widget.GetWidget("REPLAY_TEMPLATE"); + CurrentReplay = null; + + rl.RemoveChildren(); + foreach (var replayFile in Directory.GetFiles(replayDir, "*.rep").Reverse()) + AddReplay(rl, replayFile, template); + + widget.GetWidget("WATCH_BUTTON").OnMouseUp = mi => + { + if (currentReplay != null) + { + Widget.CloseWindow(); + Game.JoinReplay(CurrentReplay); + } + return true; + }; + + widget.GetWidget("REPLAY_INFO").IsVisible = () => currentReplay != null; + } + + Map MapFromSummary(ReplaySummary rs) + { + if (rs.LobbyInfo == null) + return null; + + var map = rs.LobbyInfo.GlobalSettings.Map; + if (!Game.modData.AvailableMaps.ContainsKey(map)) + return null; + + return Game.modData.AvailableMaps[map]; + } + + string currentReplay = null; + string CurrentReplay + { + get { return currentReplay; } + set + { + currentReplay = value; + if (currentReplay != null) + { + try + { + var summary = new ReplaySummary(currentReplay); + var mapStub = MapFromSummary(summary); + + widget.GetWidget("DURATION").GetText = + () => WidgetUtils.FormatTime(summary.Duration * 3 /* todo: 3:1 ratio isnt always true. */); + widget.GetWidget("MAP_PREVIEW").Map = () => mapStub; + widget.GetWidget("MAP_TITLE").GetText = + () => mapStub != null ? mapStub.Title : "(Unknown Map)"; + } + catch(Exception e) + { + Log.Write("debug", "Exception while parsing replay: {0}", e.ToString()); + currentReplay = null; + } + } + } + } + + void AddReplay(ScrollPanelWidget list, string filename, LabelWidget template) + { + var entry = template.Clone() as LabelWidget; + entry.Id = "REPLAY_"; + entry.GetText = () => " {0}".F(Path.GetFileName(filename)); + entry.GetBackground = () => (CurrentReplay == filename) ? "dialog2" : null; + entry.OnMouseDown = mi => { if (mi.Button != MouseButton.Left) return false; CurrentReplay = filename; return true; }; + entry.IsVisible = () => true; + list.AddChild(entry); + } + } + + /* a maze of twisty little hacks,... */ + class ReplaySummary + { + public readonly int Duration; + public readonly Session LobbyInfo; + + public ReplaySummary(string filename) + { + var lastFrame = 0; + var hasSeenGameStart = false; + var lobbyInfo = null as Session; + using (var conn = new ReplayConnection(filename)) + conn.Receive((client, packet) => + { + var frame = BitConverter.ToInt32(packet, 0); + if (packet.Length == 5 && packet[4] == 0xBF) + return; // disconnect + else if (packet.Length >= 5 && packet[4] == 0x65) + return; // sync + else if (frame == 0) + { + /* decode this to recover lobbyinfo, etc */ + var orders = packet.ToOrderList(null); + foreach (var o in orders) + if (o.OrderString == "StartGame") + hasSeenGameStart = true; + else if (o.OrderString == "SyncInfo" && !hasSeenGameStart) + lobbyInfo = Session.Deserialize(o.TargetString); + } + else + lastFrame = Math.Max(lastFrame, frame); + }); + + Duration = lastFrame; + LobbyInfo = lobbyInfo; + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Delegates/ServerBrowserDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/ServerBrowserDelegate.cs index 94fe4dbe7f..77ba5b9073 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/ServerBrowserDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/ServerBrowserDelegate.cs @@ -1,215 +1,215 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Server; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class ServerBrowserDelegate : IWidgetDelegate - { - static List GameButtons = new List(); - - GameServer currentServer = null; - Widget ServerTemplate; - - [ObjectCreator.UseCtor] - public ServerBrowserDelegate( [ObjectCreator.Param] Widget widget ) - { - var bg = widget.GetWidget("JOINSERVER_BG"); - - MasterServerQuery.OnComplete += games => RefreshServerList(games); - - bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; - bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list..."; - - bg.Children.RemoveAll(a => GameButtons.Contains(a)); - GameButtons.Clear(); - - MasterServerQuery.Refresh(Game.Settings.Server.MasterServer); - - bg.GetWidget("SERVER_INFO").IsVisible = () => currentServer != null; - var preview = bg.GetWidget("MAP_PREVIEW"); - preview.Map = () => CurrentMap(); - preview.IsVisible = () => CurrentMap() != null; - - bg.GetWidget("SERVER_IP").GetText = () => currentServer.Address; - bg.GetWidget("SERVER_MODS").GetText = () => GenerateModsLabel(); - bg.GetWidget("MAP_TITLE").GetText = () => (CurrentMap() != null) ? CurrentMap().Title : "Unknown"; - bg.GetWidget("MAP_PLAYERS").GetText = () => - { - if (currentServer == null) - return ""; - string ret = currentServer.Players.ToString(); - if (CurrentMap() != null) - ret += "/" + CurrentMap().PlayerCount.ToString(); - return ret; - }; - - - var sl = bg.GetWidget("SERVER_LIST"); - ServerTemplate = sl.GetWidget("SERVER_TEMPLATE"); - - bg.GetWidget("REFRESH_BUTTON").OnMouseUp = mi => - { - bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; - bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list..."; - - bg.Children.RemoveAll(a => GameButtons.Contains(a)); - GameButtons.Clear(); - - MasterServerQuery.Refresh(Game.Settings.Server.MasterServer); - - return true; - }; - - bg.GetWidget("CANCEL_BUTTON").OnMouseUp = mi => - { - Widget.CloseWindow(); - return true; - }; - - bg.GetWidget("DIRECTCONNECT_BUTTON").OnMouseUp = mi => - { - Widget.CloseWindow(); - Widget.OpenWindow("DIRECTCONNECT_BG"); - return true; - }; - - bg.GetWidget("JOIN_BUTTON").OnMouseUp = mi => - { - if (currentServer == null) - return false; - - Widget.CloseWindow(); - Game.JoinServer(currentServer.Address.Split(':')[0], int.Parse(currentServer.Address.Split(':')[1])); - return true; - }; - } - - Map CurrentMap() - { - return (currentServer == null || !Game.modData.AvailableMaps.ContainsKey(currentServer.Map)) - ? null : Game.modData.AvailableMaps[currentServer.Map]; - } - - string GenerateModsLabel() - { - return string.Join("\n", currentServer.Mods - .Select( m => m.Split('@')[0] ) - .Select(m => - Mod.AllMods.ContainsKey(m) ? string.Format("{0} ({1})", Mod.AllMods[m].Title, Mod.AllMods[m].Version) - : string.Format("Unknown Mod: {0}",m)).ToArray()); - } - - void RefreshServerList(IEnumerable games) - { - var r = Widget.RootWidget; - var bg = r.GetWidget("JOINSERVER_BG"); - - if (bg == null) // We got a MasterServer reply AFTER the browser is gone, just return to prevent crash - Gecko - return; - - var sl = bg.GetWidget("SERVER_LIST"); - - sl.RemoveChildren(); - currentServer = null; - - if (games == null) - { - r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; - r.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Failed to contact master server."; - return; - } - - var gamesWaiting = games.Where(g => CanJoin(g)); - - if (gamesWaiting.Count() == 0) - { - r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; - r.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "No games found."; - return; - } - - r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = false; - - int i = 0; - foreach (var loop in gamesWaiting) - { - var game = loop; - var template = ServerTemplate.Clone() as LabelWidget; - template.Id = "JOIN_GAME_{0}".F(i); - template.GetText = () => " {0} ({1})".F( /* /8 = hack */ - game.Name, - game.Address); - template.GetBackground = () => (currentServer == game) ? "dialog2" : null; - template.OnMouseDown = mi => { if (mi.Button != MouseButton.Left) return false; currentServer = game; return true; }; - template.IsVisible = () => true; - sl.AddChild(template); - - if (i == 0) currentServer = game; - i++; - } - } - - bool CanJoin(GameServer game) - { - //"waiting for players" - if (game.State != 1) - return false; - - // Mods won't match if there are a different number - if (Game.CurrentMods.Count != game.Mods.Count()) - return false; - - return game.Mods.All( m => m.Contains('@')) && game.Mods.Select( m => Pair.New(m.Split('@')[0], m.Split('@')[1])) - .All(kv => Game.CurrentMods.ContainsKey(kv.First) && - (kv.Second == "{DEV_VERSION}" || Game.CurrentMods[kv.First].Version == "{DEV_VERSION}" || kv.Second == Game.CurrentMods[kv.First].Version)); - } - - } - - public class DirectConnectDelegate : IWidgetDelegate - { - [ObjectCreator.UseCtor] - public DirectConnectDelegate( [ObjectCreator.Param] Widget widget ) - { - var dc = widget.GetWidget("DIRECTCONNECT_BG"); - - dc.GetWidget("SERVER_ADDRESS").Text = Game.Settings.Player.LastServer; - - dc.GetWidget("JOIN_BUTTON").OnMouseUp = mi => - { - var address = dc.GetWidget("SERVER_ADDRESS").Text; - var cpts = address.Split(':').ToArray(); - if (cpts.Length != 2) - return true; - - Game.Settings.Player.LastServer = address; - Game.Settings.Save(); - - Widget.CloseWindow(); - Game.JoinServer(cpts[0], int.Parse(cpts[1])); - return true; - }; - - dc.GetWidget("CANCEL_BUTTON").OnMouseUp = mi => - { - Widget.CloseWindow(); - Widget.OpenWindow("MAINMENU_BG"); - return true; - }; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Server; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class ServerBrowserDelegate : IWidgetDelegate + { + static List GameButtons = new List(); + + GameServer currentServer = null; + Widget ServerTemplate; + + [ObjectCreator.UseCtor] + public ServerBrowserDelegate( [ObjectCreator.Param] Widget widget ) + { + var bg = widget.GetWidget("JOINSERVER_BG"); + + MasterServerQuery.OnComplete += games => RefreshServerList(games); + + bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; + bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list..."; + + bg.Children.RemoveAll(a => GameButtons.Contains(a)); + GameButtons.Clear(); + + MasterServerQuery.Refresh(Game.Settings.Server.MasterServer); + + bg.GetWidget("SERVER_INFO").IsVisible = () => currentServer != null; + var preview = bg.GetWidget("MAP_PREVIEW"); + preview.Map = () => CurrentMap(); + preview.IsVisible = () => CurrentMap() != null; + + bg.GetWidget("SERVER_IP").GetText = () => currentServer.Address; + bg.GetWidget("SERVER_MODS").GetText = () => GenerateModsLabel(); + bg.GetWidget("MAP_TITLE").GetText = () => (CurrentMap() != null) ? CurrentMap().Title : "Unknown"; + bg.GetWidget("MAP_PLAYERS").GetText = () => + { + if (currentServer == null) + return ""; + string ret = currentServer.Players.ToString(); + if (CurrentMap() != null) + ret += "/" + CurrentMap().PlayerCount.ToString(); + return ret; + }; + + + var sl = bg.GetWidget("SERVER_LIST"); + ServerTemplate = sl.GetWidget("SERVER_TEMPLATE"); + + bg.GetWidget("REFRESH_BUTTON").OnMouseUp = mi => + { + bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; + bg.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Fetching game list..."; + + bg.Children.RemoveAll(a => GameButtons.Contains(a)); + GameButtons.Clear(); + + MasterServerQuery.Refresh(Game.Settings.Server.MasterServer); + + return true; + }; + + bg.GetWidget("CANCEL_BUTTON").OnMouseUp = mi => + { + Widget.CloseWindow(); + return true; + }; + + bg.GetWidget("DIRECTCONNECT_BUTTON").OnMouseUp = mi => + { + Widget.CloseWindow(); + Widget.OpenWindow("DIRECTCONNECT_BG"); + return true; + }; + + bg.GetWidget("JOIN_BUTTON").OnMouseUp = mi => + { + if (currentServer == null) + return false; + + Widget.CloseWindow(); + Game.JoinServer(currentServer.Address.Split(':')[0], int.Parse(currentServer.Address.Split(':')[1])); + return true; + }; + } + + Map CurrentMap() + { + return (currentServer == null || !Game.modData.AvailableMaps.ContainsKey(currentServer.Map)) + ? null : Game.modData.AvailableMaps[currentServer.Map]; + } + + string GenerateModsLabel() + { + return string.Join("\n", currentServer.Mods + .Select( m => m.Split('@')[0] ) + .Select(m => + Mod.AllMods.ContainsKey(m) ? string.Format("{0} ({1})", Mod.AllMods[m].Title, Mod.AllMods[m].Version) + : string.Format("Unknown Mod: {0}",m)).ToArray()); + } + + void RefreshServerList(IEnumerable games) + { + var r = Widget.RootWidget; + var bg = r.GetWidget("JOINSERVER_BG"); + + if (bg == null) // We got a MasterServer reply AFTER the browser is gone, just return to prevent crash - Gecko + return; + + var sl = bg.GetWidget("SERVER_LIST"); + + sl.RemoveChildren(); + currentServer = null; + + if (games == null) + { + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "Failed to contact master server."; + return; + } + + var gamesWaiting = games.Where(g => CanJoin(g)); + + if (gamesWaiting.Count() == 0) + { + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = true; + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Text = "No games found."; + return; + } + + r.GetWidget("JOINSERVER_PROGRESS_TITLE").Visible = false; + + int i = 0; + foreach (var loop in gamesWaiting) + { + var game = loop; + var template = ServerTemplate.Clone() as LabelWidget; + template.Id = "JOIN_GAME_{0}".F(i); + template.GetText = () => " {0} ({1})".F( /* /8 = hack */ + game.Name, + game.Address); + template.GetBackground = () => (currentServer == game) ? "dialog2" : null; + template.OnMouseDown = mi => { if (mi.Button != MouseButton.Left) return false; currentServer = game; return true; }; + template.IsVisible = () => true; + sl.AddChild(template); + + if (i == 0) currentServer = game; + i++; + } + } + + bool CanJoin(GameServer game) + { + //"waiting for players" + if (game.State != 1) + return false; + + // Mods won't match if there are a different number + if (Game.CurrentMods.Count != game.Mods.Count()) + return false; + + return game.Mods.All( m => m.Contains('@')) && game.Mods.Select( m => Pair.New(m.Split('@')[0], m.Split('@')[1])) + .All(kv => Game.CurrentMods.ContainsKey(kv.First) && + (kv.Second == "{DEV_VERSION}" || Game.CurrentMods[kv.First].Version == "{DEV_VERSION}" || kv.Second == Game.CurrentMods[kv.First].Version)); + } + + } + + public class DirectConnectDelegate : IWidgetDelegate + { + [ObjectCreator.UseCtor] + public DirectConnectDelegate( [ObjectCreator.Param] Widget widget ) + { + var dc = widget.GetWidget("DIRECTCONNECT_BG"); + + dc.GetWidget("SERVER_ADDRESS").Text = Game.Settings.Player.LastServer; + + dc.GetWidget("JOIN_BUTTON").OnMouseUp = mi => + { + var address = dc.GetWidget("SERVER_ADDRESS").Text; + var cpts = address.Split(':').ToArray(); + if (cpts.Length != 2) + return true; + + Game.Settings.Player.LastServer = address; + Game.Settings.Save(); + + Widget.CloseWindow(); + Game.JoinServer(cpts[0], int.Parse(cpts[1])); + return true; + }; + + dc.GetWidget("CANCEL_BUTTON").OnMouseUp = mi => + { + Widget.CloseWindow(); + Widget.OpenWindow("MAINMENU_BG"); + return true; + }; + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Delegates/SettingsMenuDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/SettingsMenuDelegate.cs index 69de7efb6b..d74c0db26d 100755 --- a/OpenRA.Mods.RA/Widgets/Delegates/SettingsMenuDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/SettingsMenuDelegate.cs @@ -1,146 +1,146 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.FileFormats.Graphics; -using OpenRA.GameRules; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets.Delegates -{ - public class SettingsMenuDelegate : IWidgetDelegate - { - Widget bg; - public SettingsMenuDelegate() - { - bg = Widget.RootWidget.GetWidget("SETTINGS_MENU"); - var tabs = bg.GetWidget("TAB_CONTAINER"); - - //Tabs - tabs.GetWidget("GENERAL").OnMouseUp = mi => FlipToTab("GENERAL_PANE"); - tabs.GetWidget("AUDIO").OnMouseUp = mi => FlipToTab("AUDIO_PANE"); - tabs.GetWidget("DISPLAY").OnMouseUp = mi => FlipToTab("DISPLAY_PANE"); - tabs.GetWidget("DEBUG").OnMouseUp = mi => FlipToTab("DEBUG_PANE"); - FlipToTab("GENERAL_PANE"); - - //General - var general = bg.GetWidget("GENERAL_PANE"); - - var name = general.GetWidget("NAME"); - name.Text = Game.Settings.Player.Name; - name.OnLoseFocus = () => - { - name.Text = name.Text.Trim(); - - if (name.Text.Length == 0) - name.Text = Game.Settings.Player.Name; - else - Game.Settings.Player.Name = name.Text; - }; - name.OnEnterKey = () => { name.LoseFocus(); return true; }; - - general.GetWidget("EDGE_SCROLL").Bind(Game.Settings.Game, "ViewportEdgeScroll"); - - // Added scroll sensitivity - Gecko - var edgeScrollSlider = general.GetWidget("EDGE_SCROLL_AMOUNT"); - if (edgeScrollSlider != null) // Backwards compatible - Gecko - { - edgeScrollSlider.SetOffset(Game.Settings.Game.ViewportEdgeScrollStep); - edgeScrollSlider.OnChange += _ => { Game.Settings.Game.ViewportEdgeScrollStep = edgeScrollSlider.GetOffset(); }; - Game.Settings.Game.ViewportEdgeScrollStep = edgeScrollSlider.GetOffset(); - } - - general.GetWidget("INVERSE_SCROLL").Bind(Game.Settings.Game, "InverseDragScroll"); - general.GetWidget("TEAMCHAT_TOGGLE").Bind(Game.Settings.Game, "TeamChatToggle"); - - - // Audio - var audio = bg.GetWidget("AUDIO_PANE"); - - var soundslider = audio.GetWidget("SOUND_VOLUME"); - soundslider.OnChange += x => { Sound.SoundVolume = x; }; - soundslider.GetOffset = () => { return Sound.SoundVolume; }; - soundslider.SetOffset(Sound.SoundVolume); - - var musicslider = audio.GetWidget("MUSIC_VOLUME"); - musicslider.OnChange += x => { Sound.MusicVolume = x; }; - musicslider.GetOffset = () => { return Sound.MusicVolume; }; - musicslider.SetOffset(Sound.MusicVolume); - - - // Display - var display = bg.GetWidget("DISPLAY_PANE"); - display.GetWidget("FULLSCREEN_CHECKBOX").Bind(Game.Settings.Game, "TeamChatToggle"); - - var fullscreen = display.GetWidget("FULLSCREEN_CHECKBOX"); - fullscreen.IsChecked = () => Game.Settings.Graphics.Mode != WindowMode.Windowed; - fullscreen.OnChange += c => Game.Settings.Graphics.Mode = (Game.Settings.Graphics.Mode == WindowMode.Windowed) ? WindowMode.PseudoFullscreen : WindowMode.Windowed; - - var width = display.GetWidget("SCREEN_WIDTH"); - Game.Settings.Graphics.WindowedSize.X = (Game.Settings.Graphics.WindowedSize.X < Game.Settings.Graphics.MinResolution.X)? - Game.Settings.Graphics.MinResolution.X : Game.Settings.Graphics.WindowedSize.X; - width.Text = Game.Settings.Graphics.WindowedSize.X.ToString(); - width.OnLoseFocus = () => - { - try { - var w = int.Parse(width.Text); - if (w > Game.Settings.Graphics.MinResolution.X) - Game.Settings.Graphics.WindowedSize = new int2(w, Game.Settings.Graphics.WindowedSize.Y); - } - catch (FormatException) { - width.Text = Game.Settings.Graphics.WindowedSize.X.ToString(); - } - }; - width.OnEnterKey = () => { width.LoseFocus(); return true; }; - - var height = display.GetWidget("SCREEN_HEIGHT"); - Game.Settings.Graphics.WindowedSize.Y = (Game.Settings.Graphics.WindowedSize.Y < Game.Settings.Graphics.MinResolution.Y)? - Game.Settings.Graphics.MinResolution.Y : Game.Settings.Graphics.WindowedSize.Y; - height.Text = Game.Settings.Graphics.WindowedSize.Y.ToString(); - height.OnLoseFocus = () => - { - try { - var h = int.Parse(height.Text); - if (h > Game.Settings.Graphics.MinResolution.Y) - Game.Settings.Graphics.WindowedSize = new int2(Game.Settings.Graphics.WindowedSize.X, h); - else - height.Text = Game.Settings.Graphics.WindowedSize.Y.ToString(); - } - catch (FormatException) { - height.Text = Game.Settings.Graphics.WindowedSize.Y.ToString(); - } - }; - height.OnEnterKey = () => { height.LoseFocus(); return true; }; - - // Debug - var debug = bg.GetWidget("DEBUG_PANE"); - debug.GetWidget("PERFDEBUG_CHECKBOX").Bind(Game.Settings.Debug, "PerfGraph"); - debug.GetWidget("GAMETIME_CHECKBOX").Bind(Game.Settings.Game, "MatchTimer"); - debug.GetWidget("CHECKUNSYNCED_CHECKBOX").Bind(Game.Settings.Debug, "SanityCheckUnsyncedCode"); - - bg.GetWidget("BUTTON_CLOSE").OnMouseUp = mi => { - Game.Settings.Save(); - Widget.CloseWindow(); - return true; - }; - } - - string open = null; - bool FlipToTab(string id) - { - if (open != null) - bg.GetWidget(open).Visible = false; - - open = id; - bg.GetWidget(open).Visible = true; - return true; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.FileFormats.Graphics; +using OpenRA.GameRules; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets.Delegates +{ + public class SettingsMenuDelegate : IWidgetDelegate + { + Widget bg; + public SettingsMenuDelegate() + { + bg = Widget.RootWidget.GetWidget("SETTINGS_MENU"); + var tabs = bg.GetWidget("TAB_CONTAINER"); + + //Tabs + tabs.GetWidget("GENERAL").OnMouseUp = mi => FlipToTab("GENERAL_PANE"); + tabs.GetWidget("AUDIO").OnMouseUp = mi => FlipToTab("AUDIO_PANE"); + tabs.GetWidget("DISPLAY").OnMouseUp = mi => FlipToTab("DISPLAY_PANE"); + tabs.GetWidget("DEBUG").OnMouseUp = mi => FlipToTab("DEBUG_PANE"); + FlipToTab("GENERAL_PANE"); + + //General + var general = bg.GetWidget("GENERAL_PANE"); + + var name = general.GetWidget("NAME"); + name.Text = Game.Settings.Player.Name; + name.OnLoseFocus = () => + { + name.Text = name.Text.Trim(); + + if (name.Text.Length == 0) + name.Text = Game.Settings.Player.Name; + else + Game.Settings.Player.Name = name.Text; + }; + name.OnEnterKey = () => { name.LoseFocus(); return true; }; + + general.GetWidget("EDGE_SCROLL").Bind(Game.Settings.Game, "ViewportEdgeScroll"); + + // Added scroll sensitivity - Gecko + var edgeScrollSlider = general.GetWidget("EDGE_SCROLL_AMOUNT"); + if (edgeScrollSlider != null) // Backwards compatible - Gecko + { + edgeScrollSlider.SetOffset(Game.Settings.Game.ViewportEdgeScrollStep); + edgeScrollSlider.OnChange += _ => { Game.Settings.Game.ViewportEdgeScrollStep = edgeScrollSlider.GetOffset(); }; + Game.Settings.Game.ViewportEdgeScrollStep = edgeScrollSlider.GetOffset(); + } + + general.GetWidget("INVERSE_SCROLL").Bind(Game.Settings.Game, "InverseDragScroll"); + general.GetWidget("TEAMCHAT_TOGGLE").Bind(Game.Settings.Game, "TeamChatToggle"); + + + // Audio + var audio = bg.GetWidget("AUDIO_PANE"); + + var soundslider = audio.GetWidget("SOUND_VOLUME"); + soundslider.OnChange += x => { Sound.SoundVolume = x; }; + soundslider.GetOffset = () => { return Sound.SoundVolume; }; + soundslider.SetOffset(Sound.SoundVolume); + + var musicslider = audio.GetWidget("MUSIC_VOLUME"); + musicslider.OnChange += x => { Sound.MusicVolume = x; }; + musicslider.GetOffset = () => { return Sound.MusicVolume; }; + musicslider.SetOffset(Sound.MusicVolume); + + + // Display + var display = bg.GetWidget("DISPLAY_PANE"); + display.GetWidget("FULLSCREEN_CHECKBOX").Bind(Game.Settings.Game, "TeamChatToggle"); + + var fullscreen = display.GetWidget("FULLSCREEN_CHECKBOX"); + fullscreen.IsChecked = () => Game.Settings.Graphics.Mode != WindowMode.Windowed; + fullscreen.OnChange += c => Game.Settings.Graphics.Mode = (Game.Settings.Graphics.Mode == WindowMode.Windowed) ? WindowMode.PseudoFullscreen : WindowMode.Windowed; + + var width = display.GetWidget("SCREEN_WIDTH"); + Game.Settings.Graphics.WindowedSize.X = (Game.Settings.Graphics.WindowedSize.X < Game.Settings.Graphics.MinResolution.X)? + Game.Settings.Graphics.MinResolution.X : Game.Settings.Graphics.WindowedSize.X; + width.Text = Game.Settings.Graphics.WindowedSize.X.ToString(); + width.OnLoseFocus = () => + { + try { + var w = int.Parse(width.Text); + if (w > Game.Settings.Graphics.MinResolution.X) + Game.Settings.Graphics.WindowedSize = new int2(w, Game.Settings.Graphics.WindowedSize.Y); + } + catch (FormatException) { + width.Text = Game.Settings.Graphics.WindowedSize.X.ToString(); + } + }; + width.OnEnterKey = () => { width.LoseFocus(); return true; }; + + var height = display.GetWidget("SCREEN_HEIGHT"); + Game.Settings.Graphics.WindowedSize.Y = (Game.Settings.Graphics.WindowedSize.Y < Game.Settings.Graphics.MinResolution.Y)? + Game.Settings.Graphics.MinResolution.Y : Game.Settings.Graphics.WindowedSize.Y; + height.Text = Game.Settings.Graphics.WindowedSize.Y.ToString(); + height.OnLoseFocus = () => + { + try { + var h = int.Parse(height.Text); + if (h > Game.Settings.Graphics.MinResolution.Y) + Game.Settings.Graphics.WindowedSize = new int2(Game.Settings.Graphics.WindowedSize.X, h); + else + height.Text = Game.Settings.Graphics.WindowedSize.Y.ToString(); + } + catch (FormatException) { + height.Text = Game.Settings.Graphics.WindowedSize.Y.ToString(); + } + }; + height.OnEnterKey = () => { height.LoseFocus(); return true; }; + + // Debug + var debug = bg.GetWidget("DEBUG_PANE"); + debug.GetWidget("PERFDEBUG_CHECKBOX").Bind(Game.Settings.Debug, "PerfGraph"); + debug.GetWidget("GAMETIME_CHECKBOX").Bind(Game.Settings.Game, "MatchTimer"); + debug.GetWidget("CHECKUNSYNCED_CHECKBOX").Bind(Game.Settings.Debug, "SanityCheckUnsyncedCode"); + + bg.GetWidget("BUTTON_CLOSE").OnMouseUp = mi => { + Game.Settings.Save(); + Widget.CloseWindow(); + return true; + }; + } + + string open = null; + bool FlipToTab(string id) + { + if (open != null) + bg.GetWidget(open).Visible = false; + + open = id; + bg.GetWidget(open).Visible = true; + return true; + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/Delegates/VideoPlayerDelegate.cs b/OpenRA.Mods.RA/Widgets/Delegates/VideoPlayerDelegate.cs index e38df3bbcb..71be34ccd8 100644 --- a/OpenRA.Mods.RA/Widgets/Delegates/VideoPlayerDelegate.cs +++ b/OpenRA.Mods.RA/Widgets/Delegates/VideoPlayerDelegate.cs @@ -1,17 +1,17 @@ #region Copyright & License Information /* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, - * see LICENSE. + * see COPYING. */ -#endregion - -using System.Drawing; +#endregion + +using System.Drawing; using OpenRA.FileFormats; -using OpenRA.Widgets; - +using OpenRA.Widgets; + namespace OpenRA.Mods.RA.Widgets.Delegates { public class VideoPlayerDelegate : IWidgetDelegate @@ -63,9 +63,9 @@ namespace OpenRA.Mods.RA.Widgets.Delegates var video = kv.Key; var title = kv.Value; if (!FileSystem.Exists(video)) - continue; - - if (Selected == null) + continue; + + if (Selected == null) player.Load(Selected = video); var template = itemTemplate.Clone() as LabelWidget; diff --git a/OpenRA.Mods.RA/Widgets/GameInitInfoWidget.cs b/OpenRA.Mods.RA/Widgets/GameInitInfoWidget.cs index b677201eb0..9e00246f5b 100755 --- a/OpenRA.Mods.RA/Widgets/GameInitInfoWidget.cs +++ b/OpenRA.Mods.RA/Widgets/GameInitInfoWidget.cs @@ -1,27 +1,27 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using OpenRA.Widgets; -using System; -using OpenRA.Mods.RA.Widgets.Delegates; - -namespace OpenRA.Mods.RA.Widgets -{ - class GameInitInfoWidget : Widget - { - public string TestFile = ""; - public string GameTitle = ""; - public string PackageURL = ""; - public string PackagePath = ""; - public string InstallMode = ""; - - public override void DrawInner() {} - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using OpenRA.Widgets; +using System; +using OpenRA.Mods.RA.Widgets.Delegates; + +namespace OpenRA.Mods.RA.Widgets +{ + class GameInitInfoWidget : Widget + { + public string TestFile = ""; + public string GameTitle = ""; + public string PackageURL = ""; + public string PackagePath = ""; + public string InstallMode = ""; + + public override void DrawInner() {} + } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/Widgets/MoneyBinWidget.cs b/OpenRA.Mods.RA/Widgets/MoneyBinWidget.cs index d7d808225c..710a89cfaa 100755 --- a/OpenRA.Mods.RA/Widgets/MoneyBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/MoneyBinWidget.cs @@ -1,71 +1,71 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Traits; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets -{ - class MoneyBinWidget : Widget - { - public bool SplitOreAndCash = false; - - readonly World world; - [ObjectCreator.UseCtor] - public MoneyBinWidget( [ObjectCreator.Param] World world ) - { - this.world = world; - } - - public override void DrawInner() - { - if( world.LocalPlayer == null ) return; - - var playerResources = world.LocalPlayer.PlayerActor.Trait(); - - var digitCollection = "digits-" + world.LocalPlayer.Country.Race; - var chromeCollection = "chrome-" + world.LocalPlayer.Country.Race; - - Game.Renderer.RgbaSpriteRenderer.DrawSprite( - ChromeProvider.GetImage(chromeCollection, "moneybin"), - new float2(Bounds.Left, 0)); - - // Cash - var cashDigits = (SplitOreAndCash ? playerResources.DisplayCash - : (playerResources.DisplayCash + playerResources.DisplayOre)).ToString(); - var x = Bounds.Right - 65; - - foreach (var d in cashDigits.Reverse()) - { - Game.Renderer.RgbaSpriteRenderer.DrawSprite( - ChromeProvider.GetImage(digitCollection, (d - '0').ToString()), - new float2(x, 6)); - x -= 14; - } - - if (SplitOreAndCash) - { - x -= 14; - // Ore - var oreDigits = playerResources.DisplayOre.ToString(); - - foreach (var d in oreDigits.Reverse()) - { - Game.Renderer.RgbaSpriteRenderer.DrawSprite( - ChromeProvider.GetImage( digitCollection, (d - '0').ToString()), - new float2(x, 6)); - x -= 14; - } - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Traits; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets +{ + class MoneyBinWidget : Widget + { + public bool SplitOreAndCash = false; + + readonly World world; + [ObjectCreator.UseCtor] + public MoneyBinWidget( [ObjectCreator.Param] World world ) + { + this.world = world; + } + + public override void DrawInner() + { + if( world.LocalPlayer == null ) return; + + var playerResources = world.LocalPlayer.PlayerActor.Trait(); + + var digitCollection = "digits-" + world.LocalPlayer.Country.Race; + var chromeCollection = "chrome-" + world.LocalPlayer.Country.Race; + + Game.Renderer.RgbaSpriteRenderer.DrawSprite( + ChromeProvider.GetImage(chromeCollection, "moneybin"), + new float2(Bounds.Left, 0)); + + // Cash + var cashDigits = (SplitOreAndCash ? playerResources.DisplayCash + : (playerResources.DisplayCash + playerResources.DisplayOre)).ToString(); + var x = Bounds.Right - 65; + + foreach (var d in cashDigits.Reverse()) + { + Game.Renderer.RgbaSpriteRenderer.DrawSprite( + ChromeProvider.GetImage(digitCollection, (d - '0').ToString()), + new float2(x, 6)); + x -= 14; + } + + if (SplitOreAndCash) + { + x -= 14; + // Ore + var oreDigits = playerResources.DisplayOre.ToString(); + + foreach (var d in oreDigits.Reverse()) + { + Game.Renderer.RgbaSpriteRenderer.DrawSprite( + ChromeProvider.GetImage( digitCollection, (d - '0').ToString()), + new float2(x, 6)); + x -= 14; + } + } + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/OrderButtonWidget.cs b/OpenRA.Mods.RA/Widgets/OrderButtonWidget.cs index c5c72b8e4b..2771ff3b92 100755 --- a/OpenRA.Mods.RA/Widgets/OrderButtonWidget.cs +++ b/OpenRA.Mods.RA/Widgets/OrderButtonWidget.cs @@ -1,16 +1,16 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.Graphics; +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.Graphics; using OpenRA.Widgets; namespace OpenRA.Mods.RA.Widgets diff --git a/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs b/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs index 7a06bf8d09..2ef5be3a49 100755 --- a/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/PowerBinWidget.cs @@ -1,91 +1,91 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using OpenRA.Graphics; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets -{ - public class PowerBinWidget : Widget - { - // Power bar - static float2 powerOrigin = new float2(42, 205); // Relative to radarOrigin - static Size powerSize = new Size(138, 5); - float? lastPowerProvidedPos; - float? lastPowerDrainedPos; - string powerCollection; - - readonly World world; - [ObjectCreator.UseCtor] - public PowerBinWidget( [ObjectCreator.Param] World world ) - { - this.world = world; - } - - public override void DrawInner() - { - if( world.LocalPlayer == null ) return; - - powerCollection = "power-" + world.LocalPlayer.Country.Race; - - var power = world.LocalPlayer.PlayerActor.Trait(); - - // Nothing to draw - if (power.PowerProvided == 0 - && power.PowerDrained == 0) - return; - - // Draw bar horizontally - var barStart = powerOrigin + RadarBinWidget.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, .3f); - float2 powerLevel = new float2(lastPowerProvidedPos.Value, barStart.Y); - - var color = Color.LimeGreen; - if (power.PowerState == PowerState.Low) - color = Color.Orange; - if (power.PowerState == PowerState.Critical) - color = Color.Red; - - var colorDark = Graphics.Util.Lerp(0.25f, color, Color.Black); - for (int i = 0; i < powerSize.Height; i++) - { - color = (i - 1 < powerSize.Height / 2) ? color : colorDark; - float2 leftOffset = new float2(0, i); - float2 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(Game.viewport.Location + barStart + leftOffset, Game.viewport.Location + 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, .3f); - float2 powerDrainLevel = new float2(lastPowerDrainedPos.Value - indicator.size.X / 2, barStart.Y - 1); - - Game.Renderer.RgbaSpriteRenderer.DrawSprite(indicator, powerDrainLevel); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets +{ + public class PowerBinWidget : Widget + { + // Power bar + static float2 powerOrigin = new float2(42, 205); // Relative to radarOrigin + static Size powerSize = new Size(138, 5); + float? lastPowerProvidedPos; + float? lastPowerDrainedPos; + string powerCollection; + + readonly World world; + [ObjectCreator.UseCtor] + public PowerBinWidget( [ObjectCreator.Param] World world ) + { + this.world = world; + } + + public override void DrawInner() + { + if( world.LocalPlayer == null ) return; + + powerCollection = "power-" + world.LocalPlayer.Country.Race; + + var power = world.LocalPlayer.PlayerActor.Trait(); + + // Nothing to draw + if (power.PowerProvided == 0 + && power.PowerDrained == 0) + return; + + // Draw bar horizontally + var barStart = powerOrigin + RadarBinWidget.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, .3f); + float2 powerLevel = new float2(lastPowerProvidedPos.Value, barStart.Y); + + var color = Color.LimeGreen; + if (power.PowerState == PowerState.Low) + color = Color.Orange; + if (power.PowerState == PowerState.Critical) + color = Color.Red; + + var colorDark = Graphics.Util.Lerp(0.25f, color, Color.Black); + for (int i = 0; i < powerSize.Height; i++) + { + color = (i - 1 < powerSize.Height / 2) ? color : colorDark; + float2 leftOffset = new float2(0, i); + float2 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(Game.viewport.Location + barStart + leftOffset, Game.viewport.Location + 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, .3f); + float2 powerDrainLevel = new float2(lastPowerDrainedPos.Value - indicator.size.X / 2, barStart.Y - 1); + + Game.Renderer.RgbaSpriteRenderer.DrawSprite(indicator, powerDrainLevel); + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs b/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs index b6378af1fa..69d2c3ff6b 100755 --- a/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs @@ -1,236 +1,236 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion -using System; -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Traits; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets -{ - public class RadarBinWidget : Widget - { - public string WorldInteractionController = null; - - static float2 radarOpenOrigin = new float2(Game.viewport.Width - 215, 29); - static float2 radarClosedOrigin = new float2(Game.viewport.Width - 215, -166); - public static float2 radarOrigin = radarClosedOrigin; - float radarMinimapHeight; - const int radarSlideAnimationLength = 15; - const int radarActivateAnimationLength = 5; - int radarAnimationFrame = 0; - bool radarAnimating = false; - bool hasRadar = false; - string radarCollection; - - float previewScale = 0; - RectangleF mapRect = Rectangle.Empty; - int2 previewOrigin; - - Sprite terrainSprite; - Sprite customTerrainSprite; - Sprite actorSprite; - Sprite shroudSprite; - - readonly World world; - [ObjectCreator.UseCtor] - public RadarBinWidget( [ObjectCreator.Param] World world ) - { - this.world = world; - var size = Math.Max(world.Map.Bounds.Width, world.Map.Bounds.Height); - previewScale = Math.Min(192f / world.Map.Bounds.Width, 192f / world.Map.Bounds.Height); - previewOrigin = new int2(9 + (int)(radarOpenOrigin.X + previewScale * (size - world.Map.Bounds.Width)/2), (int)(radarOpenOrigin.Y + previewScale * (size - world.Map.Bounds.Height)/2)); - mapRect = new RectangleF(previewOrigin.X, previewOrigin.Y, (int)(world.Map.Bounds.Width * previewScale), (int)(world.Map.Bounds.Height * previewScale)); - - // Only needs to be done once - var terrainBitmap = Minimap.TerrainBitmap(world.Map); - var r = new Rectangle( 0, 0, world.Map.Bounds.Width, world.Map.Bounds.Height ); - var s = new Size( terrainBitmap.Width, terrainBitmap.Height ); - terrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); - terrainSprite.sheet.Texture.SetData(terrainBitmap); - - // Data is set in Tick() - customTerrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); - actorSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); - shroudSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); - } - - public override string GetCursor(int2 pos) - { - if (world == null || !hasRadar) - return null; - - var loc = MinimapPixelToCell(pos); - - var mi = new MouseInput - { - Location = loc, - Button = MouseButton.Right, - Modifiers = Game.GetModifierKeys() - }; - - var cursor = world.OrderGenerator.GetCursor( world, loc, mi ); - if (cursor == null) - return "default"; - - return CursorProvider.HasCursorSequence(cursor+"-minimap") ? cursor+"-minimap" : cursor; - } - - // TODO: RadarBinWidget doesn't support delegate methods for mouse input - public override bool HandleMouseInput(MouseInput mi) - { - if (!hasRadar || radarAnimating) return false; // we're not set up for this. - - if (!mapRect.Contains(mi.Location)) - return false; - - var loc = MinimapPixelToCell(mi.Location); - if ((mi.Event == MouseInputEvent.Down || mi.Event == MouseInputEvent.Move) && mi.Button == MouseButton.Left) - Game.viewport.Center(loc); - - if (mi.Event == MouseInputEvent.Down && mi.Button == MouseButton.Right) - { - // fake a mousedown/mouseup here - var fakemi = new MouseInput - { - Event = MouseInputEvent.Down, - Button = MouseButton.Right, - Modifiers = mi.Modifiers, - Location = (loc * Game.CellSize - Game.viewport.Location).ToInt2() - }; - - if (WorldInteractionController != null) - { - var controller = Widget.RootWidget.GetWidget(WorldInteractionController); - controller.HandleMouseInput(fakemi); - fakemi.Event = MouseInputEvent.Up; - controller.HandleMouseInput(fakemi); - } - } - - return true; - } - - public override Rectangle EventBounds - { - get { return new Rectangle((int)mapRect.X, (int)mapRect.Y, (int)mapRect.Width, (int)mapRect.Height);} - } - - public override void DrawInner() - { - if( world == null || world.LocalPlayer == null ) return; - - radarCollection = "radar-" + world.LocalPlayer.Country.Race; - - Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "left"), radarOrigin); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "right"), radarOrigin + new float2(201, 0)); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "bottom"), radarOrigin + new float2(0, 192)); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "bg"), radarOrigin + new float2(9, 0)); - - // Don't draw the radar if the tray is moving - if (radarAnimationFrame >= radarSlideAnimationLength) - { - var o = new float2(mapRect.Location.X, mapRect.Location.Y + world.Map.Bounds.Height * previewScale * (1 - radarMinimapHeight)/2); - var s = new float2(mapRect.Size.Width, mapRect.Size.Height*radarMinimapHeight); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(terrainSprite, o, s); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(customTerrainSprite, o, s); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(actorSprite, o, s); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(shroudSprite, o, s); - - // Draw viewport rect - if (radarAnimationFrame == radarSlideAnimationLength + radarActivateAnimationLength) - { - var tl = CellToMinimapPixel(new int2((int)(Game.viewport.Location.X/Game.CellSize), (int)(Game.viewport.Location.Y/Game.CellSize))); - var br = CellToMinimapPixel(new int2((int)((Game.viewport.Location.X + Game.viewport.Width)/Game.CellSize), (int)((Game.viewport.Location.Y + Game.viewport.Height)/Game.CellSize))); - var tr = new int2(br.X, tl.Y); - var bl = new int2(tl.X, br.Y); - Game.Renderer.EnableScissor((int)mapRect.Left, (int)mapRect.Top, (int)mapRect.Width, (int)mapRect.Height); - Game.Renderer.LineRenderer.DrawLine(Game.viewport.Location + tl, Game.viewport.Location + tr, Color.White, Color.White); - Game.Renderer.LineRenderer.DrawLine(Game.viewport.Location + tr, Game.viewport.Location + br, Color.White, Color.White); - Game.Renderer.LineRenderer.DrawLine(Game.viewport.Location + br, Game.viewport.Location + bl, Color.White, Color.White); - Game.Renderer.LineRenderer.DrawLine(Game.viewport.Location + bl, Game.viewport.Location + tl, Color.White, Color.White); - Game.Renderer.DisableScissor(); - } - } - } - - int updateTicks = 0; - public override void Tick() - { - var hasRadarNew = world.Queries.OwnedBy[world.LocalPlayer] - .WithTrait() - .Any(a => a.Trait.IsActive); - - if (hasRadarNew != hasRadar) - radarAnimating = true; - - hasRadar = hasRadarNew; - - // Build the radar image - if (hasRadar) - { - --updateTicks; - if (updateTicks <= 0) - { - updateTicks = 12; - customTerrainSprite.sheet.Texture.SetData(Minimap.CustomTerrainBitmap(world)); - } - - if (updateTicks == 8) - actorSprite.sheet.Texture.SetData(Minimap.ActorsBitmap(world)); - - if (updateTicks == 4) - shroudSprite.sheet.Texture.SetData(Minimap.ShroudBitmap(world)); - } - - if (!radarAnimating) - return; - - // Increment frame - if (hasRadar) - radarAnimationFrame++; - else - radarAnimationFrame--; - - // Calculate radar bin position - if (radarAnimationFrame <= radarSlideAnimationLength) - radarOrigin = float2.Lerp(radarClosedOrigin, radarOpenOrigin, radarAnimationFrame * 1.0f / radarSlideAnimationLength); - - var eva = Rules.Info["world"].Traits.Get(); - - // Play radar-on sound at the start of the activate anim (open) - if (radarAnimationFrame == radarSlideAnimationLength && hasRadar) - Sound.Play(eva.RadarUp); - - // Play radar-on sound at the start of the activate anim (close) - if (radarAnimationFrame == radarSlideAnimationLength + radarActivateAnimationLength - 1 && !hasRadar) - Sound.Play(eva.RadarDown); - - // Minimap height - if (radarAnimationFrame >= radarSlideAnimationLength) - radarMinimapHeight = float2.Lerp(0, 1, (radarAnimationFrame - radarSlideAnimationLength) * 1.0f / radarActivateAnimationLength); - - // Animation is complete - if (radarAnimationFrame == (hasRadar ? radarSlideAnimationLength + radarActivateAnimationLength : 0)) - radarAnimating = false; - } - - int2 CellToMinimapPixel(int2 p) - { - return new int2((int)(mapRect.X +previewScale*(p.X - world.Map.Bounds.Left)), (int)(mapRect.Y + previewScale*(p.Y - world.Map.Bounds.Top))); - } - - int2 MinimapPixelToCell(int2 p) - { - return new int2(world.Map.Bounds.Left + (int)((p.X - mapRect.X)/previewScale), world.Map.Bounds.Top + (int)((p.Y - mapRect.Y)/previewScale)); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion +using System; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Traits; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets +{ + public class RadarBinWidget : Widget + { + public string WorldInteractionController = null; + + static float2 radarOpenOrigin = new float2(Game.viewport.Width - 215, 29); + static float2 radarClosedOrigin = new float2(Game.viewport.Width - 215, -166); + public static float2 radarOrigin = radarClosedOrigin; + float radarMinimapHeight; + const int radarSlideAnimationLength = 15; + const int radarActivateAnimationLength = 5; + int radarAnimationFrame = 0; + bool radarAnimating = false; + bool hasRadar = false; + string radarCollection; + + float previewScale = 0; + RectangleF mapRect = Rectangle.Empty; + int2 previewOrigin; + + Sprite terrainSprite; + Sprite customTerrainSprite; + Sprite actorSprite; + Sprite shroudSprite; + + readonly World world; + [ObjectCreator.UseCtor] + public RadarBinWidget( [ObjectCreator.Param] World world ) + { + this.world = world; + var size = Math.Max(world.Map.Bounds.Width, world.Map.Bounds.Height); + previewScale = Math.Min(192f / world.Map.Bounds.Width, 192f / world.Map.Bounds.Height); + previewOrigin = new int2(9 + (int)(radarOpenOrigin.X + previewScale * (size - world.Map.Bounds.Width)/2), (int)(radarOpenOrigin.Y + previewScale * (size - world.Map.Bounds.Height)/2)); + mapRect = new RectangleF(previewOrigin.X, previewOrigin.Y, (int)(world.Map.Bounds.Width * previewScale), (int)(world.Map.Bounds.Height * previewScale)); + + // Only needs to be done once + var terrainBitmap = Minimap.TerrainBitmap(world.Map); + var r = new Rectangle( 0, 0, world.Map.Bounds.Width, world.Map.Bounds.Height ); + var s = new Size( terrainBitmap.Width, terrainBitmap.Height ); + terrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + terrainSprite.sheet.Texture.SetData(terrainBitmap); + + // Data is set in Tick() + customTerrainSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + actorSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + shroudSprite = new Sprite(new Sheet(s), r, TextureChannel.Alpha); + } + + public override string GetCursor(int2 pos) + { + if (world == null || !hasRadar) + return null; + + var loc = MinimapPixelToCell(pos); + + var mi = new MouseInput + { + Location = loc, + Button = MouseButton.Right, + Modifiers = Game.GetModifierKeys() + }; + + var cursor = world.OrderGenerator.GetCursor( world, loc, mi ); + if (cursor == null) + return "default"; + + return CursorProvider.HasCursorSequence(cursor+"-minimap") ? cursor+"-minimap" : cursor; + } + + // TODO: RadarBinWidget doesn't support delegate methods for mouse input + public override bool HandleMouseInput(MouseInput mi) + { + if (!hasRadar || radarAnimating) return false; // we're not set up for this. + + if (!mapRect.Contains(mi.Location)) + return false; + + var loc = MinimapPixelToCell(mi.Location); + if ((mi.Event == MouseInputEvent.Down || mi.Event == MouseInputEvent.Move) && mi.Button == MouseButton.Left) + Game.viewport.Center(loc); + + if (mi.Event == MouseInputEvent.Down && mi.Button == MouseButton.Right) + { + // fake a mousedown/mouseup here + var fakemi = new MouseInput + { + Event = MouseInputEvent.Down, + Button = MouseButton.Right, + Modifiers = mi.Modifiers, + Location = (loc * Game.CellSize - Game.viewport.Location).ToInt2() + }; + + if (WorldInteractionController != null) + { + var controller = Widget.RootWidget.GetWidget(WorldInteractionController); + controller.HandleMouseInput(fakemi); + fakemi.Event = MouseInputEvent.Up; + controller.HandleMouseInput(fakemi); + } + } + + return true; + } + + public override Rectangle EventBounds + { + get { return new Rectangle((int)mapRect.X, (int)mapRect.Y, (int)mapRect.Width, (int)mapRect.Height);} + } + + public override void DrawInner() + { + if( world == null || world.LocalPlayer == null ) return; + + radarCollection = "radar-" + world.LocalPlayer.Country.Race; + + Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "left"), radarOrigin); + Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "right"), radarOrigin + new float2(201, 0)); + Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "bottom"), radarOrigin + new float2(0, 192)); + Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "bg"), radarOrigin + new float2(9, 0)); + + // Don't draw the radar if the tray is moving + if (radarAnimationFrame >= radarSlideAnimationLength) + { + var o = new float2(mapRect.Location.X, mapRect.Location.Y + world.Map.Bounds.Height * previewScale * (1 - radarMinimapHeight)/2); + var s = new float2(mapRect.Size.Width, mapRect.Size.Height*radarMinimapHeight); + Game.Renderer.RgbaSpriteRenderer.DrawSprite(terrainSprite, o, s); + Game.Renderer.RgbaSpriteRenderer.DrawSprite(customTerrainSprite, o, s); + Game.Renderer.RgbaSpriteRenderer.DrawSprite(actorSprite, o, s); + Game.Renderer.RgbaSpriteRenderer.DrawSprite(shroudSprite, o, s); + + // Draw viewport rect + if (radarAnimationFrame == radarSlideAnimationLength + radarActivateAnimationLength) + { + var tl = CellToMinimapPixel(new int2((int)(Game.viewport.Location.X/Game.CellSize), (int)(Game.viewport.Location.Y/Game.CellSize))); + var br = CellToMinimapPixel(new int2((int)((Game.viewport.Location.X + Game.viewport.Width)/Game.CellSize), (int)((Game.viewport.Location.Y + Game.viewport.Height)/Game.CellSize))); + var tr = new int2(br.X, tl.Y); + var bl = new int2(tl.X, br.Y); + Game.Renderer.EnableScissor((int)mapRect.Left, (int)mapRect.Top, (int)mapRect.Width, (int)mapRect.Height); + Game.Renderer.LineRenderer.DrawLine(Game.viewport.Location + tl, Game.viewport.Location + tr, Color.White, Color.White); + Game.Renderer.LineRenderer.DrawLine(Game.viewport.Location + tr, Game.viewport.Location + br, Color.White, Color.White); + Game.Renderer.LineRenderer.DrawLine(Game.viewport.Location + br, Game.viewport.Location + bl, Color.White, Color.White); + Game.Renderer.LineRenderer.DrawLine(Game.viewport.Location + bl, Game.viewport.Location + tl, Color.White, Color.White); + Game.Renderer.DisableScissor(); + } + } + } + + int updateTicks = 0; + public override void Tick() + { + var hasRadarNew = world.Queries.OwnedBy[world.LocalPlayer] + .WithTrait() + .Any(a => a.Trait.IsActive); + + if (hasRadarNew != hasRadar) + radarAnimating = true; + + hasRadar = hasRadarNew; + + // Build the radar image + if (hasRadar) + { + --updateTicks; + if (updateTicks <= 0) + { + updateTicks = 12; + customTerrainSprite.sheet.Texture.SetData(Minimap.CustomTerrainBitmap(world)); + } + + if (updateTicks == 8) + actorSprite.sheet.Texture.SetData(Minimap.ActorsBitmap(world)); + + if (updateTicks == 4) + shroudSprite.sheet.Texture.SetData(Minimap.ShroudBitmap(world)); + } + + if (!radarAnimating) + return; + + // Increment frame + if (hasRadar) + radarAnimationFrame++; + else + radarAnimationFrame--; + + // Calculate radar bin position + if (radarAnimationFrame <= radarSlideAnimationLength) + radarOrigin = float2.Lerp(radarClosedOrigin, radarOpenOrigin, radarAnimationFrame * 1.0f / radarSlideAnimationLength); + + var eva = Rules.Info["world"].Traits.Get(); + + // Play radar-on sound at the start of the activate anim (open) + if (radarAnimationFrame == radarSlideAnimationLength && hasRadar) + Sound.Play(eva.RadarUp); + + // Play radar-on sound at the start of the activate anim (close) + if (radarAnimationFrame == radarSlideAnimationLength + radarActivateAnimationLength - 1 && !hasRadar) + Sound.Play(eva.RadarDown); + + // Minimap height + if (radarAnimationFrame >= radarSlideAnimationLength) + radarMinimapHeight = float2.Lerp(0, 1, (radarAnimationFrame - radarSlideAnimationLength) * 1.0f / radarActivateAnimationLength); + + // Animation is complete + if (radarAnimationFrame == (hasRadar ? radarSlideAnimationLength + radarActivateAnimationLength : 0)) + radarAnimating = false; + } + + int2 CellToMinimapPixel(int2 p) + { + return new int2((int)(mapRect.X +previewScale*(p.X - world.Map.Bounds.Left)), (int)(mapRect.Y + previewScale*(p.Y - world.Map.Bounds.Top))); + } + + int2 MinimapPixelToCell(int2 p) + { + return new int2(world.Map.Bounds.Left + (int)((p.X - mapRect.X)/previewScale), world.Map.Bounds.Top + (int)((p.Y - mapRect.Y)/previewScale)); + } + } +} diff --git a/OpenRA.Mods.RA/Widgets/SpecialPowerBinWidget.cs b/OpenRA.Mods.RA/Widgets/SpecialPowerBinWidget.cs index 9d5ed05e32..56da129e1c 100755 --- a/OpenRA.Mods.RA/Widgets/SpecialPowerBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/SpecialPowerBinWidget.cs @@ -1,175 +1,175 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Graphics; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets -{ - class SpecialPowerBinWidget : Widget - { - Dictionary spsprites; - Animation ready; - Animation clock; - readonly List>> buttons = new List>>(); - - readonly World world; - readonly WorldRenderer worldRenderer; - [ObjectCreator.UseCtor] - public SpecialPowerBinWidget([ObjectCreator.Param] World world, [ObjectCreator.Param] WorldRenderer worldRenderer) - { - this.world = world; - this.worldRenderer = worldRenderer; - } - - public override void Initialize() - { - base.Initialize(); - - spsprites = Rules.Info.Values.SelectMany( u => u.Traits.WithInterface() ) - .Select(u => u.Image).Distinct() - .ToDictionary( - u => u, - u => Game.modData.SpriteLoader.LoadAllSprites(u)[0]); - - ready = new Animation("pips"); - ready.PlayRepeating("ready"); - clock = new Animation("clock"); - } - - public override Rectangle EventBounds - { - get { return buttons.Any() ? buttons.Select(b => b.First).Aggregate(Rectangle.Union) : Bounds; } - } - - // TODO: SpecialPowerBin doesn't support delegate methods for mouse input - public override bool HandleMouseInput(MouseInput mi) - { - if (mi.Event == MouseInputEvent.Down) - { - var action = buttons.Where(a => a.First.Contains(mi.Location)) - .Select(a => a.Second).FirstOrDefault(); - if (action == null) - return false; - - action(mi); - return true; - } - - return false; - } - - public override void DrawInner() - { - buttons.Clear(); - - if( world.LocalPlayer == null ) return; - - var manager = world.LocalPlayer.PlayerActor.Trait(); - var powers = manager.Powers.Where(p => !p.Value.Disabled); - var numPowers = powers.Count(); - if (numPowers == 0) return; - - var rectBounds = RenderBounds; - WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world, "specialbin-top"),new float2(rectBounds.X,rectBounds.Y)); - for (var i = 1; i < numPowers; i++) - WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world,"specialbin-middle"), new float2(rectBounds.X, rectBounds.Y + i * 51)); - WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world,"specialbin-bottom"), new float2(rectBounds.X, rectBounds.Y + numPowers * 51)); - - // Hack Hack Hack - rectBounds.Width = 69; - rectBounds.Height = 10 + numPowers * 51 + 21; - - var y = rectBounds.Y + 10; - foreach (var kv in powers) - { - var sp = kv.Value; - var image = spsprites[sp.Info.Image]; - - var drawPos = new float2(rectBounds.X + 5, y); - var rect = new Rectangle(rectBounds.X + 5, y, 64, 48); - - if (rect.Contains(Viewport.LastMousePos)) - { - var pos = drawPos.ToInt2(); - var tl = new int2(pos.X-3,pos.Y-3); - var m = new int2(pos.X+64+3,pos.Y+48+3); - var br = tl + new int2(64+3+20,40); - if (sp.TotalTime > 0) - br += new int2(0,20); - - if (sp.Info.LongDesc != null) - br += Game.Renderer.RegularFont.Measure(sp.Info.LongDesc.Replace("\\n", "\n")); - else - br += new int2(300,0); - - var border = WidgetUtils.GetBorderSizes("dialog4"); - - WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(tl.X, tl.Y, m.X + border[3], m.Y), - PanelSides.Left | PanelSides.Top | PanelSides.Bottom); - WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(m.X - border[2], tl.Y, br.X, m.Y + border[1]), - PanelSides.Top | PanelSides.Right); - WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(m.X, m.Y - border[1], br.X, br.Y), - PanelSides.Left | PanelSides.Right | PanelSides.Bottom); - - pos += new int2(77, 5); - Game.Renderer.BoldFont.DrawText(sp.Info.Description, pos, Color.White); - - if (sp.TotalTime > 0) - { - pos += new int2(0,20); - Game.Renderer.BoldFont.DrawText(WidgetUtils.FormatTime(sp.RemainingTime).ToString(), pos, Color.White); - Game.Renderer.BoldFont.DrawText("/ {0}".F(WidgetUtils.FormatTime(sp.TotalTime)), pos + new int2(45,0), Color.White); - } - - if (sp.Info.LongDesc != null) - { - pos += new int2(0, 20); - Game.Renderer.RegularFont.DrawText(sp.Info.LongDesc.Replace("\\n", "\n"), pos, Color.White); - } - - } - WidgetUtils.DrawSHP(image, drawPos, worldRenderer); - - clock.PlayFetchIndex("idle", - () => sp.TotalTime == 0 ? clock.CurrentSequence.Length - 1 : (sp.TotalTime - sp.RemainingTime) - * (clock.CurrentSequence.Length - 1) / sp.TotalTime); - clock.Tick(); - - WidgetUtils.DrawSHP(clock.Image, drawPos, worldRenderer); - - if (sp.Ready) - { - ready.Play("ready"); - WidgetUtils.DrawSHP(ready.Image, drawPos + new float2((64 - ready.Image.size.X) / 2, 2), worldRenderer); - } - else if (!sp.Active) - { - ready.Play("hold"); - WidgetUtils.DrawSHP(ready.Image, drawPos + new float2((64 - ready.Image.size.X) / 2, 2), worldRenderer); - } - - buttons.Add(Pair.New(rect,HandleSupportPower(kv.Key, manager))); - - y += 51; - } - } - - Action HandleSupportPower(string key, SupportPowerManager manager) - { - return mi => { if (mi.Button == MouseButton.Left) manager.Target(key); }; - } - } +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets +{ + class SpecialPowerBinWidget : Widget + { + Dictionary spsprites; + Animation ready; + Animation clock; + readonly List>> buttons = new List>>(); + + readonly World world; + readonly WorldRenderer worldRenderer; + [ObjectCreator.UseCtor] + public SpecialPowerBinWidget([ObjectCreator.Param] World world, [ObjectCreator.Param] WorldRenderer worldRenderer) + { + this.world = world; + this.worldRenderer = worldRenderer; + } + + public override void Initialize() + { + base.Initialize(); + + spsprites = Rules.Info.Values.SelectMany( u => u.Traits.WithInterface() ) + .Select(u => u.Image).Distinct() + .ToDictionary( + u => u, + u => Game.modData.SpriteLoader.LoadAllSprites(u)[0]); + + ready = new Animation("pips"); + ready.PlayRepeating("ready"); + clock = new Animation("clock"); + } + + public override Rectangle EventBounds + { + get { return buttons.Any() ? buttons.Select(b => b.First).Aggregate(Rectangle.Union) : Bounds; } + } + + // TODO: SpecialPowerBin doesn't support delegate methods for mouse input + public override bool HandleMouseInput(MouseInput mi) + { + if (mi.Event == MouseInputEvent.Down) + { + var action = buttons.Where(a => a.First.Contains(mi.Location)) + .Select(a => a.Second).FirstOrDefault(); + if (action == null) + return false; + + action(mi); + return true; + } + + return false; + } + + public override void DrawInner() + { + buttons.Clear(); + + if( world.LocalPlayer == null ) return; + + var manager = world.LocalPlayer.PlayerActor.Trait(); + var powers = manager.Powers.Where(p => !p.Value.Disabled); + var numPowers = powers.Count(); + if (numPowers == 0) return; + + var rectBounds = RenderBounds; + WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world, "specialbin-top"),new float2(rectBounds.X,rectBounds.Y)); + for (var i = 1; i < numPowers; i++) + WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world,"specialbin-middle"), new float2(rectBounds.X, rectBounds.Y + i * 51)); + WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world,"specialbin-bottom"), new float2(rectBounds.X, rectBounds.Y + numPowers * 51)); + + // Hack Hack Hack + rectBounds.Width = 69; + rectBounds.Height = 10 + numPowers * 51 + 21; + + var y = rectBounds.Y + 10; + foreach (var kv in powers) + { + var sp = kv.Value; + var image = spsprites[sp.Info.Image]; + + var drawPos = new float2(rectBounds.X + 5, y); + var rect = new Rectangle(rectBounds.X + 5, y, 64, 48); + + if (rect.Contains(Viewport.LastMousePos)) + { + var pos = drawPos.ToInt2(); + var tl = new int2(pos.X-3,pos.Y-3); + var m = new int2(pos.X+64+3,pos.Y+48+3); + var br = tl + new int2(64+3+20,40); + if (sp.TotalTime > 0) + br += new int2(0,20); + + if (sp.Info.LongDesc != null) + br += Game.Renderer.RegularFont.Measure(sp.Info.LongDesc.Replace("\\n", "\n")); + else + br += new int2(300,0); + + var border = WidgetUtils.GetBorderSizes("dialog4"); + + WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(tl.X, tl.Y, m.X + border[3], m.Y), + PanelSides.Left | PanelSides.Top | PanelSides.Bottom); + WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(m.X - border[2], tl.Y, br.X, m.Y + border[1]), + PanelSides.Top | PanelSides.Right); + WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(m.X, m.Y - border[1], br.X, br.Y), + PanelSides.Left | PanelSides.Right | PanelSides.Bottom); + + pos += new int2(77, 5); + Game.Renderer.BoldFont.DrawText(sp.Info.Description, pos, Color.White); + + if (sp.TotalTime > 0) + { + pos += new int2(0,20); + Game.Renderer.BoldFont.DrawText(WidgetUtils.FormatTime(sp.RemainingTime).ToString(), pos, Color.White); + Game.Renderer.BoldFont.DrawText("/ {0}".F(WidgetUtils.FormatTime(sp.TotalTime)), pos + new int2(45,0), Color.White); + } + + if (sp.Info.LongDesc != null) + { + pos += new int2(0, 20); + Game.Renderer.RegularFont.DrawText(sp.Info.LongDesc.Replace("\\n", "\n"), pos, Color.White); + } + + } + WidgetUtils.DrawSHP(image, drawPos, worldRenderer); + + clock.PlayFetchIndex("idle", + () => sp.TotalTime == 0 ? clock.CurrentSequence.Length - 1 : (sp.TotalTime - sp.RemainingTime) + * (clock.CurrentSequence.Length - 1) / sp.TotalTime); + clock.Tick(); + + WidgetUtils.DrawSHP(clock.Image, drawPos, worldRenderer); + + if (sp.Ready) + { + ready.Play("ready"); + WidgetUtils.DrawSHP(ready.Image, drawPos + new float2((64 - ready.Image.size.X) / 2, 2), worldRenderer); + } + else if (!sp.Active) + { + ready.Play("hold"); + WidgetUtils.DrawSHP(ready.Image, drawPos + new float2((64 - ready.Image.size.X) / 2, 2), worldRenderer); + } + + buttons.Add(Pair.New(rect,HandleSupportPower(kv.Key, manager))); + + y += 51; + } + } + + Action HandleSupportPower(string key, SupportPowerManager manager) + { + return mi => { if (mi.Button == MouseButton.Left) manager.Target(key); }; + } + } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs b/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs index 3bbee35d3b..41b8ebc1fe 100755 --- a/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs +++ b/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs @@ -1,96 +1,96 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Drawing; -using System.Linq; -using OpenRA.Graphics; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets -{ - public class WorldTooltipWidget : Widget - { - public int TooltipDelay = 10; - readonly World world; - [ObjectCreator.UseCtor] - public WorldTooltipWidget( [ObjectCreator.Param] World world ) - { - this.world = world; - } - - public override void DrawInner() - { - if (Viewport.TicksSinceLastMove < TooltipDelay || world == null || world.LocalPlayer == null) - return; - - var cell = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); - if (!world.Map.IsInMap(cell)) return; - - if (!world.LocalPlayer.Shroud.IsExplored(cell)) - { - var utext = "Unexplored Terrain"; - var usz = Game.Renderer.BoldFont.Measure(utext) + new int2(20, 24); - - WidgetUtils.DrawPanel("dialog4", Rectangle.FromLTRB( - Viewport.LastMousePos.X + 20, Viewport.LastMousePos.Y + 20, - Viewport.LastMousePos.X + usz.X + 20, Viewport.LastMousePos.Y + usz.Y + 20)); - - Game.Renderer.BoldFont.DrawText(utext, - new float2(Viewport.LastMousePos.X + 30, Viewport.LastMousePos.Y + 30), Color.White); - - return; - } - - var actor = world.FindUnitsAtMouse(Viewport.LastMousePos).FirstOrDefault(); - if (actor == null) - return; - - var text = actor.Info.Traits.Contains() - ? actor.Info.Traits.Get().Name - : actor.Info.Name; - var text2 = (actor.Owner.NonCombatant) - ? "" : "{0}".F(actor.Owner.PlayerName); - var text3 = (actor.Owner == world.LocalPlayer || actor.Owner.NonCombatant) - ? "" : " ({0})".F(world.LocalPlayer.Stances[actor.Owner]); - - var sz = Game.Renderer.BoldFont.Measure(text); - var sz2 = Game.Renderer.RegularFont.Measure(text2); - var sz3 = Game.Renderer.RegularFont.Measure(text3); - - sz.X = Math.Max(sz.X, sz2.X + sz3.X + 35); - - if (text2 != "") sz.Y += sz2.Y + 2; - - sz.X += 20; - sz.Y += 24; - - WidgetUtils.DrawPanel("dialog4", Rectangle.FromLTRB( - Viewport.LastMousePos.X + 20, Viewport.LastMousePos.Y + 20, - Viewport.LastMousePos.X + sz.X + 20, Viewport.LastMousePos.Y + sz.Y + 20)); - - Game.Renderer.BoldFont.DrawText(text, - new float2(Viewport.LastMousePos.X + 30, Viewport.LastMousePos.Y + 30), Color.White); - - if (text2 != "") - { - Game.Renderer.RegularFont.DrawText(text2, - new float2(Viewport.LastMousePos.X + 65, Viewport.LastMousePos.Y + 50), actor.Owner.ColorRamp.GetColor(0)); - - Game.Renderer.RegularFont.DrawText(text3, - new float2(Viewport.LastMousePos.X + 65 + sz2.X, Viewport.LastMousePos.Y + 50), Color.White); - - WidgetUtils.DrawRGBA( - ChromeProvider.GetImage("flags", actor.Owner.Country.Race), - new float2(Viewport.LastMousePos.X + 30, Viewport.LastMousePos.Y + 50)); - } - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Drawing; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets +{ + public class WorldTooltipWidget : Widget + { + public int TooltipDelay = 10; + readonly World world; + [ObjectCreator.UseCtor] + public WorldTooltipWidget( [ObjectCreator.Param] World world ) + { + this.world = world; + } + + public override void DrawInner() + { + if (Viewport.TicksSinceLastMove < TooltipDelay || world == null || world.LocalPlayer == null) + return; + + var cell = Game.viewport.ViewToWorld(Viewport.LastMousePos).ToInt2(); + if (!world.Map.IsInMap(cell)) return; + + if (!world.LocalPlayer.Shroud.IsExplored(cell)) + { + var utext = "Unexplored Terrain"; + var usz = Game.Renderer.BoldFont.Measure(utext) + new int2(20, 24); + + WidgetUtils.DrawPanel("dialog4", Rectangle.FromLTRB( + Viewport.LastMousePos.X + 20, Viewport.LastMousePos.Y + 20, + Viewport.LastMousePos.X + usz.X + 20, Viewport.LastMousePos.Y + usz.Y + 20)); + + Game.Renderer.BoldFont.DrawText(utext, + new float2(Viewport.LastMousePos.X + 30, Viewport.LastMousePos.Y + 30), Color.White); + + return; + } + + var actor = world.FindUnitsAtMouse(Viewport.LastMousePos).FirstOrDefault(); + if (actor == null) + return; + + var text = actor.Info.Traits.Contains() + ? actor.Info.Traits.Get().Name + : actor.Info.Name; + var text2 = (actor.Owner.NonCombatant) + ? "" : "{0}".F(actor.Owner.PlayerName); + var text3 = (actor.Owner == world.LocalPlayer || actor.Owner.NonCombatant) + ? "" : " ({0})".F(world.LocalPlayer.Stances[actor.Owner]); + + var sz = Game.Renderer.BoldFont.Measure(text); + var sz2 = Game.Renderer.RegularFont.Measure(text2); + var sz3 = Game.Renderer.RegularFont.Measure(text3); + + sz.X = Math.Max(sz.X, sz2.X + sz3.X + 35); + + if (text2 != "") sz.Y += sz2.Y + 2; + + sz.X += 20; + sz.Y += 24; + + WidgetUtils.DrawPanel("dialog4", Rectangle.FromLTRB( + Viewport.LastMousePos.X + 20, Viewport.LastMousePos.Y + 20, + Viewport.LastMousePos.X + sz.X + 20, Viewport.LastMousePos.Y + sz.Y + 20)); + + Game.Renderer.BoldFont.DrawText(text, + new float2(Viewport.LastMousePos.X + 30, Viewport.LastMousePos.Y + 30), Color.White); + + if (text2 != "") + { + Game.Renderer.RegularFont.DrawText(text2, + new float2(Viewport.LastMousePos.X + 65, Viewport.LastMousePos.Y + 50), actor.Owner.ColorRamp.GetColor(0)); + + Game.Renderer.RegularFont.DrawText(text3, + new float2(Viewport.LastMousePos.X + 65 + sz2.X, Viewport.LastMousePos.Y + 50), Color.White); + + WidgetUtils.DrawRGBA( + ChromeProvider.GetImage("flags", actor.Owner.Country.Race), + new float2(Viewport.LastMousePos.X + 30, Viewport.LastMousePos.Y + 50)); + } + } + } +} diff --git a/OpenRA.Mods.RA/WithMuzzleFlash.cs b/OpenRA.Mods.RA/WithMuzzleFlash.cs index 810306a3e4..3247538b0b 100644 --- a/OpenRA.Mods.RA/WithMuzzleFlash.cs +++ b/OpenRA.Mods.RA/WithMuzzleFlash.cs @@ -1,55 +1,55 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class WithMuzzleFlashInfo : ITraitInfo, ITraitPrerequisite - { - public object Create(ActorInitializer init) { return new WithMuzzleFlash(init.self); } - } - - class WithMuzzleFlash : INotifyAttack - { - List muzzleFlashes = new List(); - bool isShowing; - - public WithMuzzleFlash(Actor self) - { - var attack = self.Trait(); - var render = self.Trait(); - var facing = self.Trait(); - - foreach (var t in attack.Turrets) - { - var turret = t; - var muzzleFlash = new Animation(render.GetImage(self), () => self.Trait().Facing); - muzzleFlash.Play("muzzle"); - - render.anims.Add("muzzle{0}".F(muzzleFlashes.Count), new RenderSimple.AnimationWithOffset( - muzzleFlash, - () => Combat.GetTurretPosition(self, facing, turret), - () => !isShowing)); - - muzzleFlashes.Add(muzzleFlash); - } - } - - public void Attacking(Actor self, Target target) - { - isShowing = true; - foreach( var mf in muzzleFlashes ) - mf.PlayThen("muzzle", () => isShowing = false); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class WithMuzzleFlashInfo : ITraitInfo, ITraitPrerequisite + { + public object Create(ActorInitializer init) { return new WithMuzzleFlash(init.self); } + } + + class WithMuzzleFlash : INotifyAttack + { + List muzzleFlashes = new List(); + bool isShowing; + + public WithMuzzleFlash(Actor self) + { + var attack = self.Trait(); + var render = self.Trait(); + var facing = self.Trait(); + + foreach (var t in attack.Turrets) + { + var turret = t; + var muzzleFlash = new Animation(render.GetImage(self), () => self.Trait().Facing); + muzzleFlash.Play("muzzle"); + + render.anims.Add("muzzle{0}".F(muzzleFlashes.Count), new RenderSimple.AnimationWithOffset( + muzzleFlash, + () => Combat.GetTurretPosition(self, facing, turret), + () => !isShowing)); + + muzzleFlashes.Add(muzzleFlash); + } + } + + public void Attacking(Actor self, Target target) + { + isShowing = true; + foreach( var mf in muzzleFlashes ) + mf.PlayThen("muzzle", () => isShowing = false); + } + } +} diff --git a/OpenRA.Mods.RA/WithShadow.cs b/OpenRA.Mods.RA/WithShadow.cs index 0566207df4..6a37e80865 100644 --- a/OpenRA.Mods.RA/WithShadow.cs +++ b/OpenRA.Mods.RA/WithShadow.cs @@ -1,32 +1,32 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Collections.Generic; -using System.Linq; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - class WithShadowInfo : TraitInfo {} - - class WithShadow : IRenderModifier - { - public IEnumerable ModifyRender(Actor self, IEnumerable r) - { - var move = self.Trait(); - - var shadowSprites = r.Select(a => a.WithPalette("shadow")); - var flyingSprites = (move.Altitude <= 0) ? r - : r.Select(a => a.WithPos(a.Pos - new float2(0, move.Altitude)).WithZOffset(move.Altitude)); - - return shadowSprites.Concat(flyingSprites); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class WithShadowInfo : TraitInfo {} + + class WithShadow : IRenderModifier + { + public IEnumerable ModifyRender(Actor self, IEnumerable r) + { + var move = self.Trait(); + + var shadowSprites = r.Select(a => a.WithPalette("shadow")); + var flyingSprites = (move.Altitude <= 0) ? r + : r.Select(a => a.WithPos(a.Pos - new float2(0, move.Altitude)).WithZOffset(move.Altitude)); + + return shadowSprites.Concat(flyingSprites); + } + } +} diff --git a/OpenRA.Mods.RA/World/ChooseBuildTabOnSelect.cs b/OpenRA.Mods.RA/World/ChooseBuildTabOnSelect.cs index 3554203339..83e2172c59 100644 --- a/OpenRA.Mods.RA/World/ChooseBuildTabOnSelect.cs +++ b/OpenRA.Mods.RA/World/ChooseBuildTabOnSelect.cs @@ -1,57 +1,57 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Linq; -using OpenRA.Traits; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets -{ - class ChooseBuildTabOnSelectInfo : ITraitInfo - { - public object Create( ActorInitializer init ) { return new ChooseBuildTabOnSelect( init ); } - } - - class ChooseBuildTabOnSelect : INotifySelection - { - readonly World world; - - public ChooseBuildTabOnSelect( ActorInitializer init ) - { - world = init.world; - } - - public void SelectionChanged() - { - // Queue-per-structure - var perqueue = world.Selection.Actors.FirstOrDefault( - a => a.IsInWorld && a.World.LocalPlayer == a.Owner && a.HasTrait()); - - if (perqueue != null) - { - Widget.RootWidget.GetWidget("INGAME_BUILD_PALETTE") - .SetCurrentTab(perqueue.TraitsImplementing().First()); - return; - } - - // Queue-per-player - var types = world.Selection.Actors.Where(a => a.IsInWorld && (a.World.LocalPlayer == a.Owner)) - .SelectMany(a => a.TraitsImplementing()) - .SelectMany(t => t.Info.Produces) - .Distinct(); - - if (types.Count() == 0) - return; - - Widget.RootWidget.GetWidget("INGAME_BUILD_PALETTE") - .SetCurrentTab(world.LocalPlayer.PlayerActor.TraitsImplementing().FirstOrDefault(t => types.Contains(t.Info.Type))); - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; +using OpenRA.Widgets; + +namespace OpenRA.Mods.RA.Widgets +{ + class ChooseBuildTabOnSelectInfo : ITraitInfo + { + public object Create( ActorInitializer init ) { return new ChooseBuildTabOnSelect( init ); } + } + + class ChooseBuildTabOnSelect : INotifySelection + { + readonly World world; + + public ChooseBuildTabOnSelect( ActorInitializer init ) + { + world = init.world; + } + + public void SelectionChanged() + { + // Queue-per-structure + var perqueue = world.Selection.Actors.FirstOrDefault( + a => a.IsInWorld && a.World.LocalPlayer == a.Owner && a.HasTrait()); + + if (perqueue != null) + { + Widget.RootWidget.GetWidget("INGAME_BUILD_PALETTE") + .SetCurrentTab(perqueue.TraitsImplementing().First()); + return; + } + + // Queue-per-player + var types = world.Selection.Actors.Where(a => a.IsInWorld && (a.World.LocalPlayer == a.Owner)) + .SelectMany(a => a.TraitsImplementing()) + .SelectMany(t => t.Info.Produces) + .Distinct(); + + if (types.Count() == 0) + return; + + Widget.RootWidget.GetWidget("INGAME_BUILD_PALETTE") + .SetCurrentTab(world.LocalPlayer.PlayerActor.TraitsImplementing().FirstOrDefault(t => types.Contains(t.Info.Type))); + } + } +} diff --git a/OpenRA.Mods.RA/World/SmudgeLayer.cs b/OpenRA.Mods.RA/World/SmudgeLayer.cs index 6d6deba065..d9db41794d 100755 --- a/OpenRA.Mods.RA/World/SmudgeLayer.cs +++ b/OpenRA.Mods.RA/World/SmudgeLayer.cs @@ -1,20 +1,20 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using OpenRA.FileFormats; -using OpenRA.Graphics; -using OpenRA.Traits; +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; using OpenRA.Mods.RA.Effects; namespace OpenRA.Mods.RA @@ -23,15 +23,15 @@ namespace OpenRA.Mods.RA { public readonly string Type = "Scorch"; public readonly string[] Types = {"sc1", "sc2", "sc3", "sc4", "sc5", "sc6"}; - public readonly int[] Depths = {1,1,1,1,1,1}; - public readonly int SmokePercentage = 25; + public readonly int[] Depths = {1,1,1,1,1,1}; + public readonly int SmokePercentage = 25; public readonly string SmokeType = "smoke_m"; public object Create(ActorInitializer init) { return new SmudgeLayer(this); } } public class SmudgeLayer: IRenderOverlay, IWorldLoaded { - public SmudgeLayerInfo Info; + public SmudgeLayerInfo Info; Dictionary> tiles; Sprite[][] smudgeSprites; World world; @@ -54,11 +54,11 @@ namespace OpenRA.Mods.RA } public void AddSmudge(int2 loc) - { - if (!world.GetTerrainInfo(loc).AcceptSmudge) - return; - - if (Game.CosmeticRandom.Next(0,100) <= Info.SmokePercentage) + { + if (!world.GetTerrainInfo(loc).AcceptSmudge) + return; + + if (Game.CosmeticRandom.Next(0,100) <= Info.SmokePercentage) world.AddFrameEndTask(w => w.Add(new Smoke(w, Traits.Util.CenterOfCell(loc), Info.SmokeType))); // No smudge; create a new one @@ -68,30 +68,30 @@ namespace OpenRA.Mods.RA tiles.Add(loc, new TileReference(st,(byte)0)); return; } - + var tile = tiles[loc]; // Existing smudge; make it deeper - int depth = Info.Depths[tile.type-1]; - if (tile.index < depth - 1) - { - tile.index++; - tiles[loc] = tile; // struct semantics. + int depth = Info.Depths[tile.type-1]; + if (tile.index < depth - 1) + { + tile.index++; + tiles[loc] = tile; // struct semantics. } } public void Render( WorldRenderer wr ) - { - var cliprect = Game.viewport.WorldBounds(world); - var localPlayer = world.LocalPlayer; - foreach (var kv in tiles) - { - if (!cliprect.Contains(kv.Key.X,kv.Key.Y)) - continue; - if (localPlayer != null && !localPlayer.Shroud.IsExplored(kv.Key)) - continue; - - smudgeSprites[kv.Value.type- 1][kv.Value.index].DrawAt( wr, - Game.CellSize * kv.Key, "terrain"); + { + var cliprect = Game.viewport.WorldBounds(world); + var localPlayer = world.LocalPlayer; + foreach (var kv in tiles) + { + if (!cliprect.Contains(kv.Key.X,kv.Key.Y)) + continue; + if (localPlayer != null && !localPlayer.Shroud.IsExplored(kv.Key)) + continue; + + smudgeSprites[kv.Value.type- 1][kv.Value.index].DrawAt( wr, + Game.CellSize * kv.Key, "terrain"); } } } diff --git a/OpenRA.Renderer.Cg/GraphicsDevice.cs b/OpenRA.Renderer.Cg/GraphicsDevice.cs index 64f685a49e..b52464b636 100755 --- a/OpenRA.Renderer.Cg/GraphicsDevice.cs +++ b/OpenRA.Renderer.Cg/GraphicsDevice.cs @@ -1,322 +1,322 @@ -#region Copyright & License Information -/* -* Copyright 2007-2010 The OpenRA Developers (see AUTHORS) -* This file is part of OpenRA, which is free software. It is made -* available to you under the terms of the GNU General Public License -* as published by the Free Software Foundation. For more information, -* see LICENSE. -*/ -#endregion - -using System; -using System.Drawing; -using System.IO; -using OpenRA.FileFormats.Graphics; -using Tao.Cg; -using Tao.OpenGl; -using Tao.Sdl; - -[assembly: Renderer(typeof(OpenRA.Renderer.Cg.GraphicsDevice))] - -namespace OpenRA.Renderer.Cg -{ - public class GraphicsDevice : IGraphicsDevice - { - Size windowSize; - internal IntPtr cgContext; - internal int vertexProfile, fragmentProfile; - - IntPtr surf; - - public Size WindowSize { get { return windowSize; } } - - public enum GlError - { - GL_NO_ERROR = Gl.GL_NO_ERROR, - GL_INVALID_ENUM = Gl.GL_INVALID_ENUM, - GL_INVALID_VALUE = Gl.GL_INVALID_VALUE, - GL_STACK_OVERFLOW = Gl.GL_STACK_OVERFLOW, - GL_STACK_UNDERFLOW = Gl.GL_STACK_UNDERFLOW, - GL_OUT_OF_MEMORY = Gl.GL_OUT_OF_MEMORY, - GL_TABLE_TOO_LARGE = Gl.GL_TABLE_TOO_LARGE, - } - - internal static void CheckGlError() - { - var n = Gl.glGetError(); - if( n != Gl.GL_NO_ERROR ) - throw new InvalidOperationException( "GL Error: " + ( (GlError)n ).ToString() ); - } - - public GraphicsDevice( int width, int height, WindowMode window, bool vsync ) - { - Console.WriteLine("Using Cg renderer"); - Sdl.SDL_Init( Sdl.SDL_INIT_NOPARACHUTE | Sdl.SDL_INIT_VIDEO ); - Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_DOUBLEBUFFER, 1 ); - Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_RED_SIZE, 8 ); - Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_GREEN_SIZE, 8 ); - Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_BLUE_SIZE, 8 ); - Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_ALPHA_SIZE, 0 ); - - int windowFlags = 0; - switch( window ) - { - case WindowMode.Fullscreen: - windowFlags |= Sdl.SDL_FULLSCREEN; - break; - case WindowMode.PseudoFullscreen: - windowFlags |= Sdl.SDL_NOFRAME; - Environment.SetEnvironmentVariable( "SDL_VIDEO_WINDOW_POS", "0,0" ); - break; - case WindowMode.Windowed: - Environment.SetEnvironmentVariable( "SDL_VIDEO_CENTERED", "1" ); - break; - default: - break; - } - - surf = Sdl.SDL_SetVideoMode( width, height, 0, Sdl.SDL_OPENGL | windowFlags ); - - Sdl.SDL_WM_SetCaption( "OpenRA", "OpenRA" ); - Sdl.SDL_ShowCursor( 0 ); - Sdl.SDL_EnableUNICODE( 1 ); - Sdl.SDL_EnableKeyRepeat( Sdl.SDL_DEFAULT_REPEAT_DELAY, Sdl.SDL_DEFAULT_REPEAT_INTERVAL ); - - CheckGlError(); - - windowSize = new Size( width, height ); - - cgContext = Tao.Cg.Cg.cgCreateContext(); - - Tao.Cg.Cg.cgSetErrorCallback( CgErrorCallback ); - - Tao.Cg.CgGl.cgGLRegisterStates( cgContext ); - Tao.Cg.CgGl.cgGLSetManageTextureParameters( cgContext, true ); - vertexProfile = CgGl.cgGLGetLatestProfile( CgGl.CG_GL_VERTEX ); - fragmentProfile = CgGl.cgGLGetLatestProfile( CgGl.CG_GL_FRAGMENT ); - - //Console.WriteLine("VP Profile: " + vertexProfile); - //Console.WriteLine("FP Profile: " + fragmentProfile); - - Gl.glEnableClientState( Gl.GL_VERTEX_ARRAY ); - CheckGlError(); - Gl.glEnableClientState( Gl.GL_TEXTURE_COORD_ARRAY ); - CheckGlError(); - - Sdl.SDL_SetModState( 0 ); // i have had enough. - } - - static Tao.Cg.Cg.CGerrorCallbackFuncDelegate CgErrorCallback = () => - { - var err = Tao.Cg.Cg.cgGetError(); - var str = Tao.Cg.Cg.cgGetErrorString( err ); - throw new InvalidOperationException( - string.Format( "CG Error: {0}: {1}", err, str ) ); - }; - - public void EnableScissor( int left, int top, int width, int height ) - { - if( width < 0 ) width = 0; - if( height < 0 ) height = 0; - Gl.glScissor( left, windowSize.Height - ( top + height ), width, height ); - CheckGlError(); - Gl.glEnable( Gl.GL_SCISSOR_TEST ); - CheckGlError(); - } - - public void DisableScissor() - { - Gl.glDisable( Gl.GL_SCISSOR_TEST ); - CheckGlError(); - } - - public void Clear( Color c ) - { - Gl.glClearColor( 0, 0, 0, 0 ); - CheckGlError(); - Gl.glClear( Gl.GL_COLOR_BUFFER_BIT ); - CheckGlError(); - } - - MouseButton lastButtonBits = (MouseButton)0; - - MouseButton MakeButton( byte b ) - { - return b == Sdl.SDL_BUTTON_LEFT ? MouseButton.Left - : b == Sdl.SDL_BUTTON_RIGHT ? MouseButton.Right - : b == Sdl.SDL_BUTTON_MIDDLE ? MouseButton.Middle - : b == Sdl.SDL_BUTTON_WHEELDOWN ? MouseButton.WheelDown - : b == Sdl.SDL_BUTTON_WHEELUP ? MouseButton.WheelUp - : 0; - } - - Modifiers MakeModifiers( int raw ) - { - return ( ( raw & Sdl.KMOD_ALT ) != 0 ? Modifiers.Alt : 0 ) - | ( ( raw & Sdl.KMOD_CTRL ) != 0 ? Modifiers.Ctrl : 0 ) - | ( ( raw & Sdl.KMOD_SHIFT ) != 0 ? Modifiers.Shift : 0 ); - } - - bool HandleSpecialKey( KeyInput k ) - { - switch( k.VirtKey ) - { - case Sdl.SDLK_F13: - var path = Environment.GetFolderPath( Environment.SpecialFolder.Personal ) - + Path.DirectorySeparatorChar + DateTime.UtcNow.ToString( "OpenRA-yyyy-MM-ddThhmmssZ" ) + ".bmp"; - Sdl.SDL_SaveBMP( surf, path ); - return true; - - case Sdl.SDLK_F4: - if( k.Modifiers.HasModifier( Modifiers.Alt ) ) - { - OpenRA.Game.Exit(); - return true; - } - return false; - - default: - return false; - } - } - - public void Present( IInputHandler inputHandler ) - { - Sdl.SDL_GL_SwapBuffers(); - Game.HasInputFocus = 0 != ( Sdl.SDL_GetAppState() & Sdl.SDL_APPINPUTFOCUS ); - - var mods = MakeModifiers( Sdl.SDL_GetModState() ); - inputHandler.ModifierKeys( mods ); - MouseInput? pendingMotion = null; - - Sdl.SDL_Event e; - while( Sdl.SDL_PollEvent( out e ) != 0 ) - { - switch( e.type ) - { - case Sdl.SDL_QUIT: - OpenRA.Game.Exit(); - break; - - case Sdl.SDL_MOUSEBUTTONDOWN: - { - if( pendingMotion != null ) - { - inputHandler.OnMouseInput( pendingMotion.Value ); - pendingMotion = null; - } - - var button = MakeButton( e.button.button ); - lastButtonBits |= button; - - inputHandler.OnMouseInput( new MouseInput( - MouseInputEvent.Down, button, new int2( e.button.x, e.button.y ), mods ) ); - } break; - - case Sdl.SDL_MOUSEBUTTONUP: - { - if( pendingMotion != null ) - { - inputHandler.OnMouseInput( pendingMotion.Value ); - pendingMotion = null; - } - - var button = MakeButton( e.button.button ); - lastButtonBits &= ~button; - - inputHandler.OnMouseInput( new MouseInput( - MouseInputEvent.Up, button, new int2( e.button.x, e.button.y ), mods ) ); - } break; - - case Sdl.SDL_MOUSEMOTION: - { - pendingMotion = new MouseInput( - MouseInputEvent.Move, - lastButtonBits, - new int2( e.motion.x, e.motion.y ), - mods ); - } break; - - case Sdl.SDL_KEYDOWN: - { - var keyEvent = new KeyInput - { - Event = KeyInputEvent.Down, - Modifiers = mods, - KeyChar = (char)e.key.keysym.unicode, - KeyName = Sdl.SDL_GetKeyName( e.key.keysym.sym ), - VirtKey = e.key.keysym.sym - }; - - if( !HandleSpecialKey( keyEvent ) ) - inputHandler.OnKeyInput( keyEvent ); - } break; - - case Sdl.SDL_KEYUP: - { - var keyEvent = new KeyInput - { - Event = KeyInputEvent.Up, - Modifiers = mods, - KeyChar = (char)e.key.keysym.unicode, - KeyName = Sdl.SDL_GetKeyName( e.key.keysym.sym ), - VirtKey = e.key.keysym.sym - }; - - inputHandler.OnKeyInput( keyEvent ); - } break; - } - } - - if( pendingMotion != null ) - { - inputHandler.OnMouseInput( pendingMotion.Value ); - pendingMotion = null; - } - - CheckGlError(); - } - - public void DrawIndexedPrimitives( PrimitiveType pt, Range vertices, Range indices ) - { - Gl.glDrawElements( ModeFromPrimitiveType( pt ), indices.End - indices.Start, - Gl.GL_UNSIGNED_SHORT, new IntPtr( indices.Start * 2 ) ); - CheckGlError(); - } - - public void DrawIndexedPrimitives( PrimitiveType pt, int numVerts, int numPrimitives ) - { - Gl.glDrawElements( ModeFromPrimitiveType( pt ), numPrimitives * IndicesPerPrimitive( pt ), - Gl.GL_UNSIGNED_SHORT, IntPtr.Zero ); - CheckGlError(); - } - - static int ModeFromPrimitiveType( PrimitiveType pt ) - { - switch( pt ) - { - case PrimitiveType.PointList: return Gl.GL_POINTS; - case PrimitiveType.LineList: return Gl.GL_LINES; - case PrimitiveType.TriangleList: return Gl.GL_TRIANGLES; - } - throw new NotImplementedException(); - } - - static int IndicesPerPrimitive( PrimitiveType pt ) - { - switch( pt ) - { - case PrimitiveType.PointList: return 1; - case PrimitiveType.LineList: return 2; - case PrimitiveType.TriangleList: return 3; - } - throw new NotImplementedException(); - } - - public IVertexBuffer CreateVertexBuffer( int size ) { return new VertexBuffer( this, size ); } - public IIndexBuffer CreateIndexBuffer( int size ) { return new IndexBuffer( this, size ); } - public ITexture CreateTexture() { return new Texture( this ); } - public ITexture CreateTexture( Bitmap bitmap ) { return new Texture( this, bitmap ); } - public IShader CreateShader( string name ) { return new Shader( this, name ); } - } -} +#region Copyright & License Information +/* +* Copyright 2007-2011 The OpenRA Developers (see AUTHORS) +* This file is part of OpenRA, which is free software. It is made +* available to you under the terms of the GNU General Public License +* as published by the Free Software Foundation. For more information, +* see COPYING. +*/ +#endregion + +using System; +using System.Drawing; +using System.IO; +using OpenRA.FileFormats.Graphics; +using Tao.Cg; +using Tao.OpenGl; +using Tao.Sdl; + +[assembly: Renderer(typeof(OpenRA.Renderer.Cg.GraphicsDevice))] + +namespace OpenRA.Renderer.Cg +{ + public class GraphicsDevice : IGraphicsDevice + { + Size windowSize; + internal IntPtr cgContext; + internal int vertexProfile, fragmentProfile; + + IntPtr surf; + + public Size WindowSize { get { return windowSize; } } + + public enum GlError + { + GL_NO_ERROR = Gl.GL_NO_ERROR, + GL_INVALID_ENUM = Gl.GL_INVALID_ENUM, + GL_INVALID_VALUE = Gl.GL_INVALID_VALUE, + GL_STACK_OVERFLOW = Gl.GL_STACK_OVERFLOW, + GL_STACK_UNDERFLOW = Gl.GL_STACK_UNDERFLOW, + GL_OUT_OF_MEMORY = Gl.GL_OUT_OF_MEMORY, + GL_TABLE_TOO_LARGE = Gl.GL_TABLE_TOO_LARGE, + } + + internal static void CheckGlError() + { + var n = Gl.glGetError(); + if( n != Gl.GL_NO_ERROR ) + throw new InvalidOperationException( "GL Error: " + ( (GlError)n ).ToString() ); + } + + public GraphicsDevice( int width, int height, WindowMode window, bool vsync ) + { + Console.WriteLine("Using Cg renderer"); + Sdl.SDL_Init( Sdl.SDL_INIT_NOPARACHUTE | Sdl.SDL_INIT_VIDEO ); + Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_DOUBLEBUFFER, 1 ); + Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_RED_SIZE, 8 ); + Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_GREEN_SIZE, 8 ); + Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_BLUE_SIZE, 8 ); + Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_ALPHA_SIZE, 0 ); + + int windowFlags = 0; + switch( window ) + { + case WindowMode.Fullscreen: + windowFlags |= Sdl.SDL_FULLSCREEN; + break; + case WindowMode.PseudoFullscreen: + windowFlags |= Sdl.SDL_NOFRAME; + Environment.SetEnvironmentVariable( "SDL_VIDEO_WINDOW_POS", "0,0" ); + break; + case WindowMode.Windowed: + Environment.SetEnvironmentVariable( "SDL_VIDEO_CENTERED", "1" ); + break; + default: + break; + } + + surf = Sdl.SDL_SetVideoMode( width, height, 0, Sdl.SDL_OPENGL | windowFlags ); + + Sdl.SDL_WM_SetCaption( "OpenRA", "OpenRA" ); + Sdl.SDL_ShowCursor( 0 ); + Sdl.SDL_EnableUNICODE( 1 ); + Sdl.SDL_EnableKeyRepeat( Sdl.SDL_DEFAULT_REPEAT_DELAY, Sdl.SDL_DEFAULT_REPEAT_INTERVAL ); + + CheckGlError(); + + windowSize = new Size( width, height ); + + cgContext = Tao.Cg.Cg.cgCreateContext(); + + Tao.Cg.Cg.cgSetErrorCallback( CgErrorCallback ); + + Tao.Cg.CgGl.cgGLRegisterStates( cgContext ); + Tao.Cg.CgGl.cgGLSetManageTextureParameters( cgContext, true ); + vertexProfile = CgGl.cgGLGetLatestProfile( CgGl.CG_GL_VERTEX ); + fragmentProfile = CgGl.cgGLGetLatestProfile( CgGl.CG_GL_FRAGMENT ); + + //Console.WriteLine("VP Profile: " + vertexProfile); + //Console.WriteLine("FP Profile: " + fragmentProfile); + + Gl.glEnableClientState( Gl.GL_VERTEX_ARRAY ); + CheckGlError(); + Gl.glEnableClientState( Gl.GL_TEXTURE_COORD_ARRAY ); + CheckGlError(); + + Sdl.SDL_SetModState( 0 ); // i have had enough. + } + + static Tao.Cg.Cg.CGerrorCallbackFuncDelegate CgErrorCallback = () => + { + var err = Tao.Cg.Cg.cgGetError(); + var str = Tao.Cg.Cg.cgGetErrorString( err ); + throw new InvalidOperationException( + string.Format( "CG Error: {0}: {1}", err, str ) ); + }; + + public void EnableScissor( int left, int top, int width, int height ) + { + if( width < 0 ) width = 0; + if( height < 0 ) height = 0; + Gl.glScissor( left, windowSize.Height - ( top + height ), width, height ); + CheckGlError(); + Gl.glEnable( Gl.GL_SCISSOR_TEST ); + CheckGlError(); + } + + public void DisableScissor() + { + Gl.glDisable( Gl.GL_SCISSOR_TEST ); + CheckGlError(); + } + + public void Clear( Color c ) + { + Gl.glClearColor( 0, 0, 0, 0 ); + CheckGlError(); + Gl.glClear( Gl.GL_COLOR_BUFFER_BIT ); + CheckGlError(); + } + + MouseButton lastButtonBits = (MouseButton)0; + + MouseButton MakeButton( byte b ) + { + return b == Sdl.SDL_BUTTON_LEFT ? MouseButton.Left + : b == Sdl.SDL_BUTTON_RIGHT ? MouseButton.Right + : b == Sdl.SDL_BUTTON_MIDDLE ? MouseButton.Middle + : b == Sdl.SDL_BUTTON_WHEELDOWN ? MouseButton.WheelDown + : b == Sdl.SDL_BUTTON_WHEELUP ? MouseButton.WheelUp + : 0; + } + + Modifiers MakeModifiers( int raw ) + { + return ( ( raw & Sdl.KMOD_ALT ) != 0 ? Modifiers.Alt : 0 ) + | ( ( raw & Sdl.KMOD_CTRL ) != 0 ? Modifiers.Ctrl : 0 ) + | ( ( raw & Sdl.KMOD_SHIFT ) != 0 ? Modifiers.Shift : 0 ); + } + + bool HandleSpecialKey( KeyInput k ) + { + switch( k.VirtKey ) + { + case Sdl.SDLK_F13: + var path = Environment.GetFolderPath( Environment.SpecialFolder.Personal ) + + Path.DirectorySeparatorChar + DateTime.UtcNow.ToString( "OpenRA-yyyy-MM-ddThhmmssZ" ) + ".bmp"; + Sdl.SDL_SaveBMP( surf, path ); + return true; + + case Sdl.SDLK_F4: + if( k.Modifiers.HasModifier( Modifiers.Alt ) ) + { + OpenRA.Game.Exit(); + return true; + } + return false; + + default: + return false; + } + } + + public void Present( IInputHandler inputHandler ) + { + Sdl.SDL_GL_SwapBuffers(); + Game.HasInputFocus = 0 != ( Sdl.SDL_GetAppState() & Sdl.SDL_APPINPUTFOCUS ); + + var mods = MakeModifiers( Sdl.SDL_GetModState() ); + inputHandler.ModifierKeys( mods ); + MouseInput? pendingMotion = null; + + Sdl.SDL_Event e; + while( Sdl.SDL_PollEvent( out e ) != 0 ) + { + switch( e.type ) + { + case Sdl.SDL_QUIT: + OpenRA.Game.Exit(); + break; + + case Sdl.SDL_MOUSEBUTTONDOWN: + { + if( pendingMotion != null ) + { + inputHandler.OnMouseInput( pendingMotion.Value ); + pendingMotion = null; + } + + var button = MakeButton( e.button.button ); + lastButtonBits |= button; + + inputHandler.OnMouseInput( new MouseInput( + MouseInputEvent.Down, button, new int2( e.button.x, e.button.y ), mods ) ); + } break; + + case Sdl.SDL_MOUSEBUTTONUP: + { + if( pendingMotion != null ) + { + inputHandler.OnMouseInput( pendingMotion.Value ); + pendingMotion = null; + } + + var button = MakeButton( e.button.button ); + lastButtonBits &= ~button; + + inputHandler.OnMouseInput( new MouseInput( + MouseInputEvent.Up, button, new int2( e.button.x, e.button.y ), mods ) ); + } break; + + case Sdl.SDL_MOUSEMOTION: + { + pendingMotion = new MouseInput( + MouseInputEvent.Move, + lastButtonBits, + new int2( e.motion.x, e.motion.y ), + mods ); + } break; + + case Sdl.SDL_KEYDOWN: + { + var keyEvent = new KeyInput + { + Event = KeyInputEvent.Down, + Modifiers = mods, + KeyChar = (char)e.key.keysym.unicode, + KeyName = Sdl.SDL_GetKeyName( e.key.keysym.sym ), + VirtKey = e.key.keysym.sym + }; + + if( !HandleSpecialKey( keyEvent ) ) + inputHandler.OnKeyInput( keyEvent ); + } break; + + case Sdl.SDL_KEYUP: + { + var keyEvent = new KeyInput + { + Event = KeyInputEvent.Up, + Modifiers = mods, + KeyChar = (char)e.key.keysym.unicode, + KeyName = Sdl.SDL_GetKeyName( e.key.keysym.sym ), + VirtKey = e.key.keysym.sym + }; + + inputHandler.OnKeyInput( keyEvent ); + } break; + } + } + + if( pendingMotion != null ) + { + inputHandler.OnMouseInput( pendingMotion.Value ); + pendingMotion = null; + } + + CheckGlError(); + } + + public void DrawIndexedPrimitives( PrimitiveType pt, Range vertices, Range indices ) + { + Gl.glDrawElements( ModeFromPrimitiveType( pt ), indices.End - indices.Start, + Gl.GL_UNSIGNED_SHORT, new IntPtr( indices.Start * 2 ) ); + CheckGlError(); + } + + public void DrawIndexedPrimitives( PrimitiveType pt, int numVerts, int numPrimitives ) + { + Gl.glDrawElements( ModeFromPrimitiveType( pt ), numPrimitives * IndicesPerPrimitive( pt ), + Gl.GL_UNSIGNED_SHORT, IntPtr.Zero ); + CheckGlError(); + } + + static int ModeFromPrimitiveType( PrimitiveType pt ) + { + switch( pt ) + { + case PrimitiveType.PointList: return Gl.GL_POINTS; + case PrimitiveType.LineList: return Gl.GL_LINES; + case PrimitiveType.TriangleList: return Gl.GL_TRIANGLES; + } + throw new NotImplementedException(); + } + + static int IndicesPerPrimitive( PrimitiveType pt ) + { + switch( pt ) + { + case PrimitiveType.PointList: return 1; + case PrimitiveType.LineList: return 2; + case PrimitiveType.TriangleList: return 3; + } + throw new NotImplementedException(); + } + + public IVertexBuffer CreateVertexBuffer( int size ) { return new VertexBuffer( this, size ); } + public IIndexBuffer CreateIndexBuffer( int size ) { return new IndexBuffer( this, size ); } + public ITexture CreateTexture() { return new Texture( this ); } + public ITexture CreateTexture( Bitmap bitmap ) { return new Texture( this, bitmap ); } + public IShader CreateShader( string name ) { return new Shader( this, name ); } + } +} diff --git a/OpenRA.Renderer.Cg/IndexBuffer.cs b/OpenRA.Renderer.Cg/IndexBuffer.cs index 82773ee08f..ceb2111389 100644 --- a/OpenRA.Renderer.Cg/IndexBuffer.cs +++ b/OpenRA.Renderer.Cg/IndexBuffer.cs @@ -1,61 +1,61 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.FileFormats.Graphics; -using Tao.OpenGl; - -namespace OpenRA.Renderer.Cg -{ - public class IndexBuffer : IIndexBuffer, IDisposable - { - int buffer; - - public IndexBuffer(GraphicsDevice dev, int size) - { - Gl.glGenBuffers(1, out buffer); - GraphicsDevice.CheckGlError(); - Bind(); - Gl.glBufferData(Gl.GL_ELEMENT_ARRAY_BUFFER, - new IntPtr(2 * size), - new ushort[ size ], - Gl.GL_DYNAMIC_DRAW); - GraphicsDevice.CheckGlError(); - } - - public void SetData(ushort[] data, int length) - { - Bind(); - Gl.glBufferSubData(Gl.GL_ELEMENT_ARRAY_BUFFER, - IntPtr.Zero, - new IntPtr(2 * length), - data); - GraphicsDevice.CheckGlError(); - } - - public void Bind() - { - Gl.glBindBuffer(Gl.GL_ELEMENT_ARRAY_BUFFER, buffer); - GraphicsDevice.CheckGlError(); - } - - bool disposed; - public void Dispose() - { - if (disposed) return; - GC.SuppressFinalize(this); - Gl.glDeleteBuffers(1, ref buffer); - GraphicsDevice.CheckGlError(); - disposed = true; - } - - //~IndexBuffer() { Dispose(); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.FileFormats.Graphics; +using Tao.OpenGl; + +namespace OpenRA.Renderer.Cg +{ + public class IndexBuffer : IIndexBuffer, IDisposable + { + int buffer; + + public IndexBuffer(GraphicsDevice dev, int size) + { + Gl.glGenBuffers(1, out buffer); + GraphicsDevice.CheckGlError(); + Bind(); + Gl.glBufferData(Gl.GL_ELEMENT_ARRAY_BUFFER, + new IntPtr(2 * size), + new ushort[ size ], + Gl.GL_DYNAMIC_DRAW); + GraphicsDevice.CheckGlError(); + } + + public void SetData(ushort[] data, int length) + { + Bind(); + Gl.glBufferSubData(Gl.GL_ELEMENT_ARRAY_BUFFER, + IntPtr.Zero, + new IntPtr(2 * length), + data); + GraphicsDevice.CheckGlError(); + } + + public void Bind() + { + Gl.glBindBuffer(Gl.GL_ELEMENT_ARRAY_BUFFER, buffer); + GraphicsDevice.CheckGlError(); + } + + bool disposed; + public void Dispose() + { + if (disposed) return; + GC.SuppressFinalize(this); + Gl.glDeleteBuffers(1, ref buffer); + GraphicsDevice.CheckGlError(); + disposed = true; + } + + //~IndexBuffer() { Dispose(); } + } +} diff --git a/OpenRA.Renderer.Cg/Shader.cs b/OpenRA.Renderer.Cg/Shader.cs index 843eaf4341..e12056d772 100644 --- a/OpenRA.Renderer.Cg/Shader.cs +++ b/OpenRA.Renderer.Cg/Shader.cs @@ -1,87 +1,87 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.IO; -using OpenRA.FileFormats; -using OpenRA.FileFormats.Graphics; -using Tao.Cg; - -namespace OpenRA.Renderer.Cg -{ - public class Shader : IShader - { - IntPtr effect; - IntPtr technique; - GraphicsDevice dev; - - public Shader(GraphicsDevice dev, string name) - { - this.dev = dev; - string code; - using (var file = new StreamReader(FileSystem.Open("cg{0}{1}.fx".F(Path.DirectorySeparatorChar, name)))) - code = file.ReadToEnd(); - effect = Tao.Cg.Cg.cgCreateEffect(dev.cgContext, code, null); - - if (effect == IntPtr.Zero) - { - var err = Tao.Cg.Cg.cgGetErrorString(Tao.Cg.Cg.cgGetError()); - var results = Tao.Cg.Cg.cgGetLastListing(dev.cgContext); - throw new InvalidOperationException( - string.Format("Cg compile failed ({0}):\n{1}", err, results)); - } - - technique = Tao.Cg.Cg.cgGetFirstTechnique(effect); - if (technique == IntPtr.Zero) - throw new InvalidOperationException("No techniques"); - while (Tao.Cg.Cg.cgValidateTechnique(technique) == 0) - { - technique = Tao.Cg.Cg.cgGetNextTechnique(technique); - if (technique == IntPtr.Zero) - throw new InvalidOperationException("No valid techniques"); - } - } - - public void Render(Action a) - { - Tao.Cg.CgGl.cgGLEnableProfile(dev.vertexProfile); - Tao.Cg.CgGl.cgGLEnableProfile(dev.fragmentProfile); - - var pass = Tao.Cg.Cg.cgGetFirstPass(technique); - while (pass != IntPtr.Zero) - { - Tao.Cg.Cg.cgSetPassState(pass); - a(); - Tao.Cg.Cg.cgResetPassState(pass); - pass = Tao.Cg.Cg.cgGetNextPass(pass); - } - - Tao.Cg.CgGl.cgGLDisableProfile(dev.fragmentProfile); - Tao.Cg.CgGl.cgGLDisableProfile(dev.vertexProfile); - } - - public void SetValue(string name, ITexture t) - { - var texture = (Texture)t; - var param = Tao.Cg.Cg.cgGetNamedEffectParameter(effect, name); - if (param != IntPtr.Zero && texture != null) - Tao.Cg.CgGl.cgGLSetupSampler(param, texture.texture); - } - - public void SetValue(string name, float x, float y) - { - var param = Tao.Cg.Cg.cgGetNamedEffectParameter(effect, name); - if (param != IntPtr.Zero) - Tao.Cg.CgGl.cgGLSetParameter2f(param, x, y); - } - - public void Commit() { } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.IO; +using OpenRA.FileFormats; +using OpenRA.FileFormats.Graphics; +using Tao.Cg; + +namespace OpenRA.Renderer.Cg +{ + public class Shader : IShader + { + IntPtr effect; + IntPtr technique; + GraphicsDevice dev; + + public Shader(GraphicsDevice dev, string name) + { + this.dev = dev; + string code; + using (var file = new StreamReader(FileSystem.Open("cg{0}{1}.fx".F(Path.DirectorySeparatorChar, name)))) + code = file.ReadToEnd(); + effect = Tao.Cg.Cg.cgCreateEffect(dev.cgContext, code, null); + + if (effect == IntPtr.Zero) + { + var err = Tao.Cg.Cg.cgGetErrorString(Tao.Cg.Cg.cgGetError()); + var results = Tao.Cg.Cg.cgGetLastListing(dev.cgContext); + throw new InvalidOperationException( + string.Format("Cg compile failed ({0}):\n{1}", err, results)); + } + + technique = Tao.Cg.Cg.cgGetFirstTechnique(effect); + if (technique == IntPtr.Zero) + throw new InvalidOperationException("No techniques"); + while (Tao.Cg.Cg.cgValidateTechnique(technique) == 0) + { + technique = Tao.Cg.Cg.cgGetNextTechnique(technique); + if (technique == IntPtr.Zero) + throw new InvalidOperationException("No valid techniques"); + } + } + + public void Render(Action a) + { + Tao.Cg.CgGl.cgGLEnableProfile(dev.vertexProfile); + Tao.Cg.CgGl.cgGLEnableProfile(dev.fragmentProfile); + + var pass = Tao.Cg.Cg.cgGetFirstPass(technique); + while (pass != IntPtr.Zero) + { + Tao.Cg.Cg.cgSetPassState(pass); + a(); + Tao.Cg.Cg.cgResetPassState(pass); + pass = Tao.Cg.Cg.cgGetNextPass(pass); + } + + Tao.Cg.CgGl.cgGLDisableProfile(dev.fragmentProfile); + Tao.Cg.CgGl.cgGLDisableProfile(dev.vertexProfile); + } + + public void SetValue(string name, ITexture t) + { + var texture = (Texture)t; + var param = Tao.Cg.Cg.cgGetNamedEffectParameter(effect, name); + if (param != IntPtr.Zero && texture != null) + Tao.Cg.CgGl.cgGLSetupSampler(param, texture.texture); + } + + public void SetValue(string name, float x, float y) + { + var param = Tao.Cg.Cg.cgGetNamedEffectParameter(effect, name); + if (param != IntPtr.Zero) + Tao.Cg.CgGl.cgGLSetParameter2f(param, x, y); + } + + public void Commit() { } + } +} diff --git a/OpenRA.Renderer.Cg/Texture.cs b/OpenRA.Renderer.Cg/Texture.cs index a366cc115c..bac4913c9c 100644 --- a/OpenRA.Renderer.Cg/Texture.cs +++ b/OpenRA.Renderer.Cg/Texture.cs @@ -1,132 +1,132 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using System.Drawing.Imaging; -using OpenRA.FileFormats.Graphics; -using Tao.OpenGl; -using System.IO; -using System; - -namespace OpenRA.Renderer.Cg -{ - public class Texture : ITexture - { - internal int texture; - - public Texture(GraphicsDevice dev) - { - Gl.glGenTextures(1, out texture); - GraphicsDevice.CheckGlError(); - } - - public Texture(GraphicsDevice dev, Bitmap bitmap) - { - Gl.glGenTextures(1, out texture); - GraphicsDevice.CheckGlError(); - SetData(bitmap); - } - - public void SetData(byte[] colors, int width, int height) - { - if (!IsPowerOf2(width) || !IsPowerOf2(height)) - throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width, height)); - - unsafe - { - fixed (byte* ptr = &colors[0]) - { - IntPtr intPtr = new IntPtr((void*)ptr); - - Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture); - GraphicsDevice.CheckGlError(); - Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BASE_LEVEL, 0); - GraphicsDevice.CheckGlError(); - Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_LEVEL, 0); - GraphicsDevice.CheckGlError(); - Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height, - 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr); - GraphicsDevice.CheckGlError(); - } - } - } - - // An array of RGBA - public void SetData(uint[,] colors) - { - int width = colors.GetUpperBound(1) + 1; - int height = colors.GetUpperBound(0) + 1; - - if (!IsPowerOf2(width) || !IsPowerOf2(height)) - throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width,height)); - - unsafe - { - fixed (uint* ptr = &colors[0,0]) - { - IntPtr intPtr = new IntPtr((void *) ptr); - - Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture); - GraphicsDevice.CheckGlError(); - Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BASE_LEVEL, 0); - GraphicsDevice.CheckGlError(); - Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_LEVEL, 0); - GraphicsDevice.CheckGlError(); - Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height, - 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr); - GraphicsDevice.CheckGlError(); - } - } - } - - public void SetData(Bitmap bitmap) - { - if (!IsPowerOf2(bitmap.Width) || !IsPowerOf2(bitmap.Height)) - { - //throw new InvalidOperationException( "non-power-of-2-texture" ); - bitmap = new Bitmap(bitmap, new Size(NextPowerOf2(bitmap.Width), NextPowerOf2(bitmap.Height))); - } - - Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture); - GraphicsDevice.CheckGlError(); - - var bits = bitmap.LockBits( - new Rectangle(0, 0, bitmap.Width, bitmap.Height), - ImageLockMode.ReadOnly, - PixelFormat.Format32bppArgb); - - Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BASE_LEVEL, 0); - GraphicsDevice.CheckGlError(); - Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_LEVEL, 0); - GraphicsDevice.CheckGlError(); - Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, bits.Width, bits.Height, - 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, bits.Scan0); // todo: weird strides - GraphicsDevice.CheckGlError(); - - bitmap.UnlockBits(bits); - } - - bool IsPowerOf2(int v) - { - return (v & (v - 1)) == 0; - } - - int NextPowerOf2(int v) - { - --v; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - ++v; - return v; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using System.Drawing.Imaging; +using OpenRA.FileFormats.Graphics; +using Tao.OpenGl; +using System.IO; +using System; + +namespace OpenRA.Renderer.Cg +{ + public class Texture : ITexture + { + internal int texture; + + public Texture(GraphicsDevice dev) + { + Gl.glGenTextures(1, out texture); + GraphicsDevice.CheckGlError(); + } + + public Texture(GraphicsDevice dev, Bitmap bitmap) + { + Gl.glGenTextures(1, out texture); + GraphicsDevice.CheckGlError(); + SetData(bitmap); + } + + public void SetData(byte[] colors, int width, int height) + { + if (!IsPowerOf2(width) || !IsPowerOf2(height)) + throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width, height)); + + unsafe + { + fixed (byte* ptr = &colors[0]) + { + IntPtr intPtr = new IntPtr((void*)ptr); + + Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture); + GraphicsDevice.CheckGlError(); + Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BASE_LEVEL, 0); + GraphicsDevice.CheckGlError(); + Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_LEVEL, 0); + GraphicsDevice.CheckGlError(); + Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height, + 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr); + GraphicsDevice.CheckGlError(); + } + } + } + + // An array of RGBA + public void SetData(uint[,] colors) + { + int width = colors.GetUpperBound(1) + 1; + int height = colors.GetUpperBound(0) + 1; + + if (!IsPowerOf2(width) || !IsPowerOf2(height)) + throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width,height)); + + unsafe + { + fixed (uint* ptr = &colors[0,0]) + { + IntPtr intPtr = new IntPtr((void *) ptr); + + Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture); + GraphicsDevice.CheckGlError(); + Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BASE_LEVEL, 0); + GraphicsDevice.CheckGlError(); + Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_LEVEL, 0); + GraphicsDevice.CheckGlError(); + Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height, + 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr); + GraphicsDevice.CheckGlError(); + } + } + } + + public void SetData(Bitmap bitmap) + { + if (!IsPowerOf2(bitmap.Width) || !IsPowerOf2(bitmap.Height)) + { + //throw new InvalidOperationException( "non-power-of-2-texture" ); + bitmap = new Bitmap(bitmap, new Size(NextPowerOf2(bitmap.Width), NextPowerOf2(bitmap.Height))); + } + + Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture); + GraphicsDevice.CheckGlError(); + + var bits = bitmap.LockBits( + new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.ReadOnly, + PixelFormat.Format32bppArgb); + + Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BASE_LEVEL, 0); + GraphicsDevice.CheckGlError(); + Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_LEVEL, 0); + GraphicsDevice.CheckGlError(); + Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, bits.Width, bits.Height, + 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, bits.Scan0); // todo: weird strides + GraphicsDevice.CheckGlError(); + + bitmap.UnlockBits(bits); + } + + bool IsPowerOf2(int v) + { + return (v & (v - 1)) == 0; + } + + int NextPowerOf2(int v) + { + --v; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + ++v; + return v; + } + } +} diff --git a/OpenRA.Renderer.Cg/VertexBuffer.cs b/OpenRA.Renderer.Cg/VertexBuffer.cs index 905c1eb295..53e0bf2746 100644 --- a/OpenRA.Renderer.Cg/VertexBuffer.cs +++ b/OpenRA.Renderer.Cg/VertexBuffer.cs @@ -1,67 +1,67 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Runtime.InteropServices; -using OpenRA.FileFormats.Graphics; -using Tao.OpenGl; - -namespace OpenRA.Renderer.Cg -{ - public class VertexBuffer : IVertexBuffer, IDisposable - where T : struct - { - int buffer; - - public VertexBuffer(GraphicsDevice dev, int size) - { - Gl.glGenBuffers(1, out buffer); - GraphicsDevice.CheckGlError(); - Bind(); - Gl.glBufferData(Gl.GL_ARRAY_BUFFER, - new IntPtr(Marshal.SizeOf(typeof(T)) * size), - new T[ size ], - Gl.GL_DYNAMIC_DRAW); - GraphicsDevice.CheckGlError(); - } - - public void SetData(T[] data, int length) - { - Bind(); - Gl.glBufferSubData(Gl.GL_ARRAY_BUFFER, - IntPtr.Zero, - new IntPtr(Marshal.SizeOf(typeof(T)) * length), - data); - GraphicsDevice.CheckGlError(); - } - - public void Bind() - { - Gl.glBindBuffer(Gl.GL_ARRAY_BUFFER, buffer); - GraphicsDevice.CheckGlError(); - Gl.glVertexPointer(3, Gl.GL_FLOAT, Marshal.SizeOf(typeof(T)), IntPtr.Zero); - GraphicsDevice.CheckGlError(); - Gl.glTexCoordPointer(4, Gl.GL_FLOAT, Marshal.SizeOf(typeof(T)), new IntPtr(12)); - GraphicsDevice.CheckGlError(); - } - - bool disposed; - public void Dispose() - { - if (disposed) return; - GC.SuppressFinalize(this); - Gl.glDeleteBuffers(1, ref buffer); - GraphicsDevice.CheckGlError(); - disposed = true; - } - - //~VertexBuffer() { Dispose(); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Runtime.InteropServices; +using OpenRA.FileFormats.Graphics; +using Tao.OpenGl; + +namespace OpenRA.Renderer.Cg +{ + public class VertexBuffer : IVertexBuffer, IDisposable + where T : struct + { + int buffer; + + public VertexBuffer(GraphicsDevice dev, int size) + { + Gl.glGenBuffers(1, out buffer); + GraphicsDevice.CheckGlError(); + Bind(); + Gl.glBufferData(Gl.GL_ARRAY_BUFFER, + new IntPtr(Marshal.SizeOf(typeof(T)) * size), + new T[ size ], + Gl.GL_DYNAMIC_DRAW); + GraphicsDevice.CheckGlError(); + } + + public void SetData(T[] data, int length) + { + Bind(); + Gl.glBufferSubData(Gl.GL_ARRAY_BUFFER, + IntPtr.Zero, + new IntPtr(Marshal.SizeOf(typeof(T)) * length), + data); + GraphicsDevice.CheckGlError(); + } + + public void Bind() + { + Gl.glBindBuffer(Gl.GL_ARRAY_BUFFER, buffer); + GraphicsDevice.CheckGlError(); + Gl.glVertexPointer(3, Gl.GL_FLOAT, Marshal.SizeOf(typeof(T)), IntPtr.Zero); + GraphicsDevice.CheckGlError(); + Gl.glTexCoordPointer(4, Gl.GL_FLOAT, Marshal.SizeOf(typeof(T)), new IntPtr(12)); + GraphicsDevice.CheckGlError(); + } + + bool disposed; + public void Dispose() + { + if (disposed) return; + GC.SuppressFinalize(this); + Gl.glDeleteBuffers(1, ref buffer); + GraphicsDevice.CheckGlError(); + disposed = true; + } + + //~VertexBuffer() { Dispose(); } + } +} diff --git a/OpenRA.Renderer.Gl/GraphicsDevice.cs b/OpenRA.Renderer.Gl/GraphicsDevice.cs index 47b00ee605..de0e0e28d5 100755 --- a/OpenRA.Renderer.Gl/GraphicsDevice.cs +++ b/OpenRA.Renderer.Gl/GraphicsDevice.cs @@ -1,315 +1,315 @@ -#region Copyright & License Information -/* -* Copyright 2007-2010 The OpenRA Developers (see AUTHORS) -* This file is part of OpenRA, which is free software. It is made -* available to you under the terms of the GNU General Public License -* as published by the Free Software Foundation. For more information, -* see LICENSE. -*/ -#endregion - -using System; -using System.Drawing; -using System.IO; -using OpenRA.FileFormats.Graphics; -using Tao.Cg; -using Tao.OpenGl; -using Tao.Sdl; -using System.Linq; - -[assembly: Renderer(typeof(OpenRA.Renderer.Glsl.GraphicsDevice))] - -namespace OpenRA.Renderer.Glsl -{ - public class GraphicsDevice : IGraphicsDevice - { - Size windowSize; - IntPtr surf; - - public Size WindowSize { get { return windowSize; } } - - public enum GlError - { - GL_NO_ERROR = Gl.GL_NO_ERROR, - GL_INVALID_ENUM = Gl.GL_INVALID_ENUM, - GL_INVALID_VALUE = Gl.GL_INVALID_VALUE, - GL_STACK_OVERFLOW = Gl.GL_STACK_OVERFLOW, - GL_STACK_UNDERFLOW = Gl.GL_STACK_UNDERFLOW, - GL_OUT_OF_MEMORY = Gl.GL_OUT_OF_MEMORY, - GL_TABLE_TOO_LARGE = Gl.GL_TABLE_TOO_LARGE, - } - - internal static void CheckGlError() - { - var n = Gl.glGetError(); - if( n != Gl.GL_NO_ERROR ) - throw new InvalidOperationException( "GL Error: " + ( (GlError)n ).ToString() ); - } - - public GraphicsDevice( int width, int height, WindowMode window, bool vsync ) - { - Console.WriteLine("Using Gl renderer"); - Sdl.SDL_Init( Sdl.SDL_INIT_NOPARACHUTE | Sdl.SDL_INIT_VIDEO ); - Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_DOUBLEBUFFER, 1 ); - Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_RED_SIZE, 8 ); - Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_GREEN_SIZE, 8 ); - Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_BLUE_SIZE, 8 ); - Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_ALPHA_SIZE, 0 ); - - int windowFlags = 0; - switch( window ) - { - case WindowMode.Fullscreen: - windowFlags |= Sdl.SDL_FULLSCREEN; - break; - case WindowMode.PseudoFullscreen: - windowFlags |= Sdl.SDL_NOFRAME; - Environment.SetEnvironmentVariable( "SDL_VIDEO_WINDOW_POS", "0,0" ); - break; - default: - break; - } - - surf = Sdl.SDL_SetVideoMode( width, height, 0, Sdl.SDL_OPENGL | windowFlags ); - - Sdl.SDL_WM_SetCaption( "OpenRA", "OpenRA" ); - Sdl.SDL_ShowCursor( 0 ); - Sdl.SDL_EnableUNICODE( 1 ); - Sdl.SDL_EnableKeyRepeat( Sdl.SDL_DEFAULT_REPEAT_DELAY, Sdl.SDL_DEFAULT_REPEAT_INTERVAL ); - - CheckGlError(); - - windowSize = new Size( width, height ); - - Gl.glEnableClientState( Gl.GL_VERTEX_ARRAY ); - CheckGlError(); - Gl.glEnableClientState( Gl.GL_TEXTURE_COORD_ARRAY ); - CheckGlError(); - - Sdl.SDL_SetModState( 0 ); - - // Test for required extensions - var required = new string[] - { - "GL_ARB_vertex_shader", - "GL_ARB_fragment_shader", - "GL_ARB_vertex_buffer_object", - }; - - var extensions = Gl.glGetString(Gl.GL_EXTENSIONS); - if (required.Any(r => !extensions.Contains(r))) - { - Log.AddChannel("graphics", "graphics.log"); - Log.Write("graphics", "Unsupported GPU: Missing extensions."); - Log.Write("graphics", "Available extensions:"); - Log.Write("graphics", extensions); - throw new InvalidProgramException("Unsupported GPU. See graphics.log for details."); - } - } - - public void EnableScissor( int left, int top, int width, int height ) - { - if( width < 0 ) width = 0; - if( height < 0 ) height = 0; - Gl.glScissor( left, windowSize.Height - ( top + height ), width, height ); - CheckGlError(); - Gl.glEnable( Gl.GL_SCISSOR_TEST ); - CheckGlError(); - } - - public void DisableScissor() - { - Gl.glDisable( Gl.GL_SCISSOR_TEST ); - CheckGlError(); - } - - public void Clear( Color c ) - { - Gl.glClearColor( 0, 0, 0, 0 ); - CheckGlError(); - Gl.glClear( Gl.GL_COLOR_BUFFER_BIT ); - CheckGlError(); - } - - MouseButton lastButtonBits = (MouseButton)0; - - MouseButton MakeButton( byte b ) - { - return b == Sdl.SDL_BUTTON_LEFT ? MouseButton.Left - : b == Sdl.SDL_BUTTON_RIGHT ? MouseButton.Right - : b == Sdl.SDL_BUTTON_MIDDLE ? MouseButton.Middle - : b == Sdl.SDL_BUTTON_WHEELDOWN ? MouseButton.WheelDown - : b == Sdl.SDL_BUTTON_WHEELUP ? MouseButton.WheelUp - : 0; - } - - Modifiers MakeModifiers( int raw ) - { - return ( ( raw & Sdl.KMOD_ALT ) != 0 ? Modifiers.Alt : 0 ) - | ( ( raw & Sdl.KMOD_CTRL ) != 0 ? Modifiers.Ctrl : 0 ) - | ( ( raw & Sdl.KMOD_SHIFT ) != 0 ? Modifiers.Shift : 0 ); - } - - bool HandleSpecialKey( KeyInput k ) - { - switch( k.VirtKey ) - { - case Sdl.SDLK_F13: - var path = Environment.GetFolderPath( Environment.SpecialFolder.Personal ) - + Path.DirectorySeparatorChar + DateTime.UtcNow.ToString( "OpenRA-yyyy-MM-ddThhmmssZ" ) + ".bmp"; - Sdl.SDL_SaveBMP( surf, path ); - return true; - - case Sdl.SDLK_F4: - if( k.Modifiers.HasModifier( Modifiers.Alt ) ) - { - OpenRA.Game.Exit(); - return true; - } - return false; - - default: - return false; - } - } - - public void Present( IInputHandler inputHandler ) - { - Sdl.SDL_GL_SwapBuffers(); - Game.HasInputFocus = 0 != ( Sdl.SDL_GetAppState() & Sdl.SDL_APPINPUTFOCUS ); - - var mods = MakeModifiers( Sdl.SDL_GetModState() ); - inputHandler.ModifierKeys( mods ); - MouseInput? pendingMotion = null; - - Sdl.SDL_Event e; - while( Sdl.SDL_PollEvent( out e ) != 0 ) - { - switch( e.type ) - { - case Sdl.SDL_QUIT: - OpenRA.Game.Exit(); - break; - - case Sdl.SDL_MOUSEBUTTONDOWN: - { - if( pendingMotion != null ) - { - inputHandler.OnMouseInput( pendingMotion.Value ); - pendingMotion = null; - } - - var button = MakeButton( e.button.button ); - lastButtonBits |= button; - - inputHandler.OnMouseInput( new MouseInput( - MouseInputEvent.Down, button, new int2( e.button.x, e.button.y ), mods ) ); - } break; - - case Sdl.SDL_MOUSEBUTTONUP: - { - if( pendingMotion != null ) - { - inputHandler.OnMouseInput( pendingMotion.Value ); - pendingMotion = null; - } - - var button = MakeButton( e.button.button ); - lastButtonBits &= ~button; - - inputHandler.OnMouseInput( new MouseInput( - MouseInputEvent.Up, button, new int2( e.button.x, e.button.y ), mods ) ); - } break; - - case Sdl.SDL_MOUSEMOTION: - { - pendingMotion = new MouseInput( - MouseInputEvent.Move, - lastButtonBits, - new int2( e.motion.x, e.motion.y ), - mods ); - } break; - - case Sdl.SDL_KEYDOWN: - { - var keyEvent = new KeyInput - { - Event = KeyInputEvent.Down, - Modifiers = mods, - KeyChar = (char)e.key.keysym.unicode, - KeyName = Sdl.SDL_GetKeyName( e.key.keysym.sym ), - VirtKey = e.key.keysym.sym - }; - - if( !HandleSpecialKey( keyEvent ) ) - inputHandler.OnKeyInput( keyEvent ); - } break; - - case Sdl.SDL_KEYUP: - { - var keyEvent = new KeyInput - { - Event = KeyInputEvent.Up, - Modifiers = mods, - KeyChar = (char)e.key.keysym.unicode, - KeyName = Sdl.SDL_GetKeyName( e.key.keysym.sym ), - VirtKey = e.key.keysym.sym - }; - - inputHandler.OnKeyInput( keyEvent ); - } break; - } - } - - if( pendingMotion != null ) - { - inputHandler.OnMouseInput( pendingMotion.Value ); - pendingMotion = null; - } - - CheckGlError(); - } - - public void DrawIndexedPrimitives( PrimitiveType pt, Range vertices, Range indices ) - { - Gl.glDrawElements( ModeFromPrimitiveType( pt ), indices.End - indices.Start, - Gl.GL_UNSIGNED_SHORT, new IntPtr( indices.Start * 2 ) ); - CheckGlError(); - } - - public void DrawIndexedPrimitives( PrimitiveType pt, int numVerts, int numPrimitives ) - { - Gl.glDrawElements( ModeFromPrimitiveType( pt ), numPrimitives * IndicesPerPrimitive( pt ), - Gl.GL_UNSIGNED_SHORT, IntPtr.Zero ); - CheckGlError(); - } - - static int ModeFromPrimitiveType( PrimitiveType pt ) - { - switch( pt ) - { - case PrimitiveType.PointList: return Gl.GL_POINTS; - case PrimitiveType.LineList: return Gl.GL_LINES; - case PrimitiveType.TriangleList: return Gl.GL_TRIANGLES; - } - throw new NotImplementedException(); - } - - static int IndicesPerPrimitive( PrimitiveType pt ) - { - switch( pt ) - { - case PrimitiveType.PointList: return 1; - case PrimitiveType.LineList: return 2; - case PrimitiveType.TriangleList: return 3; - } - throw new NotImplementedException(); - } - - public IVertexBuffer CreateVertexBuffer( int size ) { return new VertexBuffer( this, size ); } - public IIndexBuffer CreateIndexBuffer( int size ) { return new IndexBuffer( this, size ); } - public ITexture CreateTexture() { return new Texture( this ); } - public ITexture CreateTexture( Bitmap bitmap ) { return new Texture( this, bitmap ); } - public IShader CreateShader( string name ) { return new Shader( this, name ); } - } -} +#region Copyright & License Information +/* +* Copyright 2007-2011 The OpenRA Developers (see AUTHORS) +* This file is part of OpenRA, which is free software. It is made +* available to you under the terms of the GNU General Public License +* as published by the Free Software Foundation. For more information, +* see COPYING. +*/ +#endregion + +using System; +using System.Drawing; +using System.IO; +using OpenRA.FileFormats.Graphics; +using Tao.Cg; +using Tao.OpenGl; +using Tao.Sdl; +using System.Linq; + +[assembly: Renderer(typeof(OpenRA.Renderer.Glsl.GraphicsDevice))] + +namespace OpenRA.Renderer.Glsl +{ + public class GraphicsDevice : IGraphicsDevice + { + Size windowSize; + IntPtr surf; + + public Size WindowSize { get { return windowSize; } } + + public enum GlError + { + GL_NO_ERROR = Gl.GL_NO_ERROR, + GL_INVALID_ENUM = Gl.GL_INVALID_ENUM, + GL_INVALID_VALUE = Gl.GL_INVALID_VALUE, + GL_STACK_OVERFLOW = Gl.GL_STACK_OVERFLOW, + GL_STACK_UNDERFLOW = Gl.GL_STACK_UNDERFLOW, + GL_OUT_OF_MEMORY = Gl.GL_OUT_OF_MEMORY, + GL_TABLE_TOO_LARGE = Gl.GL_TABLE_TOO_LARGE, + } + + internal static void CheckGlError() + { + var n = Gl.glGetError(); + if( n != Gl.GL_NO_ERROR ) + throw new InvalidOperationException( "GL Error: " + ( (GlError)n ).ToString() ); + } + + public GraphicsDevice( int width, int height, WindowMode window, bool vsync ) + { + Console.WriteLine("Using Gl renderer"); + Sdl.SDL_Init( Sdl.SDL_INIT_NOPARACHUTE | Sdl.SDL_INIT_VIDEO ); + Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_DOUBLEBUFFER, 1 ); + Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_RED_SIZE, 8 ); + Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_GREEN_SIZE, 8 ); + Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_BLUE_SIZE, 8 ); + Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_ALPHA_SIZE, 0 ); + + int windowFlags = 0; + switch( window ) + { + case WindowMode.Fullscreen: + windowFlags |= Sdl.SDL_FULLSCREEN; + break; + case WindowMode.PseudoFullscreen: + windowFlags |= Sdl.SDL_NOFRAME; + Environment.SetEnvironmentVariable( "SDL_VIDEO_WINDOW_POS", "0,0" ); + break; + default: + break; + } + + surf = Sdl.SDL_SetVideoMode( width, height, 0, Sdl.SDL_OPENGL | windowFlags ); + + Sdl.SDL_WM_SetCaption( "OpenRA", "OpenRA" ); + Sdl.SDL_ShowCursor( 0 ); + Sdl.SDL_EnableUNICODE( 1 ); + Sdl.SDL_EnableKeyRepeat( Sdl.SDL_DEFAULT_REPEAT_DELAY, Sdl.SDL_DEFAULT_REPEAT_INTERVAL ); + + CheckGlError(); + + windowSize = new Size( width, height ); + + Gl.glEnableClientState( Gl.GL_VERTEX_ARRAY ); + CheckGlError(); + Gl.glEnableClientState( Gl.GL_TEXTURE_COORD_ARRAY ); + CheckGlError(); + + Sdl.SDL_SetModState( 0 ); + + // Test for required extensions + var required = new string[] + { + "GL_ARB_vertex_shader", + "GL_ARB_fragment_shader", + "GL_ARB_vertex_buffer_object", + }; + + var extensions = Gl.glGetString(Gl.GL_EXTENSIONS); + if (required.Any(r => !extensions.Contains(r))) + { + Log.AddChannel("graphics", "graphics.log"); + Log.Write("graphics", "Unsupported GPU: Missing extensions."); + Log.Write("graphics", "Available extensions:"); + Log.Write("graphics", extensions); + throw new InvalidProgramException("Unsupported GPU. See graphics.log for details."); + } + } + + public void EnableScissor( int left, int top, int width, int height ) + { + if( width < 0 ) width = 0; + if( height < 0 ) height = 0; + Gl.glScissor( left, windowSize.Height - ( top + height ), width, height ); + CheckGlError(); + Gl.glEnable( Gl.GL_SCISSOR_TEST ); + CheckGlError(); + } + + public void DisableScissor() + { + Gl.glDisable( Gl.GL_SCISSOR_TEST ); + CheckGlError(); + } + + public void Clear( Color c ) + { + Gl.glClearColor( 0, 0, 0, 0 ); + CheckGlError(); + Gl.glClear( Gl.GL_COLOR_BUFFER_BIT ); + CheckGlError(); + } + + MouseButton lastButtonBits = (MouseButton)0; + + MouseButton MakeButton( byte b ) + { + return b == Sdl.SDL_BUTTON_LEFT ? MouseButton.Left + : b == Sdl.SDL_BUTTON_RIGHT ? MouseButton.Right + : b == Sdl.SDL_BUTTON_MIDDLE ? MouseButton.Middle + : b == Sdl.SDL_BUTTON_WHEELDOWN ? MouseButton.WheelDown + : b == Sdl.SDL_BUTTON_WHEELUP ? MouseButton.WheelUp + : 0; + } + + Modifiers MakeModifiers( int raw ) + { + return ( ( raw & Sdl.KMOD_ALT ) != 0 ? Modifiers.Alt : 0 ) + | ( ( raw & Sdl.KMOD_CTRL ) != 0 ? Modifiers.Ctrl : 0 ) + | ( ( raw & Sdl.KMOD_SHIFT ) != 0 ? Modifiers.Shift : 0 ); + } + + bool HandleSpecialKey( KeyInput k ) + { + switch( k.VirtKey ) + { + case Sdl.SDLK_F13: + var path = Environment.GetFolderPath( Environment.SpecialFolder.Personal ) + + Path.DirectorySeparatorChar + DateTime.UtcNow.ToString( "OpenRA-yyyy-MM-ddThhmmssZ" ) + ".bmp"; + Sdl.SDL_SaveBMP( surf, path ); + return true; + + case Sdl.SDLK_F4: + if( k.Modifiers.HasModifier( Modifiers.Alt ) ) + { + OpenRA.Game.Exit(); + return true; + } + return false; + + default: + return false; + } + } + + public void Present( IInputHandler inputHandler ) + { + Sdl.SDL_GL_SwapBuffers(); + Game.HasInputFocus = 0 != ( Sdl.SDL_GetAppState() & Sdl.SDL_APPINPUTFOCUS ); + + var mods = MakeModifiers( Sdl.SDL_GetModState() ); + inputHandler.ModifierKeys( mods ); + MouseInput? pendingMotion = null; + + Sdl.SDL_Event e; + while( Sdl.SDL_PollEvent( out e ) != 0 ) + { + switch( e.type ) + { + case Sdl.SDL_QUIT: + OpenRA.Game.Exit(); + break; + + case Sdl.SDL_MOUSEBUTTONDOWN: + { + if( pendingMotion != null ) + { + inputHandler.OnMouseInput( pendingMotion.Value ); + pendingMotion = null; + } + + var button = MakeButton( e.button.button ); + lastButtonBits |= button; + + inputHandler.OnMouseInput( new MouseInput( + MouseInputEvent.Down, button, new int2( e.button.x, e.button.y ), mods ) ); + } break; + + case Sdl.SDL_MOUSEBUTTONUP: + { + if( pendingMotion != null ) + { + inputHandler.OnMouseInput( pendingMotion.Value ); + pendingMotion = null; + } + + var button = MakeButton( e.button.button ); + lastButtonBits &= ~button; + + inputHandler.OnMouseInput( new MouseInput( + MouseInputEvent.Up, button, new int2( e.button.x, e.button.y ), mods ) ); + } break; + + case Sdl.SDL_MOUSEMOTION: + { + pendingMotion = new MouseInput( + MouseInputEvent.Move, + lastButtonBits, + new int2( e.motion.x, e.motion.y ), + mods ); + } break; + + case Sdl.SDL_KEYDOWN: + { + var keyEvent = new KeyInput + { + Event = KeyInputEvent.Down, + Modifiers = mods, + KeyChar = (char)e.key.keysym.unicode, + KeyName = Sdl.SDL_GetKeyName( e.key.keysym.sym ), + VirtKey = e.key.keysym.sym + }; + + if( !HandleSpecialKey( keyEvent ) ) + inputHandler.OnKeyInput( keyEvent ); + } break; + + case Sdl.SDL_KEYUP: + { + var keyEvent = new KeyInput + { + Event = KeyInputEvent.Up, + Modifiers = mods, + KeyChar = (char)e.key.keysym.unicode, + KeyName = Sdl.SDL_GetKeyName( e.key.keysym.sym ), + VirtKey = e.key.keysym.sym + }; + + inputHandler.OnKeyInput( keyEvent ); + } break; + } + } + + if( pendingMotion != null ) + { + inputHandler.OnMouseInput( pendingMotion.Value ); + pendingMotion = null; + } + + CheckGlError(); + } + + public void DrawIndexedPrimitives( PrimitiveType pt, Range vertices, Range indices ) + { + Gl.glDrawElements( ModeFromPrimitiveType( pt ), indices.End - indices.Start, + Gl.GL_UNSIGNED_SHORT, new IntPtr( indices.Start * 2 ) ); + CheckGlError(); + } + + public void DrawIndexedPrimitives( PrimitiveType pt, int numVerts, int numPrimitives ) + { + Gl.glDrawElements( ModeFromPrimitiveType( pt ), numPrimitives * IndicesPerPrimitive( pt ), + Gl.GL_UNSIGNED_SHORT, IntPtr.Zero ); + CheckGlError(); + } + + static int ModeFromPrimitiveType( PrimitiveType pt ) + { + switch( pt ) + { + case PrimitiveType.PointList: return Gl.GL_POINTS; + case PrimitiveType.LineList: return Gl.GL_LINES; + case PrimitiveType.TriangleList: return Gl.GL_TRIANGLES; + } + throw new NotImplementedException(); + } + + static int IndicesPerPrimitive( PrimitiveType pt ) + { + switch( pt ) + { + case PrimitiveType.PointList: return 1; + case PrimitiveType.LineList: return 2; + case PrimitiveType.TriangleList: return 3; + } + throw new NotImplementedException(); + } + + public IVertexBuffer CreateVertexBuffer( int size ) { return new VertexBuffer( this, size ); } + public IIndexBuffer CreateIndexBuffer( int size ) { return new IndexBuffer( this, size ); } + public ITexture CreateTexture() { return new Texture( this ); } + public ITexture CreateTexture( Bitmap bitmap ) { return new Texture( this, bitmap ); } + public IShader CreateShader( string name ) { return new Shader( this, name ); } + } +} diff --git a/OpenRA.Renderer.Gl/IndexBuffer.cs b/OpenRA.Renderer.Gl/IndexBuffer.cs index 8a4553ca57..dfe49fa5cb 100644 --- a/OpenRA.Renderer.Gl/IndexBuffer.cs +++ b/OpenRA.Renderer.Gl/IndexBuffer.cs @@ -1,61 +1,61 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using OpenRA.FileFormats.Graphics; -using Tao.OpenGl; - -namespace OpenRA.Renderer.Glsl -{ - public class IndexBuffer : IIndexBuffer, IDisposable - { - int buffer; - - public IndexBuffer(GraphicsDevice dev, int size) - { - Gl.glGenBuffers(1, out buffer); - GraphicsDevice.CheckGlError(); - Bind(); - Gl.glBufferData(Gl.GL_ELEMENT_ARRAY_BUFFER, - new IntPtr(2 * size), - new ushort[ size ], - Gl.GL_DYNAMIC_DRAW); - GraphicsDevice.CheckGlError(); - } - - public void SetData(ushort[] data, int length) - { - Bind(); - Gl.glBufferSubData(Gl.GL_ELEMENT_ARRAY_BUFFER, - IntPtr.Zero, - new IntPtr(2 * length), - data); - GraphicsDevice.CheckGlError(); - } - - public void Bind() - { - Gl.glBindBuffer(Gl.GL_ELEMENT_ARRAY_BUFFER, buffer); - GraphicsDevice.CheckGlError(); - } - - bool disposed; - public void Dispose() - { - if (disposed) return; - GC.SuppressFinalize(this); - Gl.glDeleteBuffers(1, ref buffer); - GraphicsDevice.CheckGlError(); - disposed = true; - } - - //~IndexBuffer() { Dispose(); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using OpenRA.FileFormats.Graphics; +using Tao.OpenGl; + +namespace OpenRA.Renderer.Glsl +{ + public class IndexBuffer : IIndexBuffer, IDisposable + { + int buffer; + + public IndexBuffer(GraphicsDevice dev, int size) + { + Gl.glGenBuffers(1, out buffer); + GraphicsDevice.CheckGlError(); + Bind(); + Gl.glBufferData(Gl.GL_ELEMENT_ARRAY_BUFFER, + new IntPtr(2 * size), + new ushort[ size ], + Gl.GL_DYNAMIC_DRAW); + GraphicsDevice.CheckGlError(); + } + + public void SetData(ushort[] data, int length) + { + Bind(); + Gl.glBufferSubData(Gl.GL_ELEMENT_ARRAY_BUFFER, + IntPtr.Zero, + new IntPtr(2 * length), + data); + GraphicsDevice.CheckGlError(); + } + + public void Bind() + { + Gl.glBindBuffer(Gl.GL_ELEMENT_ARRAY_BUFFER, buffer); + GraphicsDevice.CheckGlError(); + } + + bool disposed; + public void Dispose() + { + if (disposed) return; + GC.SuppressFinalize(this); + Gl.glDeleteBuffers(1, ref buffer); + GraphicsDevice.CheckGlError(); + disposed = true; + } + + //~IndexBuffer() { Dispose(); } + } +} diff --git a/OpenRA.Renderer.Gl/Shader.cs b/OpenRA.Renderer.Gl/Shader.cs index 0b5df1f2b5..0642686f71 100644 --- a/OpenRA.Renderer.Gl/Shader.cs +++ b/OpenRA.Renderer.Gl/Shader.cs @@ -1,147 +1,147 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.IO; -using OpenRA.FileFormats; -using OpenRA.FileFormats.Graphics; -using Tao.OpenGl; -using System.Text; -using System.Collections.Generic; - -namespace OpenRA.Renderer.Glsl -{ - public class Shader : IShader - { - int program; - readonly Dictionary samplers = new Dictionary(); - - public Shader(GraphicsDevice dev, string type) - { - // Vertex shader - string vertexCode; - using (var file = new StreamReader(FileSystem.Open("glsl{0}{1}.vert".F(Path.DirectorySeparatorChar, type)))) - vertexCode = file.ReadToEnd(); - - int v = Gl.glCreateShaderObjectARB(Gl.GL_VERTEX_SHADER_ARB); - GraphicsDevice.CheckGlError(); - Gl.glShaderSourceARB(v,1,new string[]{vertexCode},null); - GraphicsDevice.CheckGlError(); - Gl.glCompileShaderARB(v); - GraphicsDevice.CheckGlError(); - - int success; - Gl.glGetObjectParameterivARB(v, Gl.GL_OBJECT_COMPILE_STATUS_ARB, out success); - GraphicsDevice.CheckGlError(); - if (success == 0) - throw new InvalidProgramException("Compile error in {0}{1}.vert".F(Path.DirectorySeparatorChar, type)); - - // Fragment shader - string fragmentCode; - using (var file = new StreamReader(FileSystem.Open("glsl{0}{1}.frag".F(Path.DirectorySeparatorChar, type)))) - fragmentCode = file.ReadToEnd(); - int f = Gl.glCreateShaderObjectARB(Gl.GL_FRAGMENT_SHADER_ARB); - GraphicsDevice.CheckGlError(); - Gl.glShaderSourceARB(f,1,new string[]{fragmentCode},null); - GraphicsDevice.CheckGlError(); - Gl.glCompileShaderARB(f); - GraphicsDevice.CheckGlError(); - - Gl.glGetObjectParameterivARB(f, Gl.GL_OBJECT_COMPILE_STATUS_ARB, out success); - GraphicsDevice.CheckGlError(); - if (success == 0) - throw new InvalidProgramException("Compile error in glsl{0}{1}.frag".F(Path.DirectorySeparatorChar, type)); - - - // Assemble program - program = Gl.glCreateProgramObjectARB(); - GraphicsDevice.CheckGlError(); - Gl.glAttachObjectARB(program,v); - GraphicsDevice.CheckGlError(); - Gl.glAttachObjectARB(program,f); - GraphicsDevice.CheckGlError(); - - Gl.glLinkProgramARB(program); - GraphicsDevice.CheckGlError(); - - Gl.glGetObjectParameterivARB(program, Gl.GL_OBJECT_LINK_STATUS_ARB, out success); - GraphicsDevice.CheckGlError(); - if (success == 0) - throw new InvalidProgramException("Linking error in {0} shader".F(type)); - - - Gl.glUseProgramObjectARB(program); - GraphicsDevice.CheckGlError(); - - int numUniforms; - Gl.glGetObjectParameterivARB( program, Gl.GL_ACTIVE_UNIFORMS, out numUniforms ); - GraphicsDevice.CheckGlError(); - - int nextTexUnit = 1; - for( int i = 0 ; i < numUniforms ; i++ ) - { - int uLen, uSize, uType; - var sb = new StringBuilder(128); - Gl.glGetActiveUniformARB( program, i, 128, out uLen, out uSize, out uType, sb ); - GraphicsDevice.CheckGlError(); - if( uType == Gl.GL_SAMPLER_2D_ARB ) - { - samplers.Add( sb.ToString(), nextTexUnit ); - Gl.glUniform1iARB( i, nextTexUnit ); - ++nextTexUnit; - } - } - } - - public void Render(Action a) - { - Gl.glUseProgramObjectARB(program); - GraphicsDevice.CheckGlError(); - // Todo: Only enable alpha blending if we need it - Gl.glEnable(Gl.GL_BLEND); - GraphicsDevice.CheckGlError(); - Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA); - GraphicsDevice.CheckGlError(); - a(); - GraphicsDevice.CheckGlError(); - Gl.glDisable(Gl.GL_BLEND); - GraphicsDevice.CheckGlError(); - } - - public void SetValue(string name, ITexture t) - { - if( t == null ) return; - Gl.glUseProgramObjectARB(program); - GraphicsDevice.CheckGlError(); - var texture = (Texture)t; - int texUnit; - if( samplers.TryGetValue( name, out texUnit ) ) - { - Gl.glActiveTextureARB( Gl.GL_TEXTURE0_ARB + texUnit ); - GraphicsDevice.CheckGlError(); - Gl.glBindTexture( Gl.GL_TEXTURE_2D, texture.texture ); - GraphicsDevice.CheckGlError(); - Gl.glActiveTextureARB( Gl.GL_TEXTURE0_ARB ); - } - } - - public void SetValue(string name, float x, float y) - { - Gl.glUseProgramObjectARB(program); - GraphicsDevice.CheckGlError(); - int param = Gl.glGetUniformLocationARB(program, name); - GraphicsDevice.CheckGlError(); - Gl.glUniform2fARB(param,x,y); - GraphicsDevice.CheckGlError(); - } - - public void Commit() { } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.IO; +using OpenRA.FileFormats; +using OpenRA.FileFormats.Graphics; +using Tao.OpenGl; +using System.Text; +using System.Collections.Generic; + +namespace OpenRA.Renderer.Glsl +{ + public class Shader : IShader + { + int program; + readonly Dictionary samplers = new Dictionary(); + + public Shader(GraphicsDevice dev, string type) + { + // Vertex shader + string vertexCode; + using (var file = new StreamReader(FileSystem.Open("glsl{0}{1}.vert".F(Path.DirectorySeparatorChar, type)))) + vertexCode = file.ReadToEnd(); + + int v = Gl.glCreateShaderObjectARB(Gl.GL_VERTEX_SHADER_ARB); + GraphicsDevice.CheckGlError(); + Gl.glShaderSourceARB(v,1,new string[]{vertexCode},null); + GraphicsDevice.CheckGlError(); + Gl.glCompileShaderARB(v); + GraphicsDevice.CheckGlError(); + + int success; + Gl.glGetObjectParameterivARB(v, Gl.GL_OBJECT_COMPILE_STATUS_ARB, out success); + GraphicsDevice.CheckGlError(); + if (success == 0) + throw new InvalidProgramException("Compile error in {0}{1}.vert".F(Path.DirectorySeparatorChar, type)); + + // Fragment shader + string fragmentCode; + using (var file = new StreamReader(FileSystem.Open("glsl{0}{1}.frag".F(Path.DirectorySeparatorChar, type)))) + fragmentCode = file.ReadToEnd(); + int f = Gl.glCreateShaderObjectARB(Gl.GL_FRAGMENT_SHADER_ARB); + GraphicsDevice.CheckGlError(); + Gl.glShaderSourceARB(f,1,new string[]{fragmentCode},null); + GraphicsDevice.CheckGlError(); + Gl.glCompileShaderARB(f); + GraphicsDevice.CheckGlError(); + + Gl.glGetObjectParameterivARB(f, Gl.GL_OBJECT_COMPILE_STATUS_ARB, out success); + GraphicsDevice.CheckGlError(); + if (success == 0) + throw new InvalidProgramException("Compile error in glsl{0}{1}.frag".F(Path.DirectorySeparatorChar, type)); + + + // Assemble program + program = Gl.glCreateProgramObjectARB(); + GraphicsDevice.CheckGlError(); + Gl.glAttachObjectARB(program,v); + GraphicsDevice.CheckGlError(); + Gl.glAttachObjectARB(program,f); + GraphicsDevice.CheckGlError(); + + Gl.glLinkProgramARB(program); + GraphicsDevice.CheckGlError(); + + Gl.glGetObjectParameterivARB(program, Gl.GL_OBJECT_LINK_STATUS_ARB, out success); + GraphicsDevice.CheckGlError(); + if (success == 0) + throw new InvalidProgramException("Linking error in {0} shader".F(type)); + + + Gl.glUseProgramObjectARB(program); + GraphicsDevice.CheckGlError(); + + int numUniforms; + Gl.glGetObjectParameterivARB( program, Gl.GL_ACTIVE_UNIFORMS, out numUniforms ); + GraphicsDevice.CheckGlError(); + + int nextTexUnit = 1; + for( int i = 0 ; i < numUniforms ; i++ ) + { + int uLen, uSize, uType; + var sb = new StringBuilder(128); + Gl.glGetActiveUniformARB( program, i, 128, out uLen, out uSize, out uType, sb ); + GraphicsDevice.CheckGlError(); + if( uType == Gl.GL_SAMPLER_2D_ARB ) + { + samplers.Add( sb.ToString(), nextTexUnit ); + Gl.glUniform1iARB( i, nextTexUnit ); + ++nextTexUnit; + } + } + } + + public void Render(Action a) + { + Gl.glUseProgramObjectARB(program); + GraphicsDevice.CheckGlError(); + // Todo: Only enable alpha blending if we need it + Gl.glEnable(Gl.GL_BLEND); + GraphicsDevice.CheckGlError(); + Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA); + GraphicsDevice.CheckGlError(); + a(); + GraphicsDevice.CheckGlError(); + Gl.glDisable(Gl.GL_BLEND); + GraphicsDevice.CheckGlError(); + } + + public void SetValue(string name, ITexture t) + { + if( t == null ) return; + Gl.glUseProgramObjectARB(program); + GraphicsDevice.CheckGlError(); + var texture = (Texture)t; + int texUnit; + if( samplers.TryGetValue( name, out texUnit ) ) + { + Gl.glActiveTextureARB( Gl.GL_TEXTURE0_ARB + texUnit ); + GraphicsDevice.CheckGlError(); + Gl.glBindTexture( Gl.GL_TEXTURE_2D, texture.texture ); + GraphicsDevice.CheckGlError(); + Gl.glActiveTextureARB( Gl.GL_TEXTURE0_ARB ); + } + } + + public void SetValue(string name, float x, float y) + { + Gl.glUseProgramObjectARB(program); + GraphicsDevice.CheckGlError(); + int param = Gl.glGetUniformLocationARB(program, name); + GraphicsDevice.CheckGlError(); + Gl.glUniform2fARB(param,x,y); + GraphicsDevice.CheckGlError(); + } + + public void Commit() { } + } +} diff --git a/OpenRA.Renderer.Gl/Texture.cs b/OpenRA.Renderer.Gl/Texture.cs index 6c6f1a517f..7530894e2b 100644 --- a/OpenRA.Renderer.Gl/Texture.cs +++ b/OpenRA.Renderer.Gl/Texture.cs @@ -1,129 +1,129 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using System.Drawing.Imaging; -using OpenRA.FileFormats.Graphics; -using Tao.OpenGl; -using System.IO; -using System; - -namespace OpenRA.Renderer.Glsl -{ - public class Texture : ITexture - { - internal int texture; - - public Texture(GraphicsDevice dev) - { - Gl.glGenTextures(1, out texture); - GraphicsDevice.CheckGlError(); - } - - public Texture(GraphicsDevice dev, Bitmap bitmap) - { - Gl.glGenTextures(1, out texture); - GraphicsDevice.CheckGlError(); - SetData(bitmap); - } - - void PrepareTexture() - { - GraphicsDevice.CheckGlError(); - Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture); - GraphicsDevice.CheckGlError(); - Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST); - GraphicsDevice.CheckGlError(); - Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST); - GraphicsDevice.CheckGlError(); - - Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BASE_LEVEL, 0); - GraphicsDevice.CheckGlError(); - Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_LEVEL, 0); - GraphicsDevice.CheckGlError(); - } - - public void SetData(byte[] colors, int width, int height) - { - if (!IsPowerOf2(width) || !IsPowerOf2(height)) - throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width, height)); - - unsafe - { - fixed (byte* ptr = &colors[0]) - { - IntPtr intPtr = new IntPtr((void*)ptr); - PrepareTexture(); - Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height, - 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr); - GraphicsDevice.CheckGlError(); - } - } - } - - // An array of RGBA - public void SetData(uint[,] colors) - { - int width = colors.GetUpperBound(1) + 1; - int height = colors.GetUpperBound(0) + 1; - - if (!IsPowerOf2(width) || !IsPowerOf2(height)) - throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width,height)); - - unsafe - { - fixed (uint* ptr = &colors[0,0]) - { - IntPtr intPtr = new IntPtr((void *) ptr); - PrepareTexture(); - Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height, - 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr); - GraphicsDevice.CheckGlError(); - } - } - } - - public void SetData(Bitmap bitmap) - { - if (!IsPowerOf2(bitmap.Width) || !IsPowerOf2(bitmap.Height)) - { - //throw new InvalidOperationException( "non-power-of-2-texture" ); - bitmap = new Bitmap(bitmap, new Size(NextPowerOf2(bitmap.Width), NextPowerOf2(bitmap.Height))); - } - - var bits = bitmap.LockBits( - new Rectangle(0, 0, bitmap.Width, bitmap.Height), - ImageLockMode.ReadOnly, - PixelFormat.Format32bppArgb); - - PrepareTexture(); - Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, bits.Width, bits.Height, - 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, bits.Scan0); // todo: weird strides - GraphicsDevice.CheckGlError(); - bitmap.UnlockBits(bits); - } - - bool IsPowerOf2(int v) - { - return (v & (v - 1)) == 0; - } - - int NextPowerOf2(int v) - { - --v; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - ++v; - return v; - } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using System.Drawing.Imaging; +using OpenRA.FileFormats.Graphics; +using Tao.OpenGl; +using System.IO; +using System; + +namespace OpenRA.Renderer.Glsl +{ + public class Texture : ITexture + { + internal int texture; + + public Texture(GraphicsDevice dev) + { + Gl.glGenTextures(1, out texture); + GraphicsDevice.CheckGlError(); + } + + public Texture(GraphicsDevice dev, Bitmap bitmap) + { + Gl.glGenTextures(1, out texture); + GraphicsDevice.CheckGlError(); + SetData(bitmap); + } + + void PrepareTexture() + { + GraphicsDevice.CheckGlError(); + Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture); + GraphicsDevice.CheckGlError(); + Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST); + GraphicsDevice.CheckGlError(); + Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST); + GraphicsDevice.CheckGlError(); + + Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BASE_LEVEL, 0); + GraphicsDevice.CheckGlError(); + Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_LEVEL, 0); + GraphicsDevice.CheckGlError(); + } + + public void SetData(byte[] colors, int width, int height) + { + if (!IsPowerOf2(width) || !IsPowerOf2(height)) + throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width, height)); + + unsafe + { + fixed (byte* ptr = &colors[0]) + { + IntPtr intPtr = new IntPtr((void*)ptr); + PrepareTexture(); + Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height, + 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr); + GraphicsDevice.CheckGlError(); + } + } + } + + // An array of RGBA + public void SetData(uint[,] colors) + { + int width = colors.GetUpperBound(1) + 1; + int height = colors.GetUpperBound(0) + 1; + + if (!IsPowerOf2(width) || !IsPowerOf2(height)) + throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width,height)); + + unsafe + { + fixed (uint* ptr = &colors[0,0]) + { + IntPtr intPtr = new IntPtr((void *) ptr); + PrepareTexture(); + Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height, + 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr); + GraphicsDevice.CheckGlError(); + } + } + } + + public void SetData(Bitmap bitmap) + { + if (!IsPowerOf2(bitmap.Width) || !IsPowerOf2(bitmap.Height)) + { + //throw new InvalidOperationException( "non-power-of-2-texture" ); + bitmap = new Bitmap(bitmap, new Size(NextPowerOf2(bitmap.Width), NextPowerOf2(bitmap.Height))); + } + + var bits = bitmap.LockBits( + new Rectangle(0, 0, bitmap.Width, bitmap.Height), + ImageLockMode.ReadOnly, + PixelFormat.Format32bppArgb); + + PrepareTexture(); + Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, bits.Width, bits.Height, + 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, bits.Scan0); // todo: weird strides + GraphicsDevice.CheckGlError(); + bitmap.UnlockBits(bits); + } + + bool IsPowerOf2(int v) + { + return (v & (v - 1)) == 0; + } + + int NextPowerOf2(int v) + { + --v; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + ++v; + return v; + } + } +} diff --git a/OpenRA.Renderer.Gl/VertexBuffer.cs b/OpenRA.Renderer.Gl/VertexBuffer.cs index 70564f4c13..2dda205674 100644 --- a/OpenRA.Renderer.Gl/VertexBuffer.cs +++ b/OpenRA.Renderer.Gl/VertexBuffer.cs @@ -1,67 +1,67 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Runtime.InteropServices; -using OpenRA.FileFormats.Graphics; -using Tao.OpenGl; - -namespace OpenRA.Renderer.Glsl -{ - public class VertexBuffer : IVertexBuffer, IDisposable - where T : struct - { - int buffer; - - public VertexBuffer(GraphicsDevice dev, int size) - { - Gl.glGenBuffers(1, out buffer); - GraphicsDevice.CheckGlError(); - Bind(); - Gl.glBufferData(Gl.GL_ARRAY_BUFFER, - new IntPtr(Marshal.SizeOf(typeof(T)) * size), - new T[ size ], - Gl.GL_DYNAMIC_DRAW); - GraphicsDevice.CheckGlError(); - } - - public void SetData(T[] data, int length) - { - Bind(); - Gl.glBufferSubData(Gl.GL_ARRAY_BUFFER, - IntPtr.Zero, - new IntPtr(Marshal.SizeOf(typeof(T)) * length), - data); - GraphicsDevice.CheckGlError(); - } - - public void Bind() - { - Gl.glBindBuffer(Gl.GL_ARRAY_BUFFER, buffer); - GraphicsDevice.CheckGlError(); - Gl.glVertexPointer(3, Gl.GL_FLOAT, Marshal.SizeOf(typeof(T)), IntPtr.Zero); - GraphicsDevice.CheckGlError(); - Gl.glTexCoordPointer(4, Gl.GL_FLOAT, Marshal.SizeOf(typeof(T)), new IntPtr(12)); - GraphicsDevice.CheckGlError(); - } - - bool disposed; - public void Dispose() - { - if (disposed) return; - GC.SuppressFinalize(this); - Gl.glDeleteBuffers(1, ref buffer); - GraphicsDevice.CheckGlError(); - disposed = true; - } - - //~VertexBuffer() { Dispose(); } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Runtime.InteropServices; +using OpenRA.FileFormats.Graphics; +using Tao.OpenGl; + +namespace OpenRA.Renderer.Glsl +{ + public class VertexBuffer : IVertexBuffer, IDisposable + where T : struct + { + int buffer; + + public VertexBuffer(GraphicsDevice dev, int size) + { + Gl.glGenBuffers(1, out buffer); + GraphicsDevice.CheckGlError(); + Bind(); + Gl.glBufferData(Gl.GL_ARRAY_BUFFER, + new IntPtr(Marshal.SizeOf(typeof(T)) * size), + new T[ size ], + Gl.GL_DYNAMIC_DRAW); + GraphicsDevice.CheckGlError(); + } + + public void SetData(T[] data, int length) + { + Bind(); + Gl.glBufferSubData(Gl.GL_ARRAY_BUFFER, + IntPtr.Zero, + new IntPtr(Marshal.SizeOf(typeof(T)) * length), + data); + GraphicsDevice.CheckGlError(); + } + + public void Bind() + { + Gl.glBindBuffer(Gl.GL_ARRAY_BUFFER, buffer); + GraphicsDevice.CheckGlError(); + Gl.glVertexPointer(3, Gl.GL_FLOAT, Marshal.SizeOf(typeof(T)), IntPtr.Zero); + GraphicsDevice.CheckGlError(); + Gl.glTexCoordPointer(4, Gl.GL_FLOAT, Marshal.SizeOf(typeof(T)), new IntPtr(12)); + GraphicsDevice.CheckGlError(); + } + + bool disposed; + public void Dispose() + { + if (disposed) return; + GC.SuppressFinalize(this); + Gl.glDeleteBuffers(1, ref buffer); + GraphicsDevice.CheckGlError(); + disposed = true; + } + + //~VertexBuffer() { Dispose(); } + } +} diff --git a/OpenRA.Renderer.Null/NullGraphicsDevice.cs b/OpenRA.Renderer.Null/NullGraphicsDevice.cs index 824bedf6e6..ab462a7be1 100644 --- a/OpenRA.Renderer.Null/NullGraphicsDevice.cs +++ b/OpenRA.Renderer.Null/NullGraphicsDevice.cs @@ -1,78 +1,78 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System.Drawing; -using System.IO; -using OpenRA.FileFormats.Graphics; -using OpenRA.Graphics; -using System; - -[assembly: Renderer(typeof(OpenRA.Renderer.Null.NullGraphicsDevice))] - -namespace OpenRA.Renderer.Null -{ - public class NullGraphicsDevice : IGraphicsDevice - { - public Size WindowSize { get; internal set; } - - public NullGraphicsDevice(int width, int height, WindowMode window, bool vsync) - { - Console.WriteLine("Using Null renderer"); - WindowSize = new Size(width, height); - } - - public void EnableScissor(int left, int top, int width, int height) { } - public void DisableScissor() { } - - public void Clear(Color c) { } - - public void Present(IInputHandler ih) - { - Game.HasInputFocus = false; - ih.ModifierKeys(Modifiers.None); - } - - public void DrawIndexedPrimitives(PrimitiveType pt, Range vertices, Range indices) { } - public void DrawIndexedPrimitives(PrimitiveType pt, int numVerts, int numPrimitives) { } - - public IVertexBuffer CreateVertexBuffer(int size) { return new NullVertexBuffer(); } - public IIndexBuffer CreateIndexBuffer(int size) { return new NullIndexBuffer(); } - public ITexture CreateTexture() { return new NullTexture(); } - public ITexture CreateTexture(Bitmap bitmap) { return new NullTexture(); } - public IShader CreateShader(string name) { return new NullShader(); } - } - - public class NullIndexBuffer : IIndexBuffer - { - public void Bind() {} - public void SetData(ushort[] indices, int length) {} - } - - public class NullShader : IShader - { - public void SetValue(string name, float x, float y) { } - public void SetValue(string param, ITexture texture) { } - public void Commit() { } - public void Render(Action a) { } - } - - public class NullTexture : ITexture - { - public void SetData(Bitmap bitmap) { } - public void SetData(uint[,] colors) { } - public void SetData(byte[] colors, int width, int height) { } - } - - class NullVertexBuffer : IVertexBuffer - { - public void Bind() { } - public void SetData(T[] vertices, int length) { } - } -} +#region Copyright & License Information +/* + * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Drawing; +using System.IO; +using OpenRA.FileFormats.Graphics; +using OpenRA.Graphics; +using System; + +[assembly: Renderer(typeof(OpenRA.Renderer.Null.NullGraphicsDevice))] + +namespace OpenRA.Renderer.Null +{ + public class NullGraphicsDevice : IGraphicsDevice + { + public Size WindowSize { get; internal set; } + + public NullGraphicsDevice(int width, int height, WindowMode window, bool vsync) + { + Console.WriteLine("Using Null renderer"); + WindowSize = new Size(width, height); + } + + public void EnableScissor(int left, int top, int width, int height) { } + public void DisableScissor() { } + + public void Clear(Color c) { } + + public void Present(IInputHandler ih) + { + Game.HasInputFocus = false; + ih.ModifierKeys(Modifiers.None); + } + + public void DrawIndexedPrimitives(PrimitiveType pt, Range vertices, Range indices) { } + public void DrawIndexedPrimitives(PrimitiveType pt, int numVerts, int numPrimitives) { } + + public IVertexBuffer CreateVertexBuffer(int size) { return new NullVertexBuffer(); } + public IIndexBuffer CreateIndexBuffer(int size) { return new NullIndexBuffer(); } + public ITexture CreateTexture() { return new NullTexture(); } + public ITexture CreateTexture(Bitmap bitmap) { return new NullTexture(); } + public IShader CreateShader(string name) { return new NullShader(); } + } + + public class NullIndexBuffer : IIndexBuffer + { + public void Bind() {} + public void SetData(ushort[] indices, int length) {} + } + + public class NullShader : IShader + { + public void SetValue(string name, float x, float y) { } + public void SetValue(string param, ITexture texture) { } + public void Commit() { } + public void Render(Action a) { } + } + + public class NullTexture : ITexture + { + public void SetData(Bitmap bitmap) { } + public void SetData(uint[,] colors) { } + public void SetData(byte[] colors, int width, int height) { } + } + + class NullVertexBuffer : IVertexBuffer + { + public void Bind() { } + public void SetData(T[] vertices, int length) { } + } +} diff --git a/OpenRA.TilesetBuilder/Form1.cs b/OpenRA.TilesetBuilder/Form1.cs index 90f4b48caf..9c79a7b347 100644 --- a/OpenRA.TilesetBuilder/Form1.cs +++ b/OpenRA.TilesetBuilder/Form1.cs @@ -1,279 +1,279 @@ -#region Copyright & License Information -/* - * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation. For more information, - * see LICENSE. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using System.Linq; -using System.Windows.Forms; -using System.Xml; -using OpenRA.FileFormats; - -namespace OpenRA.TilesetBuilder -{ - public partial class Form1 : Form - { - string srcfile; - int size; - - public Form1( string src, int size ) - { - srcfile = src; - this.size = size; - InitializeComponent(); - surface1.TileSize = size; - surface1.Image = (Bitmap)Image.FromFile(src); - surface1.Image.SetResolution(96, 96); // people keep being noobs about DPI, and GDI+ cares. - surface1.TerrainTypes = new int[surface1.Image.Width / size, surface1.Image.Height / size]; /* all passable by default */ - surface1.Templates = new List