Add map beacons and radar pings
This commit is contained in:
@@ -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);
|
||||
|
||||
64
OpenRA.Mods.RA/Effects/Beacon.cs
Normal file
64
OpenRA.Mods.RA/Effects/Beacon.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
73
OpenRA.Mods.RA/Player/PlaceBeacon.cs
Normal file
73
OpenRA.Mods.RA/Player/PlaceBeacon.cs
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" },
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>()
|
||||
|
||||
106
OpenRA.Mods.RA/World/RadarPings.cs
Normal file
106
OpenRA.Mods.RA/World/RadarPings.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,4 +41,5 @@ Sounds:
|
||||
ChatLine: scold1
|
||||
TabClick: button
|
||||
ClickSound: button
|
||||
ClickDisabledSound: scold2
|
||||
ClickDisabledSound: scold2
|
||||
Beacon: bleep2
|
||||
@@ -16,4 +16,5 @@ Player:
|
||||
Shroud:
|
||||
PlayerStatistics:
|
||||
FrozenActorLayer:
|
||||
PlaceBeacon:
|
||||
|
||||
|
||||
@@ -175,4 +175,4 @@ World:
|
||||
DebugPauseState:
|
||||
ConquestObjectivesPanel:
|
||||
ObjectivesPanel: CONQUEST_OBJECTIVES
|
||||
|
||||
RadarPings:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -47,4 +47,5 @@ Sounds:
|
||||
BuildPaletteClose: BUTTON1
|
||||
TabClick: SIDEBAR1
|
||||
ClickSound: BUTTON1
|
||||
ClickDisabledSound: ENDLIST1
|
||||
ClickDisabledSound: ENDLIST1
|
||||
Beacon: CHAT1
|
||||
@@ -51,4 +51,4 @@ Player:
|
||||
FrozenActorLayer:
|
||||
HarvesterAttackNotifier:
|
||||
PlayerStatistics:
|
||||
|
||||
PlaceBeacon:
|
||||
|
||||
@@ -126,4 +126,4 @@ World:
|
||||
PathFinder:
|
||||
ValidateOrder:
|
||||
DebugPauseState:
|
||||
|
||||
RadarPings:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -42,4 +42,5 @@ Sounds:
|
||||
BuildPaletteClose: bleep13
|
||||
TabClick: ramenu1
|
||||
ClickSound:
|
||||
ClickDisabledSound:
|
||||
ClickDisabledSound:
|
||||
Beacon: beepslct
|
||||
@@ -56,4 +56,5 @@ Player:
|
||||
FrozenActorLayer:
|
||||
BaseAttackNotifier:
|
||||
PlayerStatistics:
|
||||
PlaceBeacon:
|
||||
|
||||
|
||||
@@ -164,4 +164,4 @@ World:
|
||||
PathFinder:
|
||||
ValidateOrder:
|
||||
DebugPauseState:
|
||||
|
||||
RadarPings:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -39,4 +39,5 @@ Sounds:
|
||||
BuildPaletteClose:
|
||||
TabClick:
|
||||
ClickSound:clicky1
|
||||
ClickDisabledSound:wrong1
|
||||
ClickDisabledSound:wrong1
|
||||
Beacon: message1
|
||||
@@ -40,4 +40,4 @@ Player:
|
||||
Shroud:
|
||||
BaseAttackNotifier:
|
||||
PlayerStatistics:
|
||||
|
||||
PlaceBeacon:
|
||||
|
||||
@@ -96,4 +96,4 @@ World:
|
||||
ValidateOrder:
|
||||
DebugPauseState:
|
||||
ScreenShaker:
|
||||
|
||||
RadarPings:
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user