Merge pull request #6706 from pchote/mission-menu-phase-two

Improve the mission menu
This commit is contained in:
Matthias Mailänder
2014-10-11 14:07:51 +02:00
59 changed files with 374 additions and 155 deletions

View File

@@ -79,6 +79,7 @@ namespace OpenRA
void Render(Action a); void Render(Action a);
} }
public enum TextureScaleFilter { Nearest, Linear }
public interface ITexture public interface ITexture
{ {
void SetData(Bitmap bitmap); void SetData(Bitmap bitmap);
@@ -86,6 +87,7 @@ namespace OpenRA
void SetData(byte[] colors, int width, int height); void SetData(byte[] colors, int width, int height);
byte[] GetData(); byte[] GetData();
Size Size { get; } Size Size { get; }
TextureScaleFilter ScaleFilter { get; set; }
} }
public interface IFrameBuffer public interface IFrameBuffer

View File

@@ -70,6 +70,7 @@ namespace OpenRA
public string Title; public string Title;
public string Type = "Conquest"; public string Type = "Conquest";
public string PreviewVideo;
public string Description; public string Description;
public string Author; public string Author;
public string Tileset; public string Tileset;

View File

@@ -18,6 +18,13 @@ namespace OpenRA.Widgets
{ {
public class VqaPlayerWidget : Widget 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; Sprite videoSprite, overlaySprite;
VqaReader video = null; VqaReader video = null;
string cachedVideo; string cachedVideo;
@@ -29,17 +36,14 @@ namespace OpenRA.Widgets
Action onComplete; Action onComplete;
public bool Paused { get { return paused; } }
public VqaReader Video { get { return video; } }
readonly World world; readonly World world;
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public VqaPlayerWidget(World world) public VqaPlayerWidget(World world)
{ {
this.world = world; this.world = world;
} }
public bool DrawOverlay = true;
public void Load(string filename) public void Load(string filename)
{ {
if (filename == cachedVideo) if (filename == cachedVideo)
@@ -58,25 +62,29 @@ namespace OpenRA.Widgets
var size = Math.Max(video.Width, video.Height); var size = Math.Max(video.Width, video.Height);
var textureSize = Exts.NextPowerOf2(size); var textureSize = Exts.NextPowerOf2(size);
var videoSheet = new Sheet(new Size(textureSize, textureSize), false); var videoSheet = new Sheet(new Size(textureSize, textureSize), false);
videoSheet.Texture.ScaleFilter = TextureScaleFilter.Linear;
videoSheet.Texture.SetData(video.FrameData); videoSheet.Texture.SetData(video.FrameData);
videoSprite = new Sprite(videoSheet, new Rectangle(0, 0, video.Width, video.Height), TextureChannel.Alpha); 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); 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 * video.Height) / 2); videoOrigin = new float2(RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * AspectRatio * video.Height) / 2);
videoSize = new float2(video.Width * scale, video.Height * scale);
// 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) if (!DrawOverlay)
return; 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; var black = (uint)255 << 24;
for (var y = 0; y < video.Height; y++) for (var y = 0; y < scaledHeight; y += 2)
for (var x = 0; x < video.Width; x++) overlay[y, 0] = black;
overlay[2 * y, x] = 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); 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() public override void Draw()
@@ -84,7 +92,7 @@ namespace OpenRA.Widgets
if (video == null) if (video == null)
return; return;
if (!(stopped || paused)) if (!stopped && !paused)
{ {
var nextFrame = (int)float2.Lerp(0, video.Frames, Sound.VideoSeekPosition * invLength); var nextFrame = (int)float2.Lerp(0, video.Frames, Sound.VideoSeekPosition * invLength);
if (nextFrame > video.Frames) if (nextFrame > video.Frames)
@@ -109,16 +117,16 @@ namespace OpenRA.Widgets
public override bool HandleKeyPress(KeyInput e) public override bool HandleKeyPress(KeyInput e)
{ {
if (e.Event == KeyInputEvent.Down) if (Hotkey.FromKeyInput(e) != CancelKey || e.Event != KeyInputEvent.Down)
{ return false;
if (e.Key == Keycode.ESCAPE)
{
Stop();
return true;
}
}
return false; Stop();
return true;
}
public override bool HandleMouseInput(MouseInput mi)
{
return RenderBounds.Contains(mi.Location);
} }
public void Play() public void Play()

View File

@@ -79,13 +79,18 @@ namespace OpenRA.Mods.RA.Widgets.Logic
missionsButton.OnClick = () => missionsButton.OnClick = () =>
{ {
menuType = MenuType.None; menuType = MenuType.None;
Ui.OpenWindow("MISSIONBROWSER_PANEL", new WidgetArgs Game.OpenWindow("MISSIONBROWSER_PANEL", new WidgetArgs
{ {
{ "onExit", () => menuType = MenuType.Singleplayer }, { "onExit", () => menuType = MenuType.Singleplayer },
{ "onStart", RemoveShellmapUI } { "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; singleplayerMenu.Get<ButtonWidget>("SKIRMISH_BUTTON").OnClick = StartSkirmishGame;

View File

@@ -9,9 +9,11 @@
#endregion #endregion
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using OpenRA.FileSystem;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Network; using OpenRA.Network;
using OpenRA.Widgets; using OpenRA.Widgets;
@@ -24,35 +26,104 @@ namespace OpenRA.Mods.RA.Widgets.Logic
readonly ScrollPanelWidget descriptionPanel; readonly ScrollPanelWidget descriptionPanel;
readonly LabelWidget description; readonly LabelWidget description;
readonly SpriteFont descriptionFont; readonly SpriteFont descriptionFont;
readonly ButtonWidget startVideoButton;
readonly ButtonWidget stopVideoButton;
readonly VqaPlayerWidget videoPlayer;
readonly ScrollPanelWidget missionList;
readonly ScrollItemWidget headerTemplate;
readonly ScrollItemWidget template;
MapPreview selectedMapPreview; MapPreview selectedMapPreview;
bool showVideoPlayer;
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public MissionBrowserLogic(Widget widget, Action onStart, Action onExit) public MissionBrowserLogic(Widget widget, Action onStart, Action onExit)
{ {
this.onStart = onStart; this.onStart = onStart;
var missionList = widget.Get<ScrollPanelWidget>("MISSION_LIST"); missionList = widget.Get<ScrollPanelWidget>("MISSION_LIST");
var template = widget.Get<ScrollItemWidget>("MISSION_TEMPLATE");
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; widget.Get("MISSION_INFO").IsVisible = () => selectedMapPreview != null;
var previewWidget = widget.Get<MapPreviewWidget>("MISSION_PREVIEW"); var previewWidget = widget.Get<MapPreviewWidget>("MISSION_PREVIEW");
previewWidget.Preview = () => selectedMapPreview; 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"); 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]; 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 // Add a group for each campaign
.Where(p => p.Status == MapStatus.Available && missionMapPaths.Contains(Path.GetFullPath(p.Map.Path))) 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); .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) foreach (var m in maps)
{ {
var map = m; var map = m;
@@ -65,23 +136,32 @@ namespace OpenRA.Mods.RA.Widgets.Logic
item.Get<LabelWidget>("TITLE").GetText = () => map.Title; item.Get<LabelWidget>("TITLE").GetText = () => map.Title;
missionList.AddChild(item); 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) void SelectMap(Map map)
{ {
StopVideo();
selectedMapPreview = Game.modData.MapCache[map.Uid]; 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") : ""; var text = map.Description != null ? map.Description.Replace("\\n", "\n") : "";
text = WidgetUtils.WrapText(text, description.Bounds.Width, descriptionFont); text = WidgetUtils.WrapText(text, description.Bounds.Width, descriptionFont);
@@ -91,8 +171,22 @@ namespace OpenRA.Mods.RA.Widgets.Logic
descriptionPanel.Layout.AdjustChildren(); descriptionPanel.Layout.AdjustChildren();
} }
void StopVideo()
{
if (!showVideoPlayer)
return;
Sound.SoundVolume = cachedSoundVolume;
Sound.MusicVolume = cachedMusicVolume;
videoPlayer.Stop();
showVideoPlayer = false;
}
void StartMission() void StartMission()
{ {
StopVideo();
OrderManager om = null; OrderManager om = null;
Action lobbyReady = null; Action lobbyReady = null;

View File

@@ -80,6 +80,7 @@ namespace OpenRA.Renderer.Null
public class NullTexture : ITexture public class NullTexture : ITexture
{ {
public TextureScaleFilter ScaleFilter { get { return TextureScaleFilter.Nearest; } set { } }
public void SetData(Bitmap bitmap) { } public void SetData(Bitmap bitmap) { }
public void SetData(uint[,] colors) { } public void SetData(uint[,] colors) { }
public void SetData(byte[] colors, int width, int height) { } public void SetData(byte[] colors, int width, int height) { }

View File

@@ -19,11 +19,29 @@ namespace OpenRA.Renderer.Sdl2
public class Texture : ITexture public class Texture : ITexture
{ {
int texture; int texture;
TextureScaleFilter scaleFilter;
Size size;
public int ID { get { return texture; } } public int ID { get { return texture; } }
Size size;
public Size Size { get { return size; } } public Size Size { get { return size; } }
public TextureScaleFilter ScaleFilter
{
get
{
return scaleFilter;
}
set
{
if (scaleFilter == value)
return;
scaleFilter = value;
PrepareTexture();
}
}
public Texture() public Texture()
{ {
GL.GenTextures(1, out texture); GL.GenTextures(1, out texture);
@@ -45,9 +63,11 @@ namespace OpenRA.Renderer.Sdl2
ErrorHandler.CheckGlError(); ErrorHandler.CheckGlError();
GL.BindTexture(TextureTarget.Texture2D, texture); GL.BindTexture(TextureTarget.Texture2D, texture);
ErrorHandler.CheckGlError(); 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(); ErrorHandler.CheckGlError();
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, filter);
ErrorHandler.CheckGlError(); ErrorHandler.CheckGlError();
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.ClampToEdge); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.ClampToEdge);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -6,27 +6,26 @@ Container@MAP_PANEL:
Background@PREVIEW_BG: Background@PREVIEW_BG:
X: (PARENT_RIGHT - WIDTH) / 2 X: (PARENT_RIGHT - WIDTH) / 2
Y: 15 Y: 15
Width: 324 Width: 362
Height: 160 Height: 202
Background: panel-gray Background: panel-black
Children: Children:
MapPreview@MAP_PREVIEW: MapPreview@MAP_PREVIEW:
Width: 320 Width: 360
Height: 156 Height: 200
X: 2 X: 1
Y: 2 Y: 1
IgnoreMouseOver: True IgnoreMouseOver: True
IgnoreMouseInput: True IgnoreMouseInput: True
ShowSpawnPoints: False ShowSpawnPoints: False
ScrollPanel@MAP_DESCRIPTION_PANEL: ScrollPanel@MAP_DESCRIPTION_PANEL:
X: 15 X: 15
Y: 190 Y: 228
Width: 482 Width: 482
Height: 170 Height: 132
Children: Children:
Label@MAP_DESCRIPTION: Label@MAP_DESCRIPTION:
X: 5 X: 4
Y: 195 Y: 1
Width: 452 Width: PARENT_RIGHT - 32
Height: 160

View File

@@ -2,31 +2,42 @@ Container@MISSIONBROWSER_PANEL:
Logic: MissionBrowserLogic Logic: MissionBrowserLogic
X: (WINDOW_RIGHT - WIDTH)/2 X: (WINDOW_RIGHT - WIDTH)/2
Y: (WINDOW_BOTTOM - HEIGHT)/2 Y: (WINDOW_BOTTOM - HEIGHT)/2
Width: 629 Width: 642
Height: 399 Height: 377
Children: Children:
Label@MISSIONBROWSER_LABEL_TITLE: Label@MISSIONBROWSER_TITLE:
Y: 0-25 Y: 0-25
Width: PARENT_RIGHT Width: PARENT_RIGHT
Text: Missions Text: Missions
Align: Center Align: Center
Contrast: true
Font: BigBold Font: BigBold
Background@BG: Background@BG:
Width: 629 Width: 642
Height: 360 Height: 377
Background: panel-black Background: panel-black
Children: Children:
ScrollPanel@MISSION_LIST: ScrollPanel@MISSION_LIST:
X: 15 X: 15
Y: 15 Y: 15
Width: 260 Width: 239
Height: 330 Height: 347
Children: 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 Width: PARENT_RIGHT-27
Height: 25 Height: 25
X: 2 X: 2
Y: 0
Visible: False Visible: False
Children: Children:
Label@TITLE: Label@TITLE:
@@ -34,50 +45,67 @@ Container@MISSIONBROWSER_PANEL:
Width: PARENT_RIGHT-20 Width: PARENT_RIGHT-20
Height: 25 Height: 25
Container@MISSION_INFO: Container@MISSION_INFO:
X: 290 X: 265
Y: 15 Y: 15
Width: 324 Width: 362
Height: 334 Height: 349
Children: Children:
Background@MISSION_BG: Background@MISSION_BG:
X: 0 Width: PARENT_RIGHT
Y: 0 Height: 202
Width: 324 Background: panel-black
Height: 160
Background: panel-gray
Children: Children:
MapPreview@MISSION_PREVIEW: MapPreview@MISSION_PREVIEW:
X: 2 X: 1
Y: 2 Y: 1
Width: PARENT_RIGHT-4 Width: PARENT_RIGHT-2
Height: PARENT_BOTTOM-4 Height: PARENT_BOTTOM-2
IgnoreMouseOver: True IgnoreMouseOver: True
IgnoreMouseInput: True IgnoreMouseInput: True
ShowSpawnPoints: False ShowSpawnPoints: False
ScrollPanel@MISSION_DESCRIPTION_PANEL: ScrollPanel@MISSION_DESCRIPTION_PANEL:
X: 0 Y: 213
Y: 171 Width: PARENT_RIGHT
Width: 324 Height: 134
Height: 159
Children: Children:
Label@MISSION_DESCRIPTION: Label@MISSION_DESCRIPTION:
X: 5 X: 4
Y: 5 Y: 1
Width: 290 Width: PARENT_RIGHT - 32
VAlign: Top VAlign: Top
Font: Small
Button@BACK_BUTTON: Button@BACK_BUTTON:
X: 0 Y: 376
Y: 359
Width: 140 Width: 140
Height: 35 Height: 35
Text: Back Text: Back
Font: Bold Font: Bold
Key: escape Key: escape
Button@STARTGAME_BUTTON: Button@START_VIDEO_BUTTON:
X: PARENT_RIGHT - 140 X: PARENT_RIGHT - 290
Y: 359 Y: 376
Width: 140 Width: 140
Height: 35 Height: 35
Text: Start Game Text: View Briefing
Font: Bold 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

View File

@@ -39,7 +39,7 @@ CheckForBase = function()
end end
WorldLoaded = function() WorldLoaded = function()
Media.PlayMovieFullscreen("gdi1.vqa", function() Media.PlayMovieFullscreen("landing.vqa") end) Media.PlayMovieFullscreen("landing.vqa")
player = Player.GetPlayer("GDI") player = Player.GetPlayer("GDI")
enemy = Player.GetPlayer("Nod") enemy = Player.GetPlayer("Nod")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -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. 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 Author: Westwood Studios
Tileset: TEMPERAT Tileset: TEMPERAT

View File

@@ -65,8 +65,6 @@ WorldLoaded = function()
Trigger.OnKilled(NodRefinery, function() player.MarkFailedObjective(gdiObjective2) end) Trigger.OnKilled(NodRefinery, function() player.MarkFailedObjective(gdiObjective2) end)
Trigger.OnAllKilled(nodInBaseTeam, BridgeheadSecured) Trigger.OnAllKilled(nodInBaseTeam, BridgeheadSecured)
Media.PlayMovieFullscreen("gdi2.vqa")
end end
Tick = function() Tick = function()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -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. 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 Author: Westwood Studios
Tileset: TEMPERAT Tileset: TEMPERAT

View File

@@ -24,7 +24,7 @@ WorldLoaded = function()
player = OpenRA.GetPlayer("GDI") player = OpenRA.GetPlayer("GDI")
enemy = OpenRA.GetPlayer("Nod") 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 }) samSites = Team.New({ Sam1, Sam2, Sam3, Sam4 })
Team.AddEventHandler(samSites.OnAllKilled, function() Actor.Create("PowerProxy.AirSupport", { Owner = player }) end) Team.AddEventHandler(samSites.OnAllKilled, function() Actor.Create("PowerProxy.AirSupport", { Owner = player }) end)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -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. 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 Author: Westwood Studios
Tileset: TEMPERAT Tileset: TEMPERAT

View File

@@ -111,7 +111,7 @@ SetupWorld = function()
end end
WorldLoaded = function() 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") player = OpenRA.GetPlayer("GDI")
nod = OpenRA.GetPlayer("Nod") nod = OpenRA.GetPlayer("Nod")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -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. 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 Author: Westwood Studios
Tileset: TEMPERAT Tileset: TEMPERAT

View File

@@ -151,7 +151,7 @@ SetupWorld = function()
end end
WorldLoaded = function() 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") player = OpenRA.GetPlayer("GDI")
nod = OpenRA.GetPlayer("Nod") nod = OpenRA.GetPlayer("Nod")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -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. 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 Tileset: TEMPERAT
MapSize: 64,64 MapSize: 64,64

View File

@@ -122,7 +122,7 @@ WorldLoaded = function()
Camera.Position = Actor141.CenterPosition 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 end
Tick = function() Tick = function()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -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. 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 Tileset: TEMPERAT
MapSize: 64,64 MapSize: 64,64

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -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. 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 Author: Westwood Studios
Tileset: DESERT Tileset: DESERT

View File

@@ -56,8 +56,6 @@ WorldLoaded = function()
Trigger.AfterDelay(Utils.Seconds(30), SendFirstInfantryReinforcements) Trigger.AfterDelay(Utils.Seconds(30), SendFirstInfantryReinforcements)
Trigger.AfterDelay(Utils.Seconds(60), SendSecondInfantryReinforcements) Trigger.AfterDelay(Utils.Seconds(60), SendSecondInfantryReinforcements)
Media.PlayMovieFullscreen("nod1pre.vqa", function() Media.PlayMovieFullscreen("nod1.vqa") end)
end end
Tick = function() Tick = function()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -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. 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 Author: Westwood Studios
Tileset: DESERT Tileset: DESERT

View File

@@ -61,8 +61,6 @@ WorldLoaded = function()
Trigger.AfterDelay(Utils.Seconds(20), function() SendAttackWave(FirstAttackWave, AttackWaveSpawnA.Location) end) 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(50), function() SendAttackWave(SecondThirdAttackWave, AttackWaveSpawnB.Location) end)
Trigger.AfterDelay(Utils.Seconds(100), function() SendAttackWave(SecondThirdAttackWave, AttackWaveSpawnC.Location) end) Trigger.AfterDelay(Utils.Seconds(100), function() SendAttackWave(SecondThirdAttackWave, AttackWaveSpawnC.Location) end)
Media.PlayMovieFullscreen("nod3.vqa")
end end
Tick = function() Tick = function()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -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. 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 Author: Westwood Studios
Tileset: DESERT Tileset: DESERT

View File

@@ -75,7 +75,6 @@ WorldLoaded = function()
Trigger.AfterDelay(Utils.Seconds(80), function() SendAttackWave(SecondAttackWaveUnits, SecondAttackWave) end) Trigger.AfterDelay(Utils.Seconds(80), function() SendAttackWave(SecondAttackWaveUnits, SecondAttackWave) end)
Trigger.AfterDelay(Utils.Seconds(140), function() SendAttackWave(ThirdAttackWaveUnits, FirstAttackWave) end) Trigger.AfterDelay(Utils.Seconds(140), function() SendAttackWave(ThirdAttackWaveUnits, FirstAttackWave) end)
Media.PlayMovieFullscreen("nod3.vqa")
end end
Tick = function() Tick = function()

View File

@@ -1,10 +1,12 @@
Missions: GDI Campaign:
./mods/cnc/maps/gdi01 ./mods/cnc/maps/gdi01
./mods/cnc/maps/gdi02 ./mods/cnc/maps/gdi02
./mods/cnc/maps/gdi03 ./mods/cnc/maps/gdi03
./mods/cnc/maps/gdi04a ./mods/cnc/maps/gdi04a
./mods/cnc/maps/gdi04b ./mods/cnc/maps/gdi04b
./mods/cnc/maps/gdi04c ./mods/cnc/maps/gdi04c
Nod Campaign:
./mods/cnc/maps/nod01 ./mods/cnc/maps/nod01
./mods/cnc/maps/nod03a ./mods/cnc/maps/nod03a
./mods/cnc/maps/nod03b ./mods/cnc/maps/nod03b

View File

@@ -170,6 +170,9 @@ ChromeMetrics:
./mods/cnc/metrics.yaml ./mods/cnc/metrics.yaml
Fonts: Fonts:
Small:
Font:FreeSans.ttf
Size:12
Regular: Regular:
Font:./FreeSans.ttf Font:./FreeSans.ttf
Size:14 Size:14

View File

@@ -166,6 +166,9 @@ Fonts:
BigBold: BigBold:
Font:./FreeSansBold.ttf Font:./FreeSansBold.ttf
Size:24 Size:24
Small:
Font:FreeSans.ttf
Size:12
Tiny: Tiny:
Font:./FreeSans.ttf Font:./FreeSans.ttf
Size:10 Size:10

View File

@@ -6,27 +6,27 @@ Container@MAP_PANEL:
Background@PREVIEW_BG: Background@PREVIEW_BG:
X: (PARENT_RIGHT - WIDTH) / 2 X: (PARENT_RIGHT - WIDTH) / 2
Y: 20 Y: 20
Width: 324 Width: 362
Height: 160 Height: 202
Background: panel-gray Background: dialog3
Children: Children:
MapPreview@MAP_PREVIEW: MapPreview@MAP_PREVIEW:
Width: 320 X: 1
Height: 156 Y: 1
X: 2 Width: PARENT_RIGHT-2
Y: 2 Height: PARENT_BOTTOM-2
IgnoreMouseOver: True IgnoreMouseOver: True
IgnoreMouseInput: True IgnoreMouseInput: True
ShowSpawnPoints: False ShowSpawnPoints: False
ScrollPanel@MAP_DESCRIPTION_PANEL: ScrollPanel@MAP_DESCRIPTION_PANEL:
X: 20 X: 20
Y: 195 Y: 232
Width: 482 Width: PARENT_RIGHT - 40
Height: 175 Height: 138
Children: Children:
Label@MAP_DESCRIPTION: Label@MAP_DESCRIPTION:
X: 5 X: 4
Y: 180 Y: 1
Width: 452 Width: PARENT_RIGHT - 32
Height: 145

View File

@@ -2,11 +2,10 @@ Background@MISSIONBROWSER_PANEL:
Logic: MissionBrowserLogic Logic: MissionBrowserLogic
X: (WINDOW_RIGHT - WIDTH)/2 X: (WINDOW_RIGHT - WIDTH)/2
Y: (WINDOW_BOTTOM - HEIGHT)/2 Y: (WINDOW_BOTTOM - HEIGHT)/2
Width: 634 Width: 682
Height: 440 Height: 487
Children: Children:
Label@MISSIONBROWSER_LABEL_TITLE: Label@MISSIONBROWSER_TITLE:
X: 0
Y: 20 Y: 20
Width: PARENT_RIGHT Width: PARENT_RIGHT
Height: 25 Height: 25
@@ -16,57 +15,80 @@ Background@MISSIONBROWSER_PANEL:
ScrollPanel@MISSION_LIST: ScrollPanel@MISSION_LIST:
X: 20 X: 20
Y: 50 Y: 50
Width: 260 Width: 270
Height: 330 Height: 377
Children: 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 Width: PARENT_RIGHT-27
Height: 25 Height: 25
X: 2 X: 2
Y: 0
Children: Children:
Label@TITLE: Label@TITLE:
X: 10 X: 10
Width: PARENT_RIGHT-20 Width: PARENT_RIGHT-20
Height: 25 Height: 25
Container@MISSION_INFO: Container@MISSION_INFO:
X: 290 X: 300
Y: 50 Y: 50
Width: 324 Width: 362
Height: 330 Height: 363
Children: Children:
Background@MISSION_BG: Background@MISSION_BG:
X: 0 Width: PARENT_RIGHT
Y: 0 Height: 202
Width: 324
Height: 160
Background: dialog3 Background: dialog3
Children: Children:
MapPreview@MISSION_PREVIEW: MapPreview@MISSION_PREVIEW:
X: 2 X: 1
Y: 2 Y: 1
Width: PARENT_RIGHT-4 Width: PARENT_RIGHT-2
Height: PARENT_BOTTOM-4 Height: PARENT_BOTTOM-2
IgnoreMouseOver: True IgnoreMouseOver: True
IgnoreMouseInput: True IgnoreMouseInput: True
ShowSpawnPoints: False ShowSpawnPoints: False
ScrollPanel@MISSION_DESCRIPTION_PANEL: ScrollPanel@MISSION_DESCRIPTION_PANEL:
X: 0 Y: 212
Y: 170 Width: PARENT_RIGHT
Width: 324 Height: 165
Height: 160
Children: Children:
Label@MISSION_DESCRIPTION: Label@MISSION_DESCRIPTION:
X: 5 X: 4
Y: 5 Y: 1
Width: 290 Width: PARENT_RIGHT - 32
VAlign: Top 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: Button@STARTGAME_BUTTON:
X: PARENT_RIGHT - 140 - 130 X: PARENT_RIGHT - 140 - 130
Y: PARENT_BOTTOM - 45 Y: PARENT_BOTTOM - 45
Width: 120 Width: 120
Height: 25 Height: 25
Text: Start Game Text: Play
Font: Bold Font: Bold
Button@BACK_BUTTON: Button@BACK_BUTTON:
X: PARENT_RIGHT - 140 X: PARENT_RIGHT - 140
@@ -76,4 +98,15 @@ Background@MISSIONBROWSER_PANEL:
Text: Back Text: Back
Font: Bold Font: Bold
Key: escape 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

View File

@@ -201,5 +201,5 @@ WorldLoaded = function()
Camera.Position = InsertionLZ.CenterPosition Camera.Position = InsertionLZ.CenterPosition
Media.PlayMovieFullscreen("ally1.vqa", function() Media.PlayMovieFullscreen("landing.vqa") end) Media.PlayMovieFullscreen("landing.vqa")
end end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -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. 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 Author: Westwood Studios
Tileset: SNOW Tileset: SNOW

View File

@@ -123,7 +123,7 @@ WorldLoaded = function()
Camera.Position = ReinforcementsEntryPoint.CenterPosition 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.Seconds(3), "TenMinutesRemaining")
ConvoyTimer(Utils.Minutes(5), "WarningFiveMinutesRemaining") ConvoyTimer(Utils.Minutes(5), "WarningFiveMinutesRemaining")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -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. 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 Author: Westwood Studios
Tileset: SNOW Tileset: SNOW

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -1,4 +1,3 @@
Missions: Allied Campaign:
./mods/ra/maps/allies-01-classic ./mods/ra/maps/allies-01-classic
./mods/ra/maps/allies-02-classic ./mods/ra/maps/allies-02-classic
./mods/ra/maps/intervention

View File

@@ -182,6 +182,9 @@ Fonts:
BigBold: BigBold:
Font:./FreeSansBold.ttf Font:./FreeSansBold.ttf
Size:24 Size:24
Small:
Font:FreeSans.ttf
Size:12
Tiny: Tiny:
Font:./FreeSans.ttf Font:./FreeSans.ttf
Size:10 Size:10

View File

@@ -207,6 +207,9 @@ Fonts:
BigBold: BigBold:
Font:./FreeSansBold.ttf Font:./FreeSansBold.ttf
Size:24 Size:24
Small:
Font:FreeSans.ttf
Size:12
Tiny: Tiny:
Font:./FreeSans.ttf Font:./FreeSans.ttf
Size:10 Size:10