Merge pull request #7175 from pchote/hardware-cursors

Closes #7015
This commit is contained in:
Matthias Mailänder
2014-12-24 09:37:17 +01:00
22 changed files with 1025 additions and 695 deletions

View File

@@ -29,6 +29,7 @@ namespace OpenRA
{
public static ModData modData;
public static Settings Settings;
public static ICursor Cursor;
static WorldRenderer worldRenderer;
internal static OrderManager orderManager;
@@ -129,6 +130,7 @@ namespace OpenRA
public static event Action BeforeGameStart = () => { };
internal static void StartGame(string mapUID, bool isShellmap)
{
Cursor.SetCursor(null);
BeforeGameStart();
Map map;
@@ -157,6 +159,7 @@ namespace OpenRA
orderManager.LastTickTime = RunTime;
orderManager.StartGame();
worldRenderer.RefreshPalette();
Cursor.SetCursor("default");
GC.Collect();
}
@@ -287,11 +290,33 @@ namespace OpenRA
Sound.Initialize();
modData = new ModData(mod, true);
Renderer.InitializeFonts(modData.Manifest);
modData.InitializeLoaders();
using (new PerfTimer("LoadMaps"))
modData.MapCache.LoadMaps();
if (Settings.Graphics.HardwareCursors)
{
try
{
Cursor = new HardwareCursor(modData.CursorProvider);
}
catch (Exception e)
{
Log.Write("debug", "Failed to initialize hardware cursors. Falling back to software cursors.");
Log.Write("debug", "Error was: " + e.Message);
Console.WriteLine("Failed to initialize hardware cursors. Falling back to software cursors.");
Console.WriteLine("Error was: " + e.Message);
Cursor = new SoftwareCursor(modData.CursorProvider);
Settings.Graphics.HardwareCursors = false;
}
}
else
Cursor = new SoftwareCursor(modData.CursorProvider);
PerfHistory.items["render"].hasNormalTick = false;
PerfHistory.items["batches"].hasNormalTick = false;
PerfHistory.items["render_widgets"].hasNormalTick = false;
@@ -401,8 +426,6 @@ namespace OpenRA
public static void RunAfterTick(Action a) { delayedActions.Add(a); }
public static void RunAfterDelay(int delay, Action a) { delayedActions.Add(a, delay); }
static float cursorFrame = 0f;
static void InnerLogicTick(OrderManager orderManager)
{
var tick = RunTime;
@@ -419,7 +442,7 @@ namespace OpenRA
Viewport.TicksSinceLastMove += uiTickDelta / Timestep;
Sync.CheckSyncUnchanged(world, Ui.Tick);
cursorFrame += 0.5f;
Cursor.Tick();
}
var worldTimestep = world == null ? Timestep : world.Timestep;
@@ -509,8 +532,8 @@ namespace OpenRA
if (modData != null && modData.CursorProvider != null)
{
var cursorName = Ui.Root.GetCursorOuter(Viewport.LastMousePos) ?? "default";
modData.CursorProvider.DrawCursor(Renderer, cursorName, Viewport.LastMousePos, (int)cursorFrame);
Cursor.SetCursor(Ui.Root.GetCursorOuter(Viewport.LastMousePos) ?? "default");
Cursor.Render(Renderer);
}
}

View File

@@ -10,26 +10,21 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileSystem;
using OpenRA.Primitives;
namespace OpenRA.Graphics
{
public sealed class CursorProvider : IDisposable
public sealed class CursorProvider
{
readonly HardwarePalette palette = new HardwarePalette();
readonly Dictionary<string, CursorSequence> cursors = new Dictionary<string, CursorSequence>();
readonly Cache<string, PaletteReference> palettes;
readonly SheetBuilder sheetBuilder;
public static bool CursorViewportZoomed { get { return Game.Settings.Graphics.CursorDouble && Game.Settings.Graphics.PixelDouble; } }
public readonly IReadOnlyDictionary<string, CursorSequence> Cursors;
public readonly IReadOnlyDictionary<string, ImmutablePalette> Palettes;
public CursorProvider(ModData modData)
{
var sequenceFiles = modData.Manifest.Cursors;
palettes = new Cache<string, PaletteReference>(CreatePaletteReference);
var sequences = new MiniYaml(null, sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(MiniYaml.MergeLiberal));
var shadowIndex = new int[] { };
@@ -41,65 +36,35 @@ namespace OpenRA.Graphics
out shadowIndex[shadowIndex.Length - 1]);
}
var palettes = new Dictionary<string, ImmutablePalette>();
foreach (var p in nodesDict["Palettes"].Nodes)
palette.AddPalette(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex), false);
palettes.Add(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex));
sheetBuilder = new SheetBuilder(SheetType.Indexed);
var spriteCache = new SpriteCache(modData.SpriteLoaders, new string[0], sheetBuilder);
Palettes = palettes.AsReadOnly();
var frameCache = new FrameCache(modData.SpriteLoaders, new string[0]);
var cursors = new Dictionary<string, CursorSequence>();
foreach (var s in nodesDict["Cursors"].Nodes)
LoadSequencesForCursor(spriteCache, s.Key, s.Value);
sheetBuilder.Current.ReleaseBuffer();
foreach (var sequence in s.Value.Nodes)
cursors.Add(sequence.Key, new CursorSequence(frameCache, sequence.Key, s.Key, s.Value.Value, sequence.Value));
palette.Initialize();
Cursors = cursors.AsReadOnly();
}
PaletteReference CreatePaletteReference(string name)
{
var pal = palette.GetPalette(name);
return new PaletteReference(name, palette.GetPaletteIndex(name), pal);
}
void LoadSequencesForCursor(SpriteCache cache, string cursorSrc, MiniYaml cursor)
{
foreach (var sequence in cursor.Nodes)
cursors.Add(sequence.Key, new CursorSequence(cache, cursorSrc, cursor.Value, sequence.Value));
}
public static bool CursorViewportZoomed { get { return Game.Settings.Graphics.CursorDouble && Game.Settings.Graphics.PixelDouble; } }
public bool HasCursorSequence(string cursor)
{
return cursors.ContainsKey(cursor);
}
public void DrawCursor(Renderer renderer, string cursorName, int2 lastMousePos, int cursorFrame)
{
var cursorSequence = GetCursorSequence(cursorName);
var cursorSprite = cursorSequence.GetSprite(cursorFrame);
var cursorSize = CursorViewportZoomed ? 2.0f * cursorSprite.size : cursorSprite.size;
var cursorOffset = CursorViewportZoomed ?
(2 * cursorSequence.Hotspot) + cursorSprite.size.ToInt2() :
cursorSequence.Hotspot + (0.5f * cursorSprite.size).ToInt2();
renderer.SetPalette(palette);
renderer.SpriteRenderer.DrawSprite(cursorSprite,
lastMousePos - cursorOffset,
palettes[cursorSequence.Palette],
cursorSize);
return Cursors.ContainsKey(cursor);
}
public CursorSequence GetCursorSequence(string cursor)
{
try { return cursors[cursor]; }
try { return Cursors[cursor]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException("Cursor does not have a sequence `{0}`".F(cursor));
}
}
public void Dispose()
{
palette.Dispose();
sheetBuilder.Dispose();
}
}
}

View File

@@ -8,47 +8,46 @@
*/
#endregion
using System.Linq;
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 string Name;
public readonly int Start;
public readonly int Length;
public readonly string Palette;
public readonly int2 Hotspot;
Sprite[] sprites;
public readonly ISpriteFrame[] Frames;
public CursorSequence(SpriteCache cache, string cursorSrc, string palette, MiniYaml info)
public CursorSequence(FrameCache cache, string name, string cursorSrc, string palette, MiniYaml info)
{
sprites = cache[cursorSrc];
var d = info.ToDictionary();
start = Exts.ParseIntegerInvariant(d["start"].Value);
this.palette = palette;
Start = Exts.ParseIntegerInvariant(d["Start"].Value);
Palette = palette;
Name = name;
if ((d.ContainsKey("length") && d["length"].Value == "*") || (d.ContainsKey("end") && d["end"].Value == "*"))
length = sprites.Length - start;
else if (d.ContainsKey("length"))
length = Exts.ParseIntegerInvariant(d["length"].Value);
else if (d.ContainsKey("end"))
length = Exts.ParseIntegerInvariant(d["end"].Value) - start;
if ((d.ContainsKey("Length") && d["Length"].Value == "*") || (d.ContainsKey("End") && d["End"].Value == "*"))
Length = Frames.Length - Start;
else if (d.ContainsKey("Length"))
Length = Exts.ParseIntegerInvariant(d["Length"].Value);
else if (d.ContainsKey("End"))
Length = Exts.ParseIntegerInvariant(d["End"].Value) - Start;
else
length = 1;
Length = 1;
if (d.ContainsKey("x"))
Exts.TryParseIntegerInvariant(d["x"].Value, out Hotspot.X);
if (d.ContainsKey("y"))
Exts.TryParseIntegerInvariant(d["y"].Value, out Hotspot.Y);
}
Frames = cache[cursorSrc]
.Skip(Start)
.Take(Length)
.ToArray();
public Sprite GetSprite(int frame)
{
return sprites[(frame % length) + start];
if (d.ContainsKey("X"))
Exts.TryParseIntegerInvariant(d["X"].Value, out Hotspot.X);
if (d.ContainsKey("Y"))
Exts.TryParseIntegerInvariant(d["Y"].Value, out Hotspot.Y);
}
}
}

View File

@@ -0,0 +1,138 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you 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.Primitives;
namespace OpenRA.Graphics
{
public class HardwareCursor : ICursor
{
readonly Dictionary<string, IHardwareCursor[]> hardwareCursors = new Dictionary<string, IHardwareCursor[]>();
readonly CursorProvider cursorProvider;
CursorSequence cursor;
public HardwareCursor(CursorProvider cursorProvider)
{
this.cursorProvider = cursorProvider;
foreach (var kv in cursorProvider.Cursors)
{
var palette = cursorProvider.Palettes[kv.Value.Palette];
var hc = kv.Value.Frames
.Select(f => CreateCursor(f, palette, kv.Key, kv.Value))
.ToArray();
hardwareCursors.Add(kv.Key, hc);
}
Update();
}
IHardwareCursor CreateCursor(ISpriteFrame f, ImmutablePalette palette, string name, CursorSequence sequence)
{
var hotspot = sequence.Hotspot - f.Offset.ToInt2() + new int2(f.Size) / 2;
// Expand the frame if required to include the hotspot
var frameWidth = f.Size.Width;
var dataWidth = f.Size.Width;
var dataX = 0;
if (hotspot.X < 0)
{
dataX = -hotspot.X;
dataWidth += dataX;
hotspot.X = 0;
}
else if (hotspot.X >= frameWidth)
dataWidth = hotspot.X + 1;
var frameHeight = f.Size.Height;
var dataHeight = f.Size.Height;
var dataY = 0;
if (hotspot.Y < 0)
{
dataY = -hotspot.Y;
dataHeight += dataY;
hotspot.Y = 0;
}
else if (hotspot.Y >= frameHeight)
dataHeight = hotspot.Y + 1;
var data = new byte[4 * dataWidth * dataHeight];
for (var j = 0; j < frameHeight; j++)
{
for (var i = 0; i < frameWidth; i++)
{
var bytes = BitConverter.GetBytes(palette[f.Data[j * frameWidth + i]]);
var start = 4 * ((j + dataY) * dataWidth + dataX + i);
for (var k = 0; k < 4; k++)
data[start + k] = bytes[k];
}
}
return Game.Renderer.Device.CreateHardwareCursor(name, new Size(dataWidth, dataHeight), data, hotspot);
}
public void SetCursor(string cursorName)
{
if ((cursorName == null && cursor == null) || (cursor != null && cursorName == cursor.Name))
return;
if (cursorName == null || !cursorProvider.Cursors.TryGetValue(cursorName, out cursor))
cursor = null;
Update();
}
int frame;
int ticks;
public void Tick()
{
if (cursor == null || cursor.Length == 1)
return;
if (++ticks > 2)
{
ticks -= 2;
frame++;
Update();
}
}
void Update()
{
if (cursor == null)
Game.Renderer.Device.SetHardwareCursor(null);
else
{
if (frame >= cursor.Length)
frame = frame % cursor.Length;
Game.Renderer.Device.SetHardwareCursor(hardwareCursors[cursor.Name][frame]);
}
}
public void Render(Renderer renderer) { }
public void Dispose()
{
foreach (var cursors in hardwareCursors)
foreach (var cursor in cursors.Value)
cursor.Dispose();
hardwareCursors.Clear();
}
}
}

View File

@@ -32,6 +32,8 @@ namespace OpenRA
IGraphicsDevice Create(Size size, WindowMode windowMode);
}
public interface IHardwareCursor : IDisposable { }
public enum BlendMode : byte { None, Alpha, Additive, Subtractive, Multiply }
public interface IGraphicsDevice : IDisposable
@@ -61,6 +63,9 @@ namespace OpenRA
void GrabWindowMouseFocus();
void ReleaseWindowMouseFocus();
IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot);
void SetHardwareCursor(IHardwareCursor cursor);
}
public interface IVertexBuffer<T> : IDisposable

View File

@@ -0,0 +1,102 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you 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.Primitives;
namespace OpenRA.Graphics
{
public interface ICursor : IDisposable
{
void Render(Renderer renderer);
void SetCursor(string cursor);
void Tick();
}
public class SoftwareCursor : ICursor
{
readonly HardwarePalette palette = new HardwarePalette();
readonly Cache<string, PaletteReference> paletteReferences;
readonly Dictionary<string, Sprite[]> sprites = new Dictionary<string, Sprite[]>();
readonly CursorProvider cursorProvider;
readonly SheetBuilder sheetBuilder;
public SoftwareCursor(CursorProvider cursorProvider)
{
this.cursorProvider = cursorProvider;
paletteReferences = new Cache<string, PaletteReference>(CreatePaletteReference);
foreach (var p in cursorProvider.Palettes)
palette.AddPalette(p.Key, p.Value, false);
palette.Initialize();
sheetBuilder = new SheetBuilder(SheetType.Indexed);
foreach (var kv in cursorProvider.Cursors)
{
var s = kv.Value.Frames.Select(a => sheetBuilder.Add(a)).ToArray();
sprites.Add(kv.Key, s);
}
sheetBuilder.Current.ReleaseBuffer();
Game.Renderer.Device.SetHardwareCursor(null);
}
PaletteReference CreatePaletteReference(string name)
{
var pal = palette.GetPalette(name);
return new PaletteReference(name, palette.GetPaletteIndex(name), pal);
}
string cursorName;
public void SetCursor(string cursor)
{
cursorName = cursor;
}
float cursorFrame;
public void Tick()
{
cursorFrame += 0.5f;
}
public void Render(Renderer renderer)
{
if (cursorName == null)
return;
var cursorSequence = cursorProvider.GetCursorSequence(cursorName);
var cursorSprite = sprites[cursorName][((int)cursorFrame % cursorSequence.Length)];
var cursorSize = CursorProvider.CursorViewportZoomed ? 2.0f * cursorSprite.size : cursorSprite.size;
var cursorOffset = CursorProvider.CursorViewportZoomed ?
(2 * cursorSequence.Hotspot) + cursorSprite.size.ToInt2() :
cursorSequence.Hotspot + (0.5f * cursorSprite.size).ToInt2();
renderer.SetPalette(palette);
renderer.SpriteRenderer.DrawSprite(cursorSprite,
Viewport.LastMousePos - cursorOffset,
paletteReferences[cursorSequence.Palette],
cursorSize);
}
public void Dispose()
{
palette.Dispose();
sheetBuilder.Dispose();
}
}
}

View File

@@ -52,6 +52,8 @@ namespace OpenRA.Graphics
public FrameCache(ISpriteLoader[] loaders, string[] exts)
{
// Include extension-less version
exts = exts.Append("").ToArray();
frames = new Cache<string, ISpriteFrame[]>(filename => SpriteLoader.GetFrames(filename, exts, loaders));
}

View File

@@ -90,8 +90,6 @@ namespace OpenRA
VoxelLoader.Dispose();
VoxelLoader = new VoxelLoader();
if (CursorProvider != null)
CursorProvider.Dispose();
CursorProvider = new CursorProvider(this);
}
@@ -175,8 +173,6 @@ namespace OpenRA
MapCache.Dispose();
if (VoxelLoader != null)
VoxelLoader.Dispose();
if (CursorProvider != null)
CursorProvider.Dispose();
}
}

View File

@@ -252,6 +252,8 @@
<Compile Include="Graphics\TargetLineRenderable.cs" />
<Compile Include="Graphics\UISpriteRenderable.cs" />
<Compile Include="GameRules\DamageWarhead.cs" />
<Compile Include="Graphics\SoftwareCursor.cs" />
<Compile Include="Graphics\HardwareCursor.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="FileSystem\D2kSoundResources.cs" />

View File

@@ -80,6 +80,7 @@ namespace OpenRA
public WindowMode Mode = WindowMode.PseudoFullscreen;
public int2 FullscreenSize = new int2(0, 0);
public int2 WindowedSize = new int2(1024, 768);
public bool HardwareCursors = true;
public bool PixelDouble = false;
public bool CursorDouble = false;
public bool CapFramerate = true;

View File

@@ -62,6 +62,17 @@ namespace OpenRA.Mods.Common.UtilityCommands
file.WriteLine(yaml.WriteToString());
}
Console.WriteLine("Processing Cursors:");
foreach (var filename in Game.modData.Manifest.Cursors)
{
Console.WriteLine("\t" + filename);
var yaml = MiniYaml.FromFile(filename);
UpgradeRules.UpgradeCursors(engineDate, ref yaml, null, 0);
using (var file = new StreamWriter(filename))
file.WriteLine(yaml.WriteToString());
}
Console.WriteLine("Processing Maps:");
var maps = Game.modData.MapCache
.Where(m => m.Status == MapStatus.Available)

View File

@@ -1041,5 +1041,27 @@ namespace OpenRA.Mods.Common.UtilityCommands
nodes.AddRange(addNodes);
}
internal static void UpgradeCursors(int engineVersion, ref List<MiniYamlNode> nodes, MiniYamlNode parent, int depth)
{
foreach (var node in nodes)
{
if (engineVersion < 20141113 && depth == 3)
{
if (node.Key == "start")
node.Key = "Start";
else if (node.Key == "length")
node.Key = "Length";
else if (node.Key == "end")
node.Key = "End";
else if (node.Key == "x")
node.Key = "X";
else if (node.Key == "y")
node.Key = "Y";
}
UpgradeCursors(engineVersion, ref node.Value.Nodes, node, depth + 1);
}
}
}
}

View File

@@ -148,6 +148,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var ds = Game.Settings.Graphics;
var gs = Game.Settings.Game;
BindCheckboxPref(panel, "HARDWARECURSORS_CHECKBOX", ds, "HardwareCursors");
BindCheckboxPref(panel, "PIXELDOUBLE_CHECKBOX", ds, "PixelDouble");
BindCheckboxPref(panel, "CURSORDOUBLE_CHECKBOX", ds, "CursorDouble");
BindCheckboxPref(panel, "FRAME_LIMIT_CHECKBOX", ds, "CapFramerate");
@@ -173,8 +174,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
worldRenderer.Viewport.Zoom = ds.PixelDouble ? 2 : 1;
};
// Cursor doubling is only supported with software cursors and when pixel doubling is enabled
var cursorDoubleCheckbox = panel.Get<CheckboxWidget>("CURSORDOUBLE_CHECKBOX");
cursorDoubleCheckbox.IsDisabled = () => !ds.PixelDouble;
cursorDoubleCheckbox.IsDisabled = () => !ds.PixelDouble || Game.Cursor is HardwareCursor;
var cursorDoubleIsChecked = cursorDoubleCheckbox.IsChecked;
cursorDoubleCheckbox.IsChecked = () => !cursorDoubleCheckbox.IsDisabled() && cursorDoubleIsChecked();
panel.Get("WINDOW_RESOLUTION").IsVisible = () => ds.Mode == WindowMode.Windowed;
var windowWidth = panel.Get<TextFieldWidget>("WINDOW_WIDTH");

View File

@@ -66,6 +66,9 @@ namespace OpenRA.Renderer.Null
public ITexture CreateTexture(Bitmap bitmap) { return new NullTexture(); }
public IFrameBuffer CreateFrameBuffer(Size s) { return new NullFrameBuffer(); }
public IShader CreateShader(string name) { return new NullShader(); }
public IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot) { return null; }
public void SetHardwareCursor(IHardwareCursor cursor) { }
}
public class NullShader : IShader

View File

@@ -10,6 +10,8 @@
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using OpenRA;
using OpenRA.Graphics;
using OpenTK.Graphics.OpenGL;
@@ -80,7 +82,6 @@ namespace OpenRA.Renderer.Sdl2
SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
}
SDL.SDL_ShowCursor(0);
context = SDL.SDL_GL_CreateContext(window);
SDL.SDL_GL_MakeCurrent(window, context);
GL.LoadAll();
@@ -103,10 +104,53 @@ namespace OpenRA.Renderer.Sdl2
input = new Sdl2Input();
}
public IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot)
{
var c = new SDL2HardwareCursor(size, data, hotspot);
if (c.Cursor == IntPtr.Zero)
throw new InvalidDataException("Failed to create hardware cursor `{0}`: {1}".F(name, SDL.SDL_GetError()));
return c;
}
public void SetHardwareCursor(IHardwareCursor cursor)
{
var c = cursor as SDL2HardwareCursor;
if (c == null)
SDL.SDL_ShowCursor(0);
else
{
SDL.SDL_ShowCursor(1);
SDL.SDL_SetCursor(c.Cursor);
}
}
class SDL2HardwareCursor : IHardwareCursor
{
public readonly IntPtr Cursor;
readonly IntPtr surface;
public SDL2HardwareCursor(Size size, byte[] data, int2 hotspot)
{
surface = SDL.SDL_CreateRGBSurface(0, size.Width, size.Height, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
var sur = (SDL2.SDL.SDL_Surface)Marshal.PtrToStructure(surface, typeof(SDL2.SDL.SDL_Surface));
Marshal.Copy(data, 0, sur.pixels, data.Length);
Cursor = SDL.SDL_CreateColorCursor(surface, hotspot.X, hotspot.Y);
}
public void Dispose()
{
SDL.SDL_FreeCursor(Cursor);
SDL.SDL_FreeSurface(surface);
}
}
public void Dispose()
{
if (disposed)
return;
disposed = true;
if (context != IntPtr.Zero)
{

View File

@@ -50,21 +50,21 @@ Container@SETTINGS_PANEL:
Text: Display
Align: Center
Label@MODE_LABEL:
X: 120
X: 110
Y: 39
Width: 45
Height: 25
Align: Right
Text: Mode:
DropDownButton@MODE_DROPDOWN:
X: 170
X: 160
Y: 40
Width: 170
Height: 25
Font: Regular
Text: Windowed
Container@WINDOW_RESOLUTION:
X: 340
X: 330
Y: 40
Children:
Label@At:
@@ -92,62 +92,69 @@ Container@SETTINGS_PANEL:
Width: 45
Height: 25
MaxLength: 5
Checkbox@HARDWARECURSORS_CHECKBOX:
X: 310
Y: 75
Width: 200
Height: 20
Font: Regular
Text: Use Hardware Cursors
Label@VIDEO_DESC:
Y: 60
Y: 93
Width: PARENT_RIGHT
Height: 25
Font: Tiny
Align: Center
Text: Mode/Resolution changes will be applied after the game is restarted
Text: Mode, resolution, and cursor changes will be applied after the game is restarted
Checkbox@FRAME_LIMIT_CHECKBOX:
X: 15
Y: 100
Y: 125
Width: 200
Height: 20
Font: Regular
Text: Enable Frame Limiter
Checkbox@PIXELDOUBLE_CHECKBOX:
X: 310
Y: 100
Y: 125
Width: 200
Height: 20
Font: Regular
Text: Enable Pixel Doubling
Checkbox@CURSORDOUBLE_CHECKBOX:
X: 355
Y: 135
X: 340
Y: 155
Width: 200
Height: 20
Font: Regular
Text: Also Double Cursor
Label@FRAME_LIMIT_DESC_A:
X: 45
Y: 132
Y: 152
Width: 50
Height: 25
Text: Limit to
Align: Right
TextField@FRAME_LIMIT_TEXTFIELD:
X: 100
Y: 133
Y: 153
Width: 45
Height: 25
MaxLength: 3
Label@FRAME_LIMIT_DESC_B:
X: 150
Y: 132
Y: 152
Height: 25
Text: FPS
Checkbox@TEAM_HEALTH_COLORS_CHECKBOX:
X: 310
Y: 170
Y: 185
Width: 200
Height: 20
Font: Regular
Text: Team Health Colors
Checkbox@SHOW_SHELLMAP:
X: 15
Y: 170
Y: 185
Width: 200
Height: 20
Font: Regular
@@ -155,18 +162,18 @@ Container@SETTINGS_PANEL:
Label@PLAYER:
Text: Player:
X: 15
Y: 215
Y: 225
TextField@PLAYERNAME:
Text: Name
X: 65
Y: 205
Y: 215
Width: 145
Height: 25
MaxLength: 16
ColorPreviewManager@COLOR_MANAGER:
DropDownButton@PLAYERCOLOR:
X: 215
Y: 205
Y: 215
Width: 70
Height: 25
IgnoreChildMouseOver: true
@@ -178,13 +185,13 @@ Container@SETTINGS_PANEL:
Height: PARENT_BOTTOM-12
Checkbox@ALWAYS_SHOW_STATUS_BARS_CHECKBOX:
X: 310
Y: 205
Y: 215
Width: 200
Height: 20
Font: Regular
Text: Always Show Status Bars
Label@LOCALIZATION_TITLE:
Y: 225
Y: 265
Width: PARENT_RIGHT
Font: Bold
Text: Localization
@@ -192,7 +199,7 @@ Container@SETTINGS_PANEL:
Visible: false
Label@LANGUAGE_LABEL:
X: 230 - WIDTH - 5
Y: 244
Y: 284
Width: 75
Height: 25
Align: Right
@@ -200,13 +207,13 @@ Container@SETTINGS_PANEL:
Visible: false
DropDownButton@LANGUAGE_DROPDOWNBUTTON:
X: 230
Y: 245
Y: 285
Width: 200
Height: 25
Font: Regular
Visible: false
Label@LANGUAGE_DESC_A:
Y: 265
Y: 310
Width: PARENT_RIGHT
Height: 25
Font: Tiny
@@ -214,7 +221,7 @@ Container@SETTINGS_PANEL:
Text: Language changes will be applied after the game is restarted
Visible: false
Label@LANGUAGE_DESC_B:
Y: 280
Y: 325
Width: PARENT_RIGHT
Height: 25
Font: Tiny

View File

@@ -1,181 +1,180 @@
Palettes:
Palettes:
cursor: cursor.pal
Cursors:
mouse2.shp: cursor
scroll-t:
start:1
Start: 1
scroll-tr:
start:2
Start: 2
scroll-r:
start:3
Start: 3
scroll-br:
start:4
Start: 4
scroll-b:
start:5
Start: 5
scroll-bl:
start:6
Start: 6
scroll-l:
start:7
Start: 7
scroll-tl:
start:8
Start: 8
scroll-t-blocked:
start:130
Start: 130
scroll-tr-blocked:
start:131
Start: 131
scroll-r-blocked:
start:132
Start: 132
scroll-br-blocked:
start:133
Start: 133
scroll-b-blocked:
start:134
Start: 134
scroll-bl-blocked:
start:135
Start: 135
scroll-l-blocked:
start:136
Start: 136
scroll-tl-blocked:
start:137
Start: 137
select:
start:12
length:6
Start: 12
Length: 6
default-minimap:
start:86
length:1
x: -16
y: -12
Start: 86
Length: 1
X: -16
Y: -12
generic-blocked:
start:9
Start: 9
generic-blocked-minimap:
start:27
Start: 27
attack:
start:18
length:8
Start: 18
Length: 8
attack-minimap:
start:140
length:8
Start: 140
Length: 8
harvest:
start:18
length:8
Start: 18
Length: 8
harvest-minimap:
start:140
length:8
Start: 140
Length: 8
enter:
start:119
length:3
Start: 119
Length: 3
enter-minimap:
start:148
length:3
Start: 148
Length: 3
c4:
start:122
length:3
Start: 122
Length: 3
c4-minimap:
start:127
length:3
Start: 127
Length: 3
# Cursors that need minimap variants
deploy:
start:53
length:9
Start: 53
Length: 9
repair:
start:29
length:24
Start: 29
Length: 24
repair-blocked:
start:126
length:1
Start: 126
Length: 1
sell:
start:62
length:24
Start: 62
Length: 24
sell-blocked:
start:125
length:1
Start: 125
Length: 1
ability:
start:88
length:8
Start: 88
Length: 8
nuke:
start:96
length:7
Start: 96
Length: 7
ioncannon:
start:103
length:16
Start: 103
Length: 16
sell-vehicle:
start:154
length:24
Start: 154
Length: 24
mouse3.shp: cursor
default:
start:0
x: -16
y: -12
Start: 0
X: -16
Y: -12
deploy-blocked:
start:1
length:1
Start: 1
Length: 1
mouse4.shp: cursor
move:
start:0
length:8
Start: 0
Length: 8
move-minimap:
start:8
length:4
Start: 8
Length: 4
move-rough:
start:0
length: 8
Start: 0
Length: 8
attackmove:
start:12
length:8
Start: 12
Length: 8
attackmove-minimap:
start:20
length:4
Start: 20
Length: 4
move-blocked:
start:24
length:1
Start: 24
Length: 1
move-blocked-minimap:
start:25
length:1
Start: 25
Length: 1
mouse5.shp: cursor
guard:
start:0
length:8
Start: 0
Length: 8
guard-minimap:
start:8
length:8
Start: 8
Length: 8
mouse6.shp: cursor
goldwrench:
start:0
length:3
Start: 0
Length: 3
goldwrench-minimap:
start:3
length:3
Start: 3
Length: 3
goldwrench-blocked:
start:6
length:1
Start: 6
Length: 1
goldwrench-blocked-minimap:
start:7
length:1
Start: 7
Length: 1
capture:
start:8
length:3
Start: 8
Length: 3
capture-minimap:
start:11
length:3
Start: 11
Length: 3
capture-blocked:
start:14
length:1
Start: 14
Length: 1
capture-blocked-minimap:
start:15
length:1
Start: 15
Length: 1
enter-blocked:
start:16
length:1
Start: 16
Length: 1
enter-blocked-minimap:
start:17
length:1
Start: 17
Length: 1
mouse7.shp: cursor
attackoutsiderange:
start:0
length:8
Start: 0
Length: 8
attackoutsiderange-minimap:
start:8
Start: 8

View File

@@ -6,269 +6,268 @@ Palettes:
Cursors:
mouse.r8: mouse
scroll-t:
start:112
x: 24
y: 24
Start: 112
X: 24
Y: 24
scroll-tr:
start: 120
x: 24
y: 24
Start: 120
X: 24
Y: 24
scroll-r:
start: 128
x: 24
y: 24
Start: 128
X: 24
Y: 24
scroll-br:
start: 136
x: 24
y: 24
Start: 136
X: 24
Y: 24
scroll-b:
start:148
x: 24
y: 24
Start: 148
X: 24
Y: 24
scroll-bl:
start:156
x: 24
y: 24
Start: 156
X: 24
Y: 24
scroll-l:
start:164
x: 24
y: 24
Start: 164
X: 24
Y: 24
scroll-tl:
start:172
x: 24
y: 24
Start: 172
X: 24
Y: 24
scroll-t-blocked:
start:180
x: 24
y: 24
Start: 180
X: 24
Y: 24
scroll-tr-blocked:
start:188
x: 24
y: 24
Start: 188
X: 24
Y: 24
scroll-r-blocked:
start:196
x: 24
y: 24
Start: 196
X: 24
Y: 24
scroll-br-blocked:
start:204
x: 24
y: 24
Start: 204
X: 24
Y: 24
scroll-b-blocked:
start:212
x: 24
y: 24
Start: 212
X: 24
Y: 24
scroll-bl-blocked:
start:220
x: 24
y: 24
Start: 220
X: 24
Y: 24
scroll-l-blocked:
start:228
x: 24
y: 24
Start: 228
X: 24
Y: 24
scroll-tl-blocked:
start:236
x: 24
y: 24
Start: 236
X: 24
Y: 24
select:
start:40
length: 8
x: 24
y: 24
Start: 40
Length: 8
X: 24
Y: 24
default:
start:0
x: 24
y: 24
Start: 0
X: 24
Y: 24
default-minimap:
start:0
x: 24
y: 24
Start: 0
X: 24
Y: 24
generic-blocked:
start:24
x: 24
y: 24
Start: 24
X: 24
Y: 24
generic-blocked-minimap:
start:24
x: 24
y: 24
Start: 24
X: 24
Y: 24
move:
start:8
length: 8
x: 24
y: 24
Start: 8
Length: 8
X: 24
Y: 24
move-minimap:
start:48
length: 8
x: 24
y: 24
Start: 48
Length: 8
X: 24
Y: 24
move-blocked:
start:24
x: 24
y: 24
Start: 24
X: 24
Y: 24
move-blocked-minimap:
start:24
x: 24
y: 24
Start: 24
X: 24
Y: 24
attack:
start:16
length: 8
x: 24
y: 24
Start: 16
Length: 8
X: 24
Y: 24
attack-minimap:
start:16
length: 8
x: 24
y: 24
Start: 16
Length: 8
X: 24
Y: 24
attackoutsiderange:
start:16
length: 8
x: 24
y: 24
Start: 16
Length: 8
X: 24
Y: 24
attackoutsiderange-minimap:
start:16
length: 8
x: 24
y: 24
Start: 16
Length: 8
X: 24
Y: 24
attackmove:
start:16
length: 8
x: 24
y: 24
Start: 16
Length: 8
X: 24
Y: 24
attackmove-minimap:
start:16
length: 8
x: 24
y: 24
Start: 16
Length: 8
X: 24
Y: 24
harvest:
start:16
length: 8
x: 24
y: 24
Start: 16
Length: 8
X: 24
Y: 24
harvest-minimap:
start:203
length: 8
x: 24
y: 24
Start: 203
Length: 8
X: 24
Y: 24
enter:
start:32
length: 8
x: 24
y: 24
Start: 32
Length: 8
X: 24
Y: 24
enter-minimap:
start:32
length: 8
x: 24
y: 24
Start: 32
Length: 8
X: 24
Y: 24
enter-blocked:
start:104
length: 1
x: 24
y: 24
Start: 104
Length: 1
X: 24
Y: 24
enter-blocked-minimap:
start:104
x: 24
y: 24
Start: 104
X: 24
Y: 24
c4:
start:248
length: 8
x: 24
y: 24
Start: 248
Length: 8
X: 24
Y: 24
c4-minimap:
start:248
length: 8
x: 24
y: 24
Start: 248
Length: 8
X: 24
Y: 24
guard:
start:72
length: 8
x: 24
y: 24
Start: 72
Length: 8
X: 24
Y: 24
guard-minimap:
start:72
length: 8
x: 24
y: 24
Start: 72
Length: 8
X: 24
Y: 24
capture:
start:32
length: 8
x: 24
y: 24
Start: 32
Length: 8
X: 24
Y: 24
capture-minimap:
start:32
length: 8
x: 24
y: 24
Start: 32
Length: 8
X: 24
Y: 24
ability:
start:72
length: 8
x: 24
y: 24
Start: 72
Length: 8
X: 24
Y: 24
ability-minimap:
start:72
length: 8
x: 24
y: 24
Start: 72
Length: 8
X: 24
Y: 24
# Cursors that need minimap variants
deploy:
start:96
length: 8
x: 24
y: 24
Start: 96
Length: 8
X: 24
Y: 24
deploy-blocked:
start:104
length: 1
x: 24
y: 24
Start: 104
Length: 1
X: 24
Y: 24
nuke:
start:240
length: 8
x: 24
y: 24
Start: 240
Length: 8
X: 24
Y: 24
sell:
start:80
length: 8
x: 24
y: 24
Start: 80
Length: 8
X: 24
Y: 24
sell-blocked:
start:56
length: 1
x: 24
y: 24
Start: 56
Length: 1
X: 24
Y: 24
repair:
start:88
length: 8
x: 24
y: 24
Start: 88
Length: 8
X: 24
Y: 24
repair-blocked:
start:64
length: 1
x: 24
y: 24
Start: 64
Length: 1
X: 24
Y: 24
goldwrench:
start:88
length: 8
x: 24
y: 24
Start: 88
Length: 8
X: 24
Y: 24
goldwrench-blocked:
start:64
length: 1
x: 24
y: 24
Start: 64
Length: 1
X: 24
Y: 24
move-rough:
start:256
length: 8
x: 24
y: 24
Start: 256
Length: 8
X: 24
Y: 24
nopower.shp: mouse
powerdown-blocked:
start:0
length: 1
x: 12
y: 12
Start: 0
Length: 1
X: 12
Y: 12
powerdown:
start:1
length: 3
x: 12
y: 12
Start: 1
Length: 3
X: 12
Y: 12

View File

@@ -4,6 +4,6 @@
Cursors:
cursor.shp: cursor
default:
start:0
x: -4
y: -7
Start:0
X: -4
Y: -7

View File

@@ -63,21 +63,21 @@ Background@SETTINGS_PANEL:
Height: PARENT_BOTTOM
Children:
Label@MODE_LABEL:
X: 120
X: 110
Y: 39
Width: 45
Height: 25
Align: Right
Text: Mode:
DropDownButton@MODE_DROPDOWN:
X: 170
X: 160
Y: 40
Width: 170
Height: 25
Font: Regular
Text: Windowed
Container@WINDOW_RESOLUTION:
X: 340
X: 330
Y: 40
Children:
Label@At:
@@ -105,62 +105,69 @@ Background@SETTINGS_PANEL:
Width: 45
Height: 25
MaxLength: 5
Checkbox@HARDWARECURSORS_CHECKBOX:
X: 310
Y: 75
Width: 200
Height: 20
Font: Regular
Text: Use Hardware Cursors
Label@VIDEO_DESC:
Y: 60
Y: 93
Width: PARENT_RIGHT
Height: 25
Font: Tiny
Align: Center
Text: Mode/Resolution changes will be applied after the game is restarted
Text: Mode, resolution, and cursor changes will be applied after the game is restarted
Checkbox@FRAME_LIMIT_CHECKBOX:
X: 15
Y: 100
Y: 125
Width: 200
Height: 20
Font: Regular
Text: Enable Frame Limiter
Checkbox@PIXELDOUBLE_CHECKBOX:
X: 310
Y: 100
Y: 125
Width: 200
Height: 20
Font: Regular
Text: Enable Pixel Doubling
Checkbox@CURSORDOUBLE_CHECKBOX:
X: 355
Y: 135
X: 340
Y: 160
Width: 200
Height: 20
Font: Regular
Text: Also Double Cursor
Label@FRAME_LIMIT_DESC_A:
X: 45
Y: 132
Y: 157
Width: 50
Height: 25
Text: Limit to
Align: Right
TextField@FRAME_LIMIT_TEXTFIELD:
X: 100
Y: 133
Y: 158
Width: 45
Height: 25
MaxLength: 3
Label@FRAME_LIMIT_DESC_B:
X: 150
Y: 132
Y: 157
Height: 25
Text: FPS
Checkbox@TEAM_HEALTH_COLORS_CHECKBOX:
X: 310
Y: 170
Y: 195
Width: 200
Height: 20
Font: Regular
Text: Team Health Colors
Checkbox@SHOW_SHELLMAP:
X: 15
Y: 170
Y: 195
Width: 200
Height: 20
Font: Regular
@@ -168,18 +175,18 @@ Background@SETTINGS_PANEL:
Label@PLAYER:
Text: Player:
X: 15
Y: 215
Y: 240
TextField@PLAYERNAME:
Text: Name
X: 65
Y: 205
Y: 230
Width: 145
Height: 25
MaxLength: 16
ColorPreviewManager@COLOR_MANAGER:
DropDownButton@PLAYERCOLOR:
X: 215
Y: 205
Y: 230
Width: 70
Height: 25
IgnoreChildMouseOver: true
@@ -191,13 +198,13 @@ Background@SETTINGS_PANEL:
Height: PARENT_BOTTOM-12
Checkbox@ALWAYS_SHOW_STATUS_BARS_CHECKBOX:
X: 310
Y: 205
Y: 230
Width: 200
Height: 20
Font: Regular
Text: Always Show Status Bars
Label@LOCALIZATION_TITLE:
Y: 225
Y: 270
Width: PARENT_RIGHT
Font: Bold
Text: Localization
@@ -205,7 +212,7 @@ Background@SETTINGS_PANEL:
Visible: false
Label@LANGUAGE_LABEL:
X: 230 - WIDTH - 5
Y: 244
Y: 289
Width: 75
Height: 25
Align: Right
@@ -213,12 +220,12 @@ Background@SETTINGS_PANEL:
Visible: false
DropDownButton@LANGUAGE_DROPDOWNBUTTON:
X: 230
Y: 245
Y: 290
Width: 200
Height: 25
Visible: false
Label@LANGUAGE_DESC_A:
Y: 265
Y: 310
Width: PARENT_RIGHT
Height: 25
Font: Tiny
@@ -226,7 +233,7 @@ Background@SETTINGS_PANEL:
Text: Language changes will be applied after the game is restarted
Visible: false
Label@LANGUAGE_DESC_B:
Y: 280
Y: 325
Width: PARENT_RIGHT
Height: 25
Font: Tiny

View File

@@ -1,180 +1,179 @@
Palettes:
Palettes:
cursor: cursor.pal
Cursors:
mouse.shp: cursor
scroll-t:
start:1
Start: 1
scroll-tr:
start:2
Start: 2
scroll-r:
start:3
Start: 3
scroll-br:
start:4
Start: 4
scroll-b:
start:5
Start: 5
scroll-bl:
start:6
Start: 6
scroll-l:
start:7
Start: 7
scroll-tl:
start:8
Start: 8
scroll-t-blocked:
start:124
Start: 124
scroll-tr-blocked:
start:125
Start: 125
scroll-r-blocked:
start:126
Start: 126
scroll-br-blocked:
start:127
Start: 127
scroll-b-blocked:
start:128
Start: 128
scroll-bl-blocked:
start:129
Start: 129
scroll-l-blocked:
start:130
Start: 130
scroll-tl-blocked:
start:131
Start: 131
select:
start:15
length: 6
Start: 15
Length: 6
default:
start:0
x: -16
y: -12
Start: 0
X: -16
Y: -12
default-minimap:
start:80
x: -16
y: -12
Start: 80
X: -16
Y: -12
generic-blocked:
start:9
Start: 9
generic-blocked-minimap:
start:33
Start: 33
move:
start:10
length: 4
Start: 10
Length: 4
move-minimap:
start:29
length: 4
Start: 29
Length: 4
move-rough:
start:10
length: 4
Start: 10
Length: 4
move-blocked:
start:14
Start: 14
move-blocked-minimap:
start:33
Start: 33
attack:
start:195
length: 8
Start: 195
Length: 8
attack-minimap:
start:203
length: 8
Start: 203
Length: 8
attackoutsiderange:
start:21
length: 8
Start: 21
Length: 8
attackoutsiderange-minimap:
start:134
length: 8
Start: 134
Length: 8
harvest:
start:21
length: 8
Start: 21
Length: 8
harvest-minimap:
start:134
length: 8
Start: 134
Length: 8
enter:
start:113
length: 3
Start: 113
Length: 3
enter-minimap:
start:139
length: 3
Start: 139
Length: 3
enter-blocked:
start:212
length: 1
Start: 212
Length: 1
enter-blocked-minimap:
start:33
Start: 33
c4:
start:116
length: 3
Start: 116
Length: 3
c4-minimap:
start:121
length: 3
Start: 121
Length: 3
guard:
start:147
length: 1
Start: 147
Length: 1
guard-minimap:
start:146
length: 1
Start: 146
Length: 1
capture:
start:164
length: 3
Start: 164
Length: 3
capture-minimap:
start:167
length: 3
Start: 167
Length: 3
heal:
start:160
length: 4
Start: 160
Length: 4
heal-minimap:
start:194
length: 1
Start: 194
Length: 1
ability:
start:82
length: 8
Start: 82
Length: 8
ability-minimap:
start:214
length: 8
Start: 214
Length: 8
# Cursors that need minimap variants
deploy:
start:59
length: 9
Start: 59
Length: 9
deploy-blocked:
start:211
length: 1
Start: 211
Length: 1
goldwrench:
start:170
length: 24
Start: 170
Length: 24
goldwrench-blocked:
start:213
length: 1
Start: 213
Length: 1
nuke:
start:90
length: 7
Start: 90
Length: 7
chrono-select:
start:97
length: 8
Start: 97
Length: 8
chrono-target:
start:105
length: 8
Start: 105
Length: 8
sell:
start:68
length: 12
Start: 68
Length: 12
sell-blocked:
start:119
length: 1
Start: 119
Length: 1
repair:
start:35
length: 24
Start: 35
Length: 24
repair-blocked:
start:120
length: 1
Start: 120
Length: 1
sell2:
start:148
length: 12
Start: 148
Length: 12
nopower.shp: cursor
powerdown-blocked:
start:0
length: 1
Start: 0
Length: 1
powerdown:
start:1
length: 3
Start: 1
Length: 3
attackmove.shp: cursor
attackmove:
start:0
length: 4
Start: 0
Length: 4
attackmove-minimap:
start:4
length: 4
Start: 4
Length: 4

View File

@@ -1,175 +1,176 @@
Palettes:
Palettes:
cursor: mousepal.pal
Cursors:
mouse.shp: cursor
scroll-t: #TODO
start: 2
scroll-tr: #TODO
start: 3
scroll-r: #TODO
start: 4
scroll-br: #TODO
start: 5
scroll-b: #TODO
start: 6
scroll-bl: #TODO
start: 7
scroll-l: #TODO
start: 8
scroll-tl: #TODO
start: 9
scroll-t-blocked: #TODO
start: 10
scroll-tr-blocked: #TODO
start: 11
scroll-r-blocked: #TODO
start: 12
scroll-br-blocked: #TODO
start: 13
scroll-b-blocked: #TODO
start: 14
scroll-bl-blocked: #TODO
start: 15
scroll-l-blocked: #TODO
start: 16
scroll-tl-blocked: #TODO
start: 17
scroll-t:
Start: 2
scroll-tr:
Start: 3
scroll-r:
Start: 4
scroll-br:
Start: 5
scroll-b:
Start: 6
scroll-bl:
Start: 7
scroll-l:
Start: 8
scroll-tl:
Start: 9
scroll-t-blocked:
Start: 10
scroll-tr-blocked:
Start: 11
scroll-r-blocked:
Start: 12
scroll-br-blocked:
Start: 13
scroll-b-blocked:
Start: 14
scroll-bl-blocked:
Start: 15
scroll-l-blocked:
Start: 16
scroll-tl-blocked:
Start: 17
select:
start:18
length: 12
Start: 18
Length: 12
default:
start:0
x: -26
y: -20
Start: 0
X: -26
Y: -20
default-minimap:
start:1
x: -26
y: -20
Start: 1
X: -26
Y: -20
generic-blocked:
start:9
Start: 9
generic-blocked-minimap:
start:52
Start: 52
move:
start:31
length: 10
Start: 31
Length: 10
move-minimap:
start:42
length: 10
Start: 42
Length: 10
move-rough:
start:31
length: 10
Start: 31
Length: 10
move-blocked:
start:41
Start: 41
move-blocked-minimap:
start:52
Start: 52
attack:
start: 53
length: 5
Start: 53
Length: 5
attack-blocked: # TODO: unused
start: 41
length: 1
Start: 41
Length: 1
attack-minimap:
start: 63
length: 5
Start: 63
Length: 5
attackoutsiderange:
start: 58
length: 5
Start: 58
Length: 5
attackoutsiderange-minimap:
start: 63
length: 5
attackmove: #TODO
start: 58
length: 5
attackmove-minimap: #TODO
start:68
length: 5
harvest: #TODO
start:53
length: 5
harvest-minimap: #TODO
start:134
length: 8
Start: 63
Length: 5
attackmove:
Start: 58
Length: 5
attackmove-minimap:
Start: 68
Length: 5
harvest:
Start: 53
Length: 5
harvest-minimap:
Start: 134
Length: 8
enter:
start: 89
length: 10
Start: 89
Length: 10
enter-minimap:
start: 100
length: 10
Start: 100
Length: 10
enter-blocked:
start: 99
length: 1
enter-blocked-minimap: #TODO
start:33
Start: 99
Length: 1
enter-blocked-minimap:
Start: 33
c4:
start: 309
length: 10
c4-minimap: #TODO
start:121
length: 3
Start: 309
Length: 10
c4-minimap:
Start: 121
Length: 3
guard:
start: 68
length: 5
Start: 68
Length: 5
guard-minimap:
start: 73
length: 5
Start: 73
Length: 5
capture:
start: 89
length: 10
Start: 89
Length: 10
capture-minimap:
start: 100
length: 10
Start: 100
Length: 10
heal:
start: 346
length: 10
heal-minimap: #TODO
start:194
length: 1
Start: 346
Length: 10
heal-minimap:
Start: 194
Length: 1
ability:
start: 78
length: 10
ability-minimap: #TODO
start:214
length: 8
Start: 78
Length: 10
ability-minimap:
Start: 214
Length: 8
deploy:
start: 110
length: 9
Start: 110
Length: 9
deploy-blocked:
start: 119
length: 1
Start: 119
Length: 1
undeploy: #TODO: unused
start:120
length: 9
goldwrench: #TODO
start:170
length: 24
Start: 120
Length: 9
goldwrench:
Start: 170
Length: 24
goldwrench-blocked: #TODO
start:213
length: 1
nuke: #TODO
start:90
length: 7
Start: 213
Length: 1
nuke:
Start: 90
Length: 7
sell:
start:129
length: 10
Start: 129
Length: 10
sell-minimap: #TODO: unused
start:139
length: 10
Start: 139
Length: 10
sell-blocked:
start:149
length: 1
Start: 149
Length: 1
repair:
start:170
length: 20
Start: 170
Length: 20
repair-blocked:
start:190
length: 1
Start: 190
Length: 1
sell2:
start:139
length: 10
Start: 139
Length: 10
powerdown-blocked:
start:345
length: 1
Start: 345
Length: 1
powerdown:
start:329
length: 15
Start: 329
Length: 15