Merge pull request #6706 from pchote/mission-menu-phase-two
Improve the mission menu
@@ -79,6 +79,7 @@ namespace OpenRA
|
||||
void Render(Action a);
|
||||
}
|
||||
|
||||
public enum TextureScaleFilter { Nearest, Linear }
|
||||
public interface ITexture
|
||||
{
|
||||
void SetData(Bitmap bitmap);
|
||||
@@ -86,6 +87,7 @@ namespace OpenRA
|
||||
void SetData(byte[] colors, int width, int height);
|
||||
byte[] GetData();
|
||||
Size Size { get; }
|
||||
TextureScaleFilter ScaleFilter { get; set; }
|
||||
}
|
||||
|
||||
public interface IFrameBuffer
|
||||
|
||||
@@ -70,6 +70,7 @@ namespace OpenRA
|
||||
|
||||
public string Title;
|
||||
public string Type = "Conquest";
|
||||
public string PreviewVideo;
|
||||
public string Description;
|
||||
public string Author;
|
||||
public string Tileset;
|
||||
|
||||
@@ -18,6 +18,13 @@ namespace OpenRA.Widgets
|
||||
{
|
||||
public class VqaPlayerWidget : Widget
|
||||
{
|
||||
public Hotkey CancelKey = new Hotkey(Keycode.ESCAPE, Modifiers.None);
|
||||
public float AspectRatio = 1.2f;
|
||||
public bool DrawOverlay = true;
|
||||
|
||||
public bool Paused { get { return paused; } }
|
||||
public VqaReader Video { get { return video; } }
|
||||
|
||||
Sprite videoSprite, overlaySprite;
|
||||
VqaReader video = null;
|
||||
string cachedVideo;
|
||||
@@ -29,17 +36,14 @@ namespace OpenRA.Widgets
|
||||
|
||||
Action onComplete;
|
||||
|
||||
public bool Paused { get { return paused; } }
|
||||
public VqaReader Video { get { return video; } }
|
||||
|
||||
readonly World world;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public VqaPlayerWidget(World world)
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public bool DrawOverlay = true;
|
||||
public void Load(string filename)
|
||||
{
|
||||
if (filename == cachedVideo)
|
||||
@@ -58,25 +62,29 @@ namespace OpenRA.Widgets
|
||||
var size = Math.Max(video.Width, video.Height);
|
||||
var textureSize = Exts.NextPowerOf2(size);
|
||||
var videoSheet = new Sheet(new Size(textureSize, textureSize), false);
|
||||
|
||||
videoSheet.Texture.ScaleFilter = TextureScaleFilter.Linear;
|
||||
videoSheet.Texture.SetData(video.FrameData);
|
||||
videoSprite = new Sprite(videoSheet, new Rectangle(0, 0, video.Width, video.Height), TextureChannel.Alpha);
|
||||
|
||||
var scale = Math.Min(RenderBounds.Width / video.Width, RenderBounds.Height / video.Height);
|
||||
videoOrigin = new float2(RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * video.Height) / 2);
|
||||
videoSize = new float2(video.Width * scale, video.Height * scale);
|
||||
var scale = Math.Min(RenderBounds.Width / video.Width, RenderBounds.Height / (video.Height * AspectRatio));
|
||||
videoOrigin = new float2(RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * AspectRatio * video.Height) / 2);
|
||||
|
||||
// Round size to integer pixels. Round up to be consistent with the scale calcuation.
|
||||
videoSize = new float2((int)Math.Ceiling(video.Width * scale), (int)Math.Ceiling(video.Height * scale * AspectRatio));
|
||||
|
||||
if (!DrawOverlay)
|
||||
return;
|
||||
|
||||
overlay = new uint[2 * textureSize, 2 * textureSize];
|
||||
var scaledHeight = (int)videoSize.Y;
|
||||
overlay = new uint[Exts.NextPowerOf2(scaledHeight), 1];
|
||||
var black = (uint)255 << 24;
|
||||
for (var y = 0; y < video.Height; y++)
|
||||
for (var x = 0; x < video.Width; x++)
|
||||
overlay[2 * y, x] = black;
|
||||
for (var y = 0; y < scaledHeight; y += 2)
|
||||
overlay[y, 0] = black;
|
||||
|
||||
var overlaySheet = new Sheet(new Size(2 * textureSize, 2 * textureSize), false);
|
||||
var overlaySheet = new Sheet(new Size(1, Exts.NextPowerOf2(scaledHeight)), false);
|
||||
overlaySheet.Texture.SetData(overlay);
|
||||
overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, video.Width, 2 * video.Height), TextureChannel.Alpha);
|
||||
overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, scaledHeight), TextureChannel.Alpha);
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
@@ -84,7 +92,7 @@ namespace OpenRA.Widgets
|
||||
if (video == null)
|
||||
return;
|
||||
|
||||
if (!(stopped || paused))
|
||||
if (!stopped && !paused)
|
||||
{
|
||||
var nextFrame = (int)float2.Lerp(0, video.Frames, Sound.VideoSeekPosition * invLength);
|
||||
if (nextFrame > video.Frames)
|
||||
@@ -109,16 +117,16 @@ namespace OpenRA.Widgets
|
||||
|
||||
public override bool HandleKeyPress(KeyInput e)
|
||||
{
|
||||
if (e.Event == KeyInputEvent.Down)
|
||||
{
|
||||
if (e.Key == Keycode.ESCAPE)
|
||||
{
|
||||
Stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (Hotkey.FromKeyInput(e) != CancelKey || e.Event != KeyInputEvent.Down)
|
||||
return false;
|
||||
|
||||
return false;
|
||||
Stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool HandleMouseInput(MouseInput mi)
|
||||
{
|
||||
return RenderBounds.Contains(mi.Location);
|
||||
}
|
||||
|
||||
public void Play()
|
||||
|
||||
@@ -79,13 +79,18 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
missionsButton.OnClick = () =>
|
||||
{
|
||||
menuType = MenuType.None;
|
||||
Ui.OpenWindow("MISSIONBROWSER_PANEL", new WidgetArgs
|
||||
Game.OpenWindow("MISSIONBROWSER_PANEL", new WidgetArgs
|
||||
{
|
||||
{ "onExit", () => menuType = MenuType.Singleplayer },
|
||||
{ "onStart", RemoveShellmapUI }
|
||||
});
|
||||
};
|
||||
missionsButton.Disabled = !Game.modData.Manifest.Missions.Any();
|
||||
|
||||
var hasCampaign = Game.modData.Manifest.Missions.Any();
|
||||
var hasMissions = Game.modData.MapCache
|
||||
.Any(p => p.Status == MapStatus.Available && p.Map.Type == "Mission" && !p.Map.Selectable);
|
||||
|
||||
missionsButton.Disabled = !hasCampaign && !hasMissions;
|
||||
|
||||
singleplayerMenu.Get<ButtonWidget>("SKIRMISH_BUTTON").OnClick = StartSkirmishGame;
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Widgets;
|
||||
@@ -24,35 +26,104 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
readonly ScrollPanelWidget descriptionPanel;
|
||||
readonly LabelWidget description;
|
||||
readonly SpriteFont descriptionFont;
|
||||
readonly ButtonWidget startVideoButton;
|
||||
readonly ButtonWidget stopVideoButton;
|
||||
readonly VqaPlayerWidget videoPlayer;
|
||||
|
||||
readonly ScrollPanelWidget missionList;
|
||||
readonly ScrollItemWidget headerTemplate;
|
||||
readonly ScrollItemWidget template;
|
||||
|
||||
MapPreview selectedMapPreview;
|
||||
|
||||
bool showVideoPlayer;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public MissionBrowserLogic(Widget widget, Action onStart, Action onExit)
|
||||
{
|
||||
this.onStart = onStart;
|
||||
|
||||
var missionList = widget.Get<ScrollPanelWidget>("MISSION_LIST");
|
||||
var template = widget.Get<ScrollItemWidget>("MISSION_TEMPLATE");
|
||||
missionList = widget.Get<ScrollPanelWidget>("MISSION_LIST");
|
||||
|
||||
headerTemplate = widget.Get<ScrollItemWidget>("HEADER");
|
||||
template = widget.Get<ScrollItemWidget>("TEMPLATE");
|
||||
|
||||
var title = widget.GetOrNull<LabelWidget>("MISSIONBROWSER_TITLE");
|
||||
if (title != null)
|
||||
title.GetText = () => showVideoPlayer ? selectedMapPreview.Title : title.Text;
|
||||
|
||||
widget.Get("MISSION_INFO").IsVisible = () => selectedMapPreview != null;
|
||||
|
||||
var previewWidget = widget.Get<MapPreviewWidget>("MISSION_PREVIEW");
|
||||
previewWidget.Preview = () => selectedMapPreview;
|
||||
previewWidget.IsVisible = () => !showVideoPlayer;
|
||||
|
||||
videoPlayer = widget.Get<VqaPlayerWidget>("MISSION_VIDEO");
|
||||
widget.Get("MISSION_BIN").IsVisible = () => showVideoPlayer;
|
||||
|
||||
descriptionPanel = widget.Get<ScrollPanelWidget>("MISSION_DESCRIPTION_PANEL");
|
||||
description = widget.Get<LabelWidget>("MISSION_DESCRIPTION");
|
||||
|
||||
description = descriptionPanel.Get<LabelWidget>("MISSION_DESCRIPTION");
|
||||
descriptionFont = Game.Renderer.Fonts[description.Font];
|
||||
|
||||
var yaml = new MiniYaml(null, Game.modData.Manifest.Missions.Select(MiniYaml.FromFile).Aggregate(MiniYaml.MergeLiberal)).ToDictionary();
|
||||
startVideoButton = widget.Get<ButtonWidget>("START_VIDEO_BUTTON");
|
||||
stopVideoButton = widget.Get<ButtonWidget>("STOP_VIDEO_BUTTON");
|
||||
stopVideoButton.IsVisible = () => showVideoPlayer;
|
||||
stopVideoButton.OnClick = StopVideo;
|
||||
|
||||
var missionMapPaths = yaml["Missions"].Nodes.Select(n => Platform.ResolvePath(n.Key));
|
||||
var allMaps = new List<Map>();
|
||||
missionList.RemoveChildren();
|
||||
|
||||
var maps = Game.modData.MapCache
|
||||
.Where(p => p.Status == MapStatus.Available && missionMapPaths.Contains(Path.GetFullPath(p.Map.Path)))
|
||||
// Add a group for each campaign
|
||||
if (Game.modData.Manifest.Missions.Any())
|
||||
{
|
||||
var yaml = Game.modData.Manifest.Missions.Select(MiniYaml.FromFile).Aggregate(MiniYaml.MergeLiberal);
|
||||
|
||||
foreach (var kv in yaml)
|
||||
{
|
||||
var missionMapPaths = kv.Value.Nodes.Select(n => Path.GetFullPath(n.Key));
|
||||
|
||||
var maps = Game.modData.MapCache
|
||||
.Where(p => p.Status == MapStatus.Available && missionMapPaths.Contains(Path.GetFullPath(p.Map.Path)))
|
||||
.Select(p => p.Map);
|
||||
|
||||
CreateMissionGroup(kv.Key, maps);
|
||||
allMaps.AddRange(maps);
|
||||
}
|
||||
}
|
||||
|
||||
// Add an additional group for loose missions
|
||||
// Loose missions must define Type: Mission and Selectable: false.
|
||||
var looseMissions = Game.modData.MapCache
|
||||
.Where(p => p.Status == MapStatus.Available && p.Map.Type == "Mission" && !p.Map.Selectable && !allMaps.Contains(p.Map))
|
||||
.Select(p => p.Map);
|
||||
|
||||
missionList.RemoveChildren();
|
||||
if (looseMissions.Any())
|
||||
{
|
||||
CreateMissionGroup("Missions", looseMissions);
|
||||
allMaps.AddRange(looseMissions);
|
||||
}
|
||||
|
||||
if (allMaps.Any())
|
||||
SelectMap(allMaps.First());
|
||||
|
||||
widget.Get<ButtonWidget>("STARTGAME_BUTTON").OnClick = StartMission;
|
||||
|
||||
widget.Get<ButtonWidget>("BACK_BUTTON").OnClick = () =>
|
||||
{
|
||||
StopVideo();
|
||||
Game.Disconnect();
|
||||
Ui.CloseWindow();
|
||||
onExit();
|
||||
};
|
||||
}
|
||||
|
||||
void CreateMissionGroup(string title, IEnumerable<Map> maps)
|
||||
{
|
||||
var header = ScrollItemWidget.Setup(headerTemplate, () => true, () => {});
|
||||
header.Get<LabelWidget>("LABEL").GetText = () => title;
|
||||
missionList.AddChild(header);
|
||||
|
||||
foreach (var m in maps)
|
||||
{
|
||||
var map = m;
|
||||
@@ -65,23 +136,32 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
item.Get<LabelWidget>("TITLE").GetText = () => map.Title;
|
||||
missionList.AddChild(item);
|
||||
}
|
||||
|
||||
if (maps.Any())
|
||||
SelectMap(maps.First());
|
||||
|
||||
widget.Get<ButtonWidget>("STARTGAME_BUTTON").OnClick = StartMission;
|
||||
|
||||
widget.Get<ButtonWidget>("BACK_BUTTON").OnClick = () =>
|
||||
{
|
||||
Game.Disconnect();
|
||||
Ui.CloseWindow();
|
||||
onExit();
|
||||
};
|
||||
}
|
||||
|
||||
float cachedSoundVolume;
|
||||
float cachedMusicVolume;
|
||||
void SelectMap(Map map)
|
||||
{
|
||||
StopVideo();
|
||||
|
||||
selectedMapPreview = Game.modData.MapCache[map.Uid];
|
||||
var video = selectedMapPreview.Map.PreviewVideo;
|
||||
var videoVisible = video != null;
|
||||
var videoDisabled = !(videoVisible && GlobalFileSystem.Exists(video));
|
||||
|
||||
startVideoButton.IsVisible = () => videoVisible && !showVideoPlayer;
|
||||
startVideoButton.IsDisabled = () => videoDisabled;
|
||||
startVideoButton.OnClick = () =>
|
||||
{
|
||||
showVideoPlayer = true;
|
||||
videoPlayer.Load(video);
|
||||
videoPlayer.PlayThen(StopVideo);
|
||||
|
||||
// Mute other distracting sounds
|
||||
cachedSoundVolume = Sound.SoundVolume;
|
||||
cachedMusicVolume = Sound.MusicVolume;
|
||||
Sound.SoundVolume = Sound.MusicVolume = 0;
|
||||
};
|
||||
|
||||
var text = map.Description != null ? map.Description.Replace("\\n", "\n") : "";
|
||||
text = WidgetUtils.WrapText(text, description.Bounds.Width, descriptionFont);
|
||||
@@ -91,8 +171,22 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
descriptionPanel.Layout.AdjustChildren();
|
||||
}
|
||||
|
||||
void StopVideo()
|
||||
{
|
||||
if (!showVideoPlayer)
|
||||
return;
|
||||
|
||||
Sound.SoundVolume = cachedSoundVolume;
|
||||
Sound.MusicVolume = cachedMusicVolume;
|
||||
|
||||
videoPlayer.Stop();
|
||||
showVideoPlayer = false;
|
||||
}
|
||||
|
||||
void StartMission()
|
||||
{
|
||||
StopVideo();
|
||||
|
||||
OrderManager om = null;
|
||||
|
||||
Action lobbyReady = null;
|
||||
|
||||
@@ -80,6 +80,7 @@ namespace OpenRA.Renderer.Null
|
||||
|
||||
public class NullTexture : ITexture
|
||||
{
|
||||
public TextureScaleFilter ScaleFilter { get { return TextureScaleFilter.Nearest; } set { } }
|
||||
public void SetData(Bitmap bitmap) { }
|
||||
public void SetData(uint[,] colors) { }
|
||||
public void SetData(byte[] colors, int width, int height) { }
|
||||
|
||||
@@ -19,11 +19,29 @@ namespace OpenRA.Renderer.Sdl2
|
||||
public class Texture : ITexture
|
||||
{
|
||||
int texture;
|
||||
TextureScaleFilter scaleFilter;
|
||||
Size size;
|
||||
|
||||
public int ID { get { return texture; } }
|
||||
|
||||
Size size;
|
||||
public Size Size { get { return size; } }
|
||||
|
||||
public TextureScaleFilter ScaleFilter
|
||||
{
|
||||
get
|
||||
{
|
||||
return scaleFilter;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (scaleFilter == value)
|
||||
return;
|
||||
|
||||
scaleFilter = value;
|
||||
PrepareTexture();
|
||||
}
|
||||
}
|
||||
|
||||
public Texture()
|
||||
{
|
||||
GL.GenTextures(1, out texture);
|
||||
@@ -45,9 +63,11 @@ namespace OpenRA.Renderer.Sdl2
|
||||
ErrorHandler.CheckGlError();
|
||||
GL.BindTexture(TextureTarget.Texture2D, texture);
|
||||
ErrorHandler.CheckGlError();
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Nearest);
|
||||
|
||||
var filter = scaleFilter == TextureScaleFilter.Linear ? (int)TextureMinFilter.Linear : (int)TextureMinFilter.Nearest;
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, filter);
|
||||
ErrorHandler.CheckGlError();
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, filter);
|
||||
ErrorHandler.CheckGlError();
|
||||
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.ClampToEdge);
|
||||
|
||||
BIN
artsrc/cnc/campaign/gdi01.psd
Normal file
BIN
artsrc/cnc/campaign/gdi02.psd
Normal file
BIN
artsrc/cnc/campaign/gdi03.psd
Normal file
BIN
artsrc/cnc/campaign/gdi04.psd
Normal file
BIN
artsrc/cnc/campaign/nod01.psd
Normal file
BIN
artsrc/cnc/campaign/nod03.psd
Normal file
BIN
artsrc/ra/campaign/generic-allies.psd
Normal file
BIN
artsrc/ra/campaign/generic-soviets.psd
Normal file
@@ -6,27 +6,26 @@ Container@MAP_PANEL:
|
||||
Background@PREVIEW_BG:
|
||||
X: (PARENT_RIGHT - WIDTH) / 2
|
||||
Y: 15
|
||||
Width: 324
|
||||
Height: 160
|
||||
Background: panel-gray
|
||||
Width: 362
|
||||
Height: 202
|
||||
Background: panel-black
|
||||
Children:
|
||||
MapPreview@MAP_PREVIEW:
|
||||
Width: 320
|
||||
Height: 156
|
||||
X: 2
|
||||
Y: 2
|
||||
Width: 360
|
||||
Height: 200
|
||||
X: 1
|
||||
Y: 1
|
||||
IgnoreMouseOver: True
|
||||
IgnoreMouseInput: True
|
||||
ShowSpawnPoints: False
|
||||
ScrollPanel@MAP_DESCRIPTION_PANEL:
|
||||
X: 15
|
||||
Y: 190
|
||||
Y: 228
|
||||
Width: 482
|
||||
Height: 170
|
||||
Height: 132
|
||||
Children:
|
||||
Label@MAP_DESCRIPTION:
|
||||
X: 5
|
||||
Y: 195
|
||||
Width: 452
|
||||
Height: 160
|
||||
X: 4
|
||||
Y: 1
|
||||
Width: PARENT_RIGHT - 32
|
||||
|
||||
|
||||
@@ -2,31 +2,42 @@ Container@MISSIONBROWSER_PANEL:
|
||||
Logic: MissionBrowserLogic
|
||||
X: (WINDOW_RIGHT - WIDTH)/2
|
||||
Y: (WINDOW_BOTTOM - HEIGHT)/2
|
||||
Width: 629
|
||||
Height: 399
|
||||
Width: 642
|
||||
Height: 377
|
||||
Children:
|
||||
Label@MISSIONBROWSER_LABEL_TITLE:
|
||||
Label@MISSIONBROWSER_TITLE:
|
||||
Y: 0-25
|
||||
Width: PARENT_RIGHT
|
||||
Text: Missions
|
||||
Align: Center
|
||||
Contrast: true
|
||||
Font: BigBold
|
||||
Background@BG:
|
||||
Width: 629
|
||||
Height: 360
|
||||
Width: 642
|
||||
Height: 377
|
||||
Background: panel-black
|
||||
Children:
|
||||
ScrollPanel@MISSION_LIST:
|
||||
X: 15
|
||||
Y: 15
|
||||
Width: 260
|
||||
Height: 330
|
||||
Width: 239
|
||||
Height: 347
|
||||
Children:
|
||||
ScrollItem@MISSION_TEMPLATE:
|
||||
ScrollItem@HEADER:
|
||||
Width: PARENT_RIGHT-27
|
||||
Height: 13
|
||||
X: 2
|
||||
Visible: false
|
||||
Children:
|
||||
Label@LABEL:
|
||||
Font: TinyBold
|
||||
Width: PARENT_RIGHT
|
||||
Height: 10
|
||||
Align: Center
|
||||
ScrollItem@TEMPLATE:
|
||||
Width: PARENT_RIGHT-27
|
||||
Height: 25
|
||||
X: 2
|
||||
Y: 0
|
||||
Visible: False
|
||||
Children:
|
||||
Label@TITLE:
|
||||
@@ -34,50 +45,67 @@ Container@MISSIONBROWSER_PANEL:
|
||||
Width: PARENT_RIGHT-20
|
||||
Height: 25
|
||||
Container@MISSION_INFO:
|
||||
X: 290
|
||||
X: 265
|
||||
Y: 15
|
||||
Width: 324
|
||||
Height: 334
|
||||
Width: 362
|
||||
Height: 349
|
||||
Children:
|
||||
Background@MISSION_BG:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 324
|
||||
Height: 160
|
||||
Background: panel-gray
|
||||
Width: PARENT_RIGHT
|
||||
Height: 202
|
||||
Background: panel-black
|
||||
Children:
|
||||
MapPreview@MISSION_PREVIEW:
|
||||
X: 2
|
||||
Y: 2
|
||||
Width: PARENT_RIGHT-4
|
||||
Height: PARENT_BOTTOM-4
|
||||
X: 1
|
||||
Y: 1
|
||||
Width: PARENT_RIGHT-2
|
||||
Height: PARENT_BOTTOM-2
|
||||
IgnoreMouseOver: True
|
||||
IgnoreMouseInput: True
|
||||
ShowSpawnPoints: False
|
||||
ScrollPanel@MISSION_DESCRIPTION_PANEL:
|
||||
X: 0
|
||||
Y: 171
|
||||
Width: 324
|
||||
Height: 159
|
||||
Y: 213
|
||||
Width: PARENT_RIGHT
|
||||
Height: 134
|
||||
Children:
|
||||
Label@MISSION_DESCRIPTION:
|
||||
X: 5
|
||||
Y: 5
|
||||
Width: 290
|
||||
X: 4
|
||||
Y: 1
|
||||
Width: PARENT_RIGHT - 32
|
||||
VAlign: Top
|
||||
Font: Small
|
||||
Button@BACK_BUTTON:
|
||||
X: 0
|
||||
Y: 359
|
||||
Y: 376
|
||||
Width: 140
|
||||
Height: 35
|
||||
Text: Back
|
||||
Font: Bold
|
||||
Key: escape
|
||||
Button@STARTGAME_BUTTON:
|
||||
X: PARENT_RIGHT - 140
|
||||
Y: 359
|
||||
Button@START_VIDEO_BUTTON:
|
||||
X: PARENT_RIGHT - 290
|
||||
Y: 376
|
||||
Width: 140
|
||||
Height: 35
|
||||
Text: Start Game
|
||||
Text: View Briefing
|
||||
Font: Bold
|
||||
|
||||
Button@STOP_VIDEO_BUTTON:
|
||||
X: PARENT_RIGHT - 290
|
||||
Y: 376
|
||||
Width: 140
|
||||
Height: 35
|
||||
Text: Stop Briefing
|
||||
Font: Bold
|
||||
Button@STARTGAME_BUTTON:
|
||||
X: PARENT_RIGHT - 140
|
||||
Y: 376
|
||||
Width: 140
|
||||
Height: 35
|
||||
Text: Play
|
||||
Font: Bold
|
||||
Container@MISSION_BIN:
|
||||
Children:
|
||||
VqaPlayer@MISSION_VIDEO:
|
||||
X: 1
|
||||
Y: 1
|
||||
Width: 640
|
||||
Height: 375
|
||||
|
||||
@@ -39,7 +39,7 @@ CheckForBase = function()
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
Media.PlayMovieFullscreen("gdi1.vqa", function() Media.PlayMovieFullscreen("landing.vqa") end)
|
||||
Media.PlayMovieFullscreen("landing.vqa")
|
||||
|
||||
player = Player.GetPlayer("GDI")
|
||||
enemy = Player.GetPlayer("Nod")
|
||||
|
||||
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 50 KiB |
@@ -8,6 +8,8 @@ Title: Storm the Beachhead
|
||||
|
||||
Description: Use the units provided to protect the Mobile Construction Vehicle. (MCV)\n\nYou should then deploy the MCV by double clicking on it.\n\nThen you can begin to build up a base. Start with a Power Plant.\n\nFinally, search out and destroy all enemy Nod units in the surrounding area.
|
||||
|
||||
PreviewVideo: gdi1.vqa
|
||||
|
||||
Author: Westwood Studios
|
||||
|
||||
Tileset: TEMPERAT
|
||||
|
||||
@@ -65,8 +65,6 @@ WorldLoaded = function()
|
||||
Trigger.OnKilled(NodRefinery, function() player.MarkFailedObjective(gdiObjective2) end)
|
||||
|
||||
Trigger.OnAllKilled(nodInBaseTeam, BridgeheadSecured)
|
||||
|
||||
Media.PlayMovieFullscreen("gdi2.vqa")
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
|
||||
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 50 KiB |
@@ -8,6 +8,8 @@ Title: Knock out the Refinery
|
||||
|
||||
Description: Defend your position, deploy the MCV, then build a sizable force to search out and destroy the Nod base in the area.\n\nAll Nod units and structures must be either destroyed or captured to complete objective.
|
||||
|
||||
PreviewVideo: gdi2.vqa
|
||||
|
||||
Author: Westwood Studios
|
||||
|
||||
Tileset: TEMPERAT
|
||||
|
||||
@@ -24,7 +24,7 @@ WorldLoaded = function()
|
||||
player = OpenRA.GetPlayer("GDI")
|
||||
enemy = OpenRA.GetPlayer("Nod")
|
||||
|
||||
Media.PlayMovieFullscreen("gdi3.vqa", function() Media.PlayMovieFullscreen("samdie.vqa") end)
|
||||
Media.PlayMovieFullscreen("samdie.vqa")
|
||||
|
||||
samSites = Team.New({ Sam1, Sam2, Sam3, Sam4 })
|
||||
Team.AddEventHandler(samSites.OnAllKilled, function() Actor.Create("PowerProxy.AirSupport", { Owner = player }) end)
|
||||
|
||||
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 50 KiB |
@@ -8,6 +8,8 @@ Title: Destroy The SAM Sites
|
||||
|
||||
Description: Build up forces to destroy Nod base.\n\nOnce all Nod SAM sites are neutralized then air support will be provided to combat obstacles such as turrets.\n\nDestroy all units and structures to complete the mission objective.
|
||||
|
||||
PreviewVideo: gdi3.vqa
|
||||
|
||||
Author: Westwood Studios
|
||||
|
||||
Tileset: TEMPERAT
|
||||
|
||||
@@ -111,7 +111,7 @@ SetupWorld = function()
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("gdi4b.vqa", function() Media.PlayMovieFullscreen("nitejump.vqa") end) end)
|
||||
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("nitejump.vqa") end)
|
||||
|
||||
player = OpenRA.GetPlayer("GDI")
|
||||
nod = OpenRA.GetPlayer("Nod")
|
||||
|
||||
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 50 KiB |
@@ -8,6 +8,8 @@ Title: Get the Rods back (a)
|
||||
|
||||
Description: Nod has captured classified GDI property.\n\nYou must find and retrieve the stolen equipment.\n\nIt is being transported in a shipping crate.\n\nUse the new APC to strategically transport infantry through Nod forces.
|
||||
|
||||
PreviewVideo: gdi4b.vqa
|
||||
|
||||
Author: Westwood Studios
|
||||
|
||||
Tileset: TEMPERAT
|
||||
|
||||
@@ -151,7 +151,7 @@ SetupWorld = function()
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("gdi4b.vqa", function() Media.PlayMovieFullscreen("nitejump.vqa") end) end)
|
||||
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("nitejump.vqa") end)
|
||||
|
||||
player = OpenRA.GetPlayer("GDI")
|
||||
nod = OpenRA.GetPlayer("Nod")
|
||||
|
||||
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 50 KiB |
@@ -10,6 +10,8 @@ Author: Westwood Studios
|
||||
|
||||
Description: Nod has captured classified GDI property.\n\nYou must find and retrieve the stolen equipment.\n\nIt is being transported in a shipping crate.\n\nUse the new APC to strategically transport infantry through Nod forces.
|
||||
|
||||
PreviewVideo: gdi4b.vqa
|
||||
|
||||
Tileset: TEMPERAT
|
||||
|
||||
MapSize: 64,64
|
||||
|
||||
@@ -122,7 +122,7 @@ WorldLoaded = function()
|
||||
|
||||
Camera.Position = Actor141.CenterPosition
|
||||
|
||||
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("gdi4a.vqa", function() Media.PlayMovieFullscreen("nodsweep.vqa") end) end)
|
||||
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("nodsweep.vqa") end)
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
|
||||
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 50 KiB |
@@ -10,6 +10,8 @@ Author: Westwood Studios
|
||||
|
||||
Description: Nod is moving to capture and hold a civilian town.\n\nYour mission is to reach the town first and hold off invading Nod units until GDI reinforcements can arrive.\n\nAll invading Nod units must be destroyed.
|
||||
|
||||
PreviewVideo: gdi4a.vqa
|
||||
|
||||
Tileset: TEMPERAT
|
||||
|
||||
MapSize: 64,64
|
||||
|
||||
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 43 KiB |
@@ -8,6 +8,8 @@ Title: Nikoomba's Demise
|
||||
|
||||
Description: In order for the Brotherhood to gain a foothold, we must begin by eliminating certain elements.\n\nNikoomba, the nearby village's leader, is one such element.\n\nHis views and ours do not coincide.\n\nHe and his whole group must be eliminated.
|
||||
|
||||
PreviewVideo: nod1.vqa
|
||||
|
||||
Author: Westwood Studios
|
||||
|
||||
Tileset: DESERT
|
||||
|
||||
@@ -56,8 +56,6 @@ WorldLoaded = function()
|
||||
|
||||
Trigger.AfterDelay(Utils.Seconds(30), SendFirstInfantryReinforcements)
|
||||
Trigger.AfterDelay(Utils.Seconds(60), SendSecondInfantryReinforcements)
|
||||
|
||||
Media.PlayMovieFullscreen("nod1pre.vqa", function() Media.PlayMovieFullscreen("nod1.vqa") end)
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
|
||||
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 43 KiB |
@@ -8,6 +8,8 @@ Title: Sudanese Prison Break (a)
|
||||
|
||||
Description: GDI has established a prison camp, where they are detaining some of the local political leaders.\n\nKane wishes to liberate these victims.\n\nDestroy the GDI forces and capture the prison, do not destroy it.
|
||||
|
||||
PreviewVideo: nod3.vqa
|
||||
|
||||
Author: Westwood Studios
|
||||
|
||||
Tileset: DESERT
|
||||
|
||||
@@ -61,8 +61,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(Utils.Seconds(20), function() SendAttackWave(FirstAttackWave, AttackWaveSpawnA.Location) end)
|
||||
Trigger.AfterDelay(Utils.Seconds(50), function() SendAttackWave(SecondThirdAttackWave, AttackWaveSpawnB.Location) end)
|
||||
Trigger.AfterDelay(Utils.Seconds(100), function() SendAttackWave(SecondThirdAttackWave, AttackWaveSpawnC.Location) end)
|
||||
|
||||
Media.PlayMovieFullscreen("nod3.vqa")
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
|
||||
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 43 KiB |
@@ -8,6 +8,8 @@ Title: Sudanese Prison Break (b)
|
||||
|
||||
Description: GDI has established a prison camp, where they are detaining some of the local political leaders.\n\nKane wishes to liberate these victims.\n\nDestroy the GDI forces and capture the prison, do not destroy it.
|
||||
|
||||
PreviewVideo: nod3.vqa
|
||||
|
||||
Author: Westwood Studios
|
||||
|
||||
Tileset: DESERT
|
||||
|
||||
@@ -75,7 +75,6 @@ WorldLoaded = function()
|
||||
Trigger.AfterDelay(Utils.Seconds(80), function() SendAttackWave(SecondAttackWaveUnits, SecondAttackWave) end)
|
||||
Trigger.AfterDelay(Utils.Seconds(140), function() SendAttackWave(ThirdAttackWaveUnits, FirstAttackWave) end)
|
||||
|
||||
Media.PlayMovieFullscreen("nod3.vqa")
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
Missions:
|
||||
GDI Campaign:
|
||||
./mods/cnc/maps/gdi01
|
||||
./mods/cnc/maps/gdi02
|
||||
./mods/cnc/maps/gdi03
|
||||
./mods/cnc/maps/gdi04a
|
||||
./mods/cnc/maps/gdi04b
|
||||
./mods/cnc/maps/gdi04c
|
||||
|
||||
Nod Campaign:
|
||||
./mods/cnc/maps/nod01
|
||||
./mods/cnc/maps/nod03a
|
||||
./mods/cnc/maps/nod03b
|
||||
|
||||
@@ -170,6 +170,9 @@ ChromeMetrics:
|
||||
./mods/cnc/metrics.yaml
|
||||
|
||||
Fonts:
|
||||
Small:
|
||||
Font:FreeSans.ttf
|
||||
Size:12
|
||||
Regular:
|
||||
Font:./FreeSans.ttf
|
||||
Size:14
|
||||
|
||||
@@ -166,6 +166,9 @@ Fonts:
|
||||
BigBold:
|
||||
Font:./FreeSansBold.ttf
|
||||
Size:24
|
||||
Small:
|
||||
Font:FreeSans.ttf
|
||||
Size:12
|
||||
Tiny:
|
||||
Font:./FreeSans.ttf
|
||||
Size:10
|
||||
|
||||
@@ -6,27 +6,27 @@ Container@MAP_PANEL:
|
||||
Background@PREVIEW_BG:
|
||||
X: (PARENT_RIGHT - WIDTH) / 2
|
||||
Y: 20
|
||||
Width: 324
|
||||
Height: 160
|
||||
Background: panel-gray
|
||||
Width: 362
|
||||
Height: 202
|
||||
Background: dialog3
|
||||
Children:
|
||||
MapPreview@MAP_PREVIEW:
|
||||
Width: 320
|
||||
Height: 156
|
||||
X: 2
|
||||
Y: 2
|
||||
X: 1
|
||||
Y: 1
|
||||
Width: PARENT_RIGHT-2
|
||||
Height: PARENT_BOTTOM-2
|
||||
IgnoreMouseOver: True
|
||||
IgnoreMouseInput: True
|
||||
ShowSpawnPoints: False
|
||||
ScrollPanel@MAP_DESCRIPTION_PANEL:
|
||||
X: 20
|
||||
Y: 195
|
||||
Width: 482
|
||||
Height: 175
|
||||
Y: 232
|
||||
Width: PARENT_RIGHT - 40
|
||||
Height: 138
|
||||
Children:
|
||||
Label@MAP_DESCRIPTION:
|
||||
X: 5
|
||||
Y: 180
|
||||
Width: 452
|
||||
Height: 145
|
||||
X: 4
|
||||
Y: 1
|
||||
Width: PARENT_RIGHT - 32
|
||||
|
||||
|
||||
|
||||
@@ -2,11 +2,10 @@ Background@MISSIONBROWSER_PANEL:
|
||||
Logic: MissionBrowserLogic
|
||||
X: (WINDOW_RIGHT - WIDTH)/2
|
||||
Y: (WINDOW_BOTTOM - HEIGHT)/2
|
||||
Width: 634
|
||||
Height: 440
|
||||
Width: 682
|
||||
Height: 487
|
||||
Children:
|
||||
Label@MISSIONBROWSER_LABEL_TITLE:
|
||||
X: 0
|
||||
Label@MISSIONBROWSER_TITLE:
|
||||
Y: 20
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
@@ -16,57 +15,80 @@ Background@MISSIONBROWSER_PANEL:
|
||||
ScrollPanel@MISSION_LIST:
|
||||
X: 20
|
||||
Y: 50
|
||||
Width: 260
|
||||
Height: 330
|
||||
Width: 270
|
||||
Height: 377
|
||||
Children:
|
||||
ScrollItem@MISSION_TEMPLATE:
|
||||
ScrollItem@HEADER:
|
||||
BaseName: scrollheader
|
||||
Width: PARENT_RIGHT-27
|
||||
Height: 13
|
||||
X: 2
|
||||
Visible: false
|
||||
Children:
|
||||
Label@LABEL:
|
||||
Font: TinyBold
|
||||
Width: PARENT_RIGHT
|
||||
Height: 10
|
||||
Align: Center
|
||||
ScrollItem@TEMPLATE:
|
||||
Width: PARENT_RIGHT-27
|
||||
Height: 25
|
||||
X: 2
|
||||
Y: 0
|
||||
Children:
|
||||
Label@TITLE:
|
||||
X: 10
|
||||
Width: PARENT_RIGHT-20
|
||||
Height: 25
|
||||
Container@MISSION_INFO:
|
||||
X: 290
|
||||
X: 300
|
||||
Y: 50
|
||||
Width: 324
|
||||
Height: 330
|
||||
Width: 362
|
||||
Height: 363
|
||||
Children:
|
||||
Background@MISSION_BG:
|
||||
X: 0
|
||||
Y: 0
|
||||
Width: 324
|
||||
Height: 160
|
||||
Width: PARENT_RIGHT
|
||||
Height: 202
|
||||
Background: dialog3
|
||||
Children:
|
||||
MapPreview@MISSION_PREVIEW:
|
||||
X: 2
|
||||
Y: 2
|
||||
Width: PARENT_RIGHT-4
|
||||
Height: PARENT_BOTTOM-4
|
||||
X: 1
|
||||
Y: 1
|
||||
Width: PARENT_RIGHT-2
|
||||
Height: PARENT_BOTTOM-2
|
||||
IgnoreMouseOver: True
|
||||
IgnoreMouseInput: True
|
||||
ShowSpawnPoints: False
|
||||
ScrollPanel@MISSION_DESCRIPTION_PANEL:
|
||||
X: 0
|
||||
Y: 170
|
||||
Width: 324
|
||||
Height: 160
|
||||
Y: 212
|
||||
Width: PARENT_RIGHT
|
||||
Height: 165
|
||||
Children:
|
||||
Label@MISSION_DESCRIPTION:
|
||||
X: 5
|
||||
Y: 5
|
||||
Width: 290
|
||||
X: 4
|
||||
Y: 1
|
||||
Width: PARENT_RIGHT - 32
|
||||
VAlign: Top
|
||||
Font: Small
|
||||
Button@START_VIDEO_BUTTON:
|
||||
X: 20
|
||||
Y: PARENT_BOTTOM - 45
|
||||
Width: 120
|
||||
Height: 25
|
||||
Text: Play Briefing
|
||||
Font: Bold
|
||||
Button@STOP_VIDEO_BUTTON:
|
||||
X: 20
|
||||
Y: PARENT_BOTTOM - 45
|
||||
Width: 120
|
||||
Height: 25
|
||||
Text: Stop Briefing
|
||||
Font: Bold
|
||||
Button@STARTGAME_BUTTON:
|
||||
X: PARENT_RIGHT - 140 - 130
|
||||
Y: PARENT_BOTTOM - 45
|
||||
Width: 120
|
||||
Height: 25
|
||||
Text: Start Game
|
||||
Text: Play
|
||||
Font: Bold
|
||||
Button@BACK_BUTTON:
|
||||
X: PARENT_RIGHT - 140
|
||||
@@ -76,4 +98,15 @@ Background@MISSIONBROWSER_PANEL:
|
||||
Text: Back
|
||||
Font: Bold
|
||||
Key: escape
|
||||
|
||||
Background@MISSION_BIN:
|
||||
X: 20
|
||||
Y: 50
|
||||
Width: 642
|
||||
Height: 377
|
||||
Background: dialog3
|
||||
Children:
|
||||
VqaPlayer@MISSION_VIDEO:
|
||||
X: 1
|
||||
Y: 1
|
||||
Width: 640
|
||||
Height: 375
|
||||
|
||||
@@ -201,5 +201,5 @@ WorldLoaded = function()
|
||||
|
||||
Camera.Position = InsertionLZ.CenterPosition
|
||||
|
||||
Media.PlayMovieFullscreen("ally1.vqa", function() Media.PlayMovieFullscreen("landing.vqa") end)
|
||||
Media.PlayMovieFullscreen("landing.vqa")
|
||||
end
|
||||
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 28 KiB |
@@ -8,6 +8,8 @@ Title: Allies 01: In the thick of it
|
||||
|
||||
Description: Rescue Einstein from the Headquarters inside this Soviet complex.\n\nOnce found, evacuate him via the helicopter at the signal flare.\n\nEinstein and Tanya must be kept alive at all costs.\n\nBeware the Soviet's Tesla Coils.\n\nDirect Tanya to destroy the westmost power plants to take them off-line.
|
||||
|
||||
PreviewVideo: ally1.vqa
|
||||
|
||||
Author: Westwood Studios
|
||||
|
||||
Tileset: SNOW
|
||||
|
||||
@@ -123,7 +123,7 @@ WorldLoaded = function()
|
||||
|
||||
Camera.Position = ReinforcementsEntryPoint.CenterPosition
|
||||
|
||||
Media.PlayMovieFullscreen("ally2.vqa", function() Media.PlayMovieFullscreen("mcv.vqa") end)
|
||||
Media.PlayMovieFullscreen("mcv.vqa")
|
||||
|
||||
ConvoyTimer(Utils.Seconds(3), "TenMinutesRemaining")
|
||||
ConvoyTimer(Utils.Minutes(5), "WarningFiveMinutesRemaining")
|
||||
|
||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
@@ -8,6 +8,8 @@ Title: Allies 02: Five to one
|
||||
|
||||
Description: A critical supply convoy is due through this area in 10 minutes, but Soviet forces have blocked the road in several places.\n\nUnless you can clear them out, those supplies will never make it to the front.\n\nThe convoy will come from the northwest, and time is short so work quickly.
|
||||
|
||||
PreviewVideo: ally2.vqa
|
||||
|
||||
Author: Westwood Studios
|
||||
|
||||
Tileset: SNOW
|
||||
|
||||
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 28 KiB |
@@ -1,4 +1,3 @@
|
||||
Missions:
|
||||
Allied Campaign:
|
||||
./mods/ra/maps/allies-01-classic
|
||||
./mods/ra/maps/allies-02-classic
|
||||
./mods/ra/maps/intervention
|
||||
|
||||
@@ -182,6 +182,9 @@ Fonts:
|
||||
BigBold:
|
||||
Font:./FreeSansBold.ttf
|
||||
Size:24
|
||||
Small:
|
||||
Font:FreeSans.ttf
|
||||
Size:12
|
||||
Tiny:
|
||||
Font:./FreeSans.ttf
|
||||
Size:10
|
||||
|
||||
@@ -207,6 +207,9 @@ Fonts:
|
||||
BigBold:
|
||||
Font:./FreeSansBold.ttf
|
||||
Size:24
|
||||
Small:
|
||||
Font:FreeSans.ttf
|
||||
Size:12
|
||||
Tiny:
|
||||
Font:./FreeSans.ttf
|
||||
Size:10
|
||||
|
||||