Add map beacons and radar pings

This commit is contained in:
ScottNZ
2014-02-19 21:43:54 +13:00
parent 7be3078115
commit 2a8efde8e6
24 changed files with 345 additions and 17 deletions

View File

@@ -150,6 +150,8 @@ namespace OpenRA.GameRules
public Hotkey SelectAllUnitsKey = new Hotkey(Keycode.A, Modifiers.Ctrl);
public Hotkey SelectUnitsByTypeKey = new Hotkey(Keycode.T, Modifiers.Ctrl);
public Hotkey PlaceBeaconKey = new Hotkey(Keycode.B, Modifiers.Ctrl);
public Hotkey PauseKey = new Hotkey(Keycode.F9, Modifiers.None);
public Hotkey SellKey = new Hotkey(Keycode.F10, Modifiers.None);
public Hotkey PowerDownKey = new Hotkey(Keycode.F11, Modifiers.None);

View File

@@ -0,0 +1,64 @@
#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.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Graphics;
namespace OpenRA.Mods.RA.Effects
{
public class Beacon : IEffect
{
readonly Player owner;
readonly WPos position;
readonly string palettePrefix;
readonly Animation arrow = new Animation("beacon");
readonly Animation circles = new Animation("beacon");
static readonly int maxArrowHeight = 512;
int arrowHeight = maxArrowHeight;
int arrowSpeed = 50;
public Beacon(Player owner, WPos position, int duration, string palettePrefix)
{
this.owner = owner;
this.position = position;
this.palettePrefix = palettePrefix;
arrow.Play("arrow");
circles.Play("circles");
owner.World.Add(new DelayedAction(duration, () => owner.World.Remove(this)));
}
public void Tick(World world)
{
arrowHeight += arrowSpeed;
var clamped = arrowHeight.Clamp(0, maxArrowHeight);
if (arrowHeight != clamped)
{
arrowHeight = clamped;
arrowSpeed *= -1;
}
arrow.Tick();
circles.Tick();
}
public IEnumerable<IRenderable> Render(WorldRenderer r)
{
if (!owner.IsAlliedWith(owner.World.RenderPlayer))
return SpriteRenderable.None;
var palette = r.Palette(palettePrefix + owner.InternalName);
return circles.Render(position, palette).Concat(arrow.Render(position + new WVec(0, 0, arrowHeight), palette));
}
}
}

View File

@@ -123,6 +123,8 @@
<Compile Include="Air\Aircraft.cs" />
<Compile Include="Air\AttackHeli.cs" />
<Compile Include="Air\AttackPlane.cs" />
<Compile Include="Effects\Beacon.cs" />
<Compile Include="Player\PlaceBeacon.cs" />
<Compile Include="MenuPaletteEffect.cs" />
<Compile Include="Crates\UnitUpgradeCrateAction.cs" />
<Compile Include="EjectOnDeath.cs" />
@@ -306,6 +308,7 @@
<Compile Include="Player\ClassicProductionQueue.cs" />
<Compile Include="Player\PlaceBuilding.cs" />
<Compile Include="Player\ProductionQueue.cs" />
<Compile Include="World\RadarPings.cs" />
<Compile Include="Player\TechTree.cs" />
<Compile Include="PlayerExts.cs" />
<Compile Include="PrimaryBuilding.cs" />

View File

@@ -0,0 +1,73 @@
#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 OpenRA.Mods.RA.Effects;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class PlaceBeaconInfo : ITraitInfo
{
public readonly int Duration = 30 * 25;
public readonly string NotificationType = "Sounds";
public readonly string Notification = "Beacon";
public readonly string PalettePrefix = "player";
public object Create(ActorInitializer init) { return new PlaceBeacon(init.self, this); }
}
public class PlaceBeacon : IResolveOrder
{
readonly PlaceBeaconInfo info;
readonly RadarPings radarPings;
Beacon playerBeacon;
RadarPing playerRadarPing;
public PlaceBeacon(Actor self, PlaceBeaconInfo info)
{
radarPings = self.World.WorldActor.TraitOrDefault<RadarPings>();
this.info = info;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString != "PlaceBeacon")
return;
var pos = order.TargetLocation.CenterPosition;
self.World.AddFrameEndTask(w =>
{
if (playerBeacon != null)
self.World.Remove(playerBeacon);
playerBeacon = new Beacon(self.Owner, pos, info.Duration, info.PalettePrefix);
self.World.Add(playerBeacon);
if (self.Owner.IsAlliedWith(self.World.RenderPlayer))
Sound.PlayNotification(null, info.NotificationType, info.Notification,
self.World.RenderPlayer != null ? self.World.RenderPlayer.Country.Race : null);
if (radarPings != null)
{
if (playerRadarPing != null)
radarPings.Remove(playerRadarPing);
playerRadarPing = radarPings.Add(
() => self.Owner.IsAlliedWith(self.World.RenderPlayer),
pos,
self.Owner.Color.RGB,
info.Duration);
}
});
}
}
}

View File

@@ -255,6 +255,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{ "SelectAllUnitsKey", "Select all units on screen" },
{ "SelectUnitsByTypeKey", "Select units by type" },
{ "PlaceBeaconKey", "Place beacon" },
{ "PauseKey", "Pause / Unpause" },
{ "SellKey", "Sell mode" },
{ "PowerDownKey", "Power-down mode" },

View File

@@ -10,6 +10,7 @@
using System;
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Widgets;
@@ -22,8 +23,8 @@ namespace OpenRA.Mods.RA.Widgets
public string RadarOnlineSound = null;
public string RadarOfflineSound = null;
public Func<bool> IsEnabled = () => true;
public Action AfterOpen = () => {};
public Action AfterClose = () => {};
public Action AfterOpen = () => { };
public Action AfterClose = () => { };
float radarMinimapHeight;
int frame;
@@ -43,11 +44,14 @@ namespace OpenRA.Mods.RA.Widgets
readonly World world;
readonly WorldRenderer worldRenderer;
readonly RadarPings radarPings;
[ObjectCreator.UseCtor]
public RadarWidget(World world, WorldRenderer worldRenderer)
{
this.world = world;
this.worldRenderer = worldRenderer;
radarPings = world.WorldActor.TraitOrDefault<RadarPings>();
}
public override void Initialize(WidgetArgs args)
@@ -60,8 +64,8 @@ namespace OpenRA.Mods.RA.Widgets
var rb = RenderBounds;
previewScale = Math.Min(rb.Width * 1f / width, rb.Height * 1f / height);
previewOrigin = new int2((int)(previewScale*(size - width)/2), (int)(previewScale*(size - height)/2));
mapRect = new Rectangle(previewOrigin.X, previewOrigin.Y, (int)(previewScale*width), (int)(previewScale*height));
previewOrigin = new int2((int)(previewScale * (size - width) / 2), (int)(previewScale * (size - height) / 2));
mapRect = new Rectangle(previewOrigin.X, previewOrigin.Y, (int)(previewScale * width), (int)(previewScale * height));
// Only needs to be done once
var terrainBitmap = Minimap.TerrainBitmap(world.Map);
@@ -95,7 +99,7 @@ namespace OpenRA.Mods.RA.Widgets
if (cursor == null)
return "default";
return CursorProvider.HasCursorSequence(cursor+"-minimap") ? cursor+"-minimap" : cursor;
return CursorProvider.HasCursorSequence(cursor + "-minimap") ? cursor + "-minimap" : cursor;
}
public override bool HandleMouseInput(MouseInput mi)
@@ -140,8 +144,8 @@ namespace OpenRA.Mods.RA.Widgets
if (world == null)
return;
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);
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);
var rsr = Game.Renderer.RgbaSpriteRenderer;
rsr.DrawSprite(terrainSprite, o, s);
@@ -156,11 +160,34 @@ namespace OpenRA.Mods.RA.Widgets
var br = CellToMinimapPixel(worldRenderer.Position(worldRenderer.Viewport.BottomRight).ToCPos());
Game.Renderer.EnableScissor(mapRect);
DrawRadarPings();
Game.Renderer.LineRenderer.DrawRect(tl, br, Color.White);
Game.Renderer.DisableScissor();
}
}
void DrawRadarPings()
{
if (radarPings == null)
return;
var lr = Game.Renderer.LineRenderer;
var oldWidth = lr.LineWidth;
lr.LineWidth = 2;
foreach (var radarPing in radarPings.Pings.Where(e => e.IsVisible()))
{
var c = radarPing.Color;
var points = radarPing.Points(CellToMinimapPixel(radarPing.Position.ToCPos())).ToArray();
lr.DrawLine(points[0], points[1], c, c);
lr.DrawLine(points[1], points[2], c, c);
lr.DrawLine(points[2], points[0], c, c);
}
lr.LineWidth = oldWidth;
}
public override void Tick()
{
// Update the radar animation even when its closed

View File

@@ -63,6 +63,9 @@ namespace OpenRA.Mods.RA.Widgets
if (key == ks.ToggleStatusBarsKey)
return ToggleStatusBars();
if (key == ks.PlaceBeaconKey)
return PerformPlaceBeacon();
// Put all functions that aren't unit-specific before this line!
if (!world.Selection.Actors.Any())
return false;
@@ -180,6 +183,15 @@ namespace OpenRA.Mods.RA.Widgets
return true;
}
bool PerformPlaceBeacon()
{
if (world.LocalPlayer == null)
return true;
world.OrderGenerator = new GenericSelectTarget(world.LocalPlayer.PlayerActor, "PlaceBeacon", "ability");
return true;
}
bool CycleBases()
{
var bases = world.ActorsWithTrait<BaseBuilding>()

View File

@@ -0,0 +1,106 @@
#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 OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class RadarPingsInfo : ITraitInfo
{
public readonly int FromRadius = 200;
public readonly int ToRadius = 15;
public readonly int ShrinkSpeed = 4;
public readonly float RotationSpeed = 0.12f;
public object Create(ActorInitializer init) { return new RadarPings(this); }
}
public class RadarPings : ITick
{
public readonly List<RadarPing> Pings = new List<RadarPing>();
readonly RadarPingsInfo info;
public RadarPings(RadarPingsInfo info)
{
this.info = info;
}
public void Tick(Actor self)
{
foreach (var ping in Pings.ToArray())
if (!ping.Tick())
Pings.Remove(ping);
}
public RadarPing Add(Func<bool> isVisible, WPos position, Color color, int duration)
{
var ping = new RadarPing(isVisible, position, color, duration,
info.FromRadius, info.ToRadius, info.ShrinkSpeed, info.RotationSpeed);
Pings.Add(ping);
return ping;
}
public void Remove(RadarPing ping)
{
Pings.Remove(ping);
}
}
public class RadarPing
{
public Func<bool> IsVisible;
public WPos Position;
public Color Color;
public int Duration;
public int FromRadius;
public int ToRadius;
public int ShrinkSpeed;
public float RotationSpeed;
int radius;
float angle;
int tick;
public RadarPing(Func<bool> isVisible, WPos position, Color color, int duration,
int fromRadius, int toRadius, int shrinkSpeed, float rotationSpeed)
{
IsVisible = isVisible;
Position = position;
Color = color;
Duration = duration;
FromRadius = fromRadius;
ToRadius = toRadius;
ShrinkSpeed = shrinkSpeed;
RotationSpeed = rotationSpeed;
radius = fromRadius;
}
public bool Tick()
{
if (++tick == Duration)
return false;
radius = Math.Max(radius - ShrinkSpeed, ToRadius);
angle -= RotationSpeed;
return true;
}
public IEnumerable<float2> Points(float2 center)
{
yield return center + radius * float2.FromAngle(angle);
yield return center + radius * float2.FromAngle((float)(angle + 2 * Math.PI / 3));
yield return center + radius * float2.FromAngle((float)(angle + 4 * Math.PI / 3));
}
}
}

View File

@@ -41,4 +41,5 @@ Sounds:
ChatLine: scold1
TabClick: button
ClickSound: button
ClickDisabledSound: scold2
ClickDisabledSound: scold2
Beacon: bleep2

View File

@@ -16,4 +16,5 @@ Player:
Shroud:
PlayerStatistics:
FrozenActorLayer:
PlaceBeacon:

View File

@@ -175,4 +175,4 @@ World:
DebugPauseState:
ConquestObjectivesPanel:
ObjectivesPanel: CONQUEST_OBJECTIVES
RadarPings:

View File

@@ -152,6 +152,14 @@ rallypoint:
Start: 0
Length: *
beacon:
arrow: mouse2
Start: 5
Offset: 1,-12
circles: fpls
Start: 0
Length: *
select:
repair:
Start: 2

View File

@@ -47,4 +47,5 @@ Sounds:
BuildPaletteClose: BUTTON1
TabClick: SIDEBAR1
ClickSound: BUTTON1
ClickDisabledSound: ENDLIST1
ClickDisabledSound: ENDLIST1
Beacon: CHAT1

View File

@@ -51,4 +51,4 @@ Player:
FrozenActorLayer:
HarvesterAttackNotifier:
PlayerStatistics:
PlaceBeacon:

View File

@@ -126,4 +126,4 @@ World:
PathFinder:
ValidateOrder:
DebugPauseState:
RadarPings:

View File

@@ -130,6 +130,14 @@ rallypoint:
Start: 0
Length: *
beacon:
arrow: mouse
Start: 148
Offset: -24,-24
circles: fpls
Start: 0
Length: *
rpg:
idle: DATA
Start: 3015

View File

@@ -42,4 +42,5 @@ Sounds:
BuildPaletteClose: bleep13
TabClick: ramenu1
ClickSound:
ClickDisabledSound:
ClickDisabledSound:
Beacon: beepslct

View File

@@ -56,4 +56,5 @@ Player:
FrozenActorLayer:
BaseAttackNotifier:
PlayerStatistics:
PlaceBeacon:

View File

@@ -164,4 +164,4 @@ World:
PathFinder:
ValidateOrder:
DebugPauseState:
RadarPings:

View File

@@ -114,6 +114,14 @@ rallypoint:
Start: 0
Length: *
beacon:
arrow: mouse
Start: 5
Offset: 1,-12
circles: fpls
Start: 0
Length: *
smoke_m:
idle:
Start: 0

View File

@@ -39,4 +39,5 @@ Sounds:
BuildPaletteClose:
TabClick:
ClickSound:clicky1
ClickDisabledSound:wrong1
ClickDisabledSound:wrong1
Beacon: message1

View File

@@ -40,4 +40,4 @@ Player:
Shroud:
BaseAttackNotifier:
PlayerStatistics:
PlaceBeacon:

View File

@@ -96,4 +96,4 @@ World:
ValidateOrder:
DebugPauseState:
ScreenShaker:
RadarPings:

View File

@@ -44,6 +44,15 @@ rallypoint:
Length: 12
BlendMode: Additive
beacon:
arrow: mouse
Start: 6
Offset: 1,-12
circles: ring
Start: 0
Length: 12
BlendMode: Additive
rank: # TODO: backfall to RA asset
rank:
Start: 0