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);
}
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

View File

@@ -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;

View File

@@ -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()

View File

@@ -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;

View File

@@ -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;

View File

@@ -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) { }

View File

@@ -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);

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:
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

View File

@@ -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

View File

@@ -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")

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.
PreviewVideo: gdi1.vqa
Author: Westwood Studios
Tileset: TEMPERAT

View File

@@ -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()

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.
PreviewVideo: gdi2.vqa
Author: Westwood Studios
Tileset: TEMPERAT

View File

@@ -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)

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.
PreviewVideo: gdi3.vqa
Author: Westwood Studios
Tileset: TEMPERAT

View File

@@ -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")

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.
PreviewVideo: gdi4b.vqa
Author: Westwood Studios
Tileset: TEMPERAT

View File

@@ -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")

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.
PreviewVideo: gdi4b.vqa
Tileset: TEMPERAT
MapSize: 64,64

View File

@@ -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()

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.
PreviewVideo: gdi4a.vqa
Tileset: TEMPERAT
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.
PreviewVideo: nod1.vqa
Author: Westwood Studios
Tileset: DESERT

View File

@@ -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()

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.
PreviewVideo: nod3.vqa
Author: Westwood Studios
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(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()

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.
PreviewVideo: nod3.vqa
Author: Westwood Studios
Tileset: DESERT

View File

@@ -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()

View File

@@ -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

View File

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

View File

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

View File

@@ -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

View File

@@ -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

View File

@@ -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

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.
PreviewVideo: ally1.vqa
Author: Westwood Studios
Tileset: SNOW

View File

@@ -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")

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.
PreviewVideo: ally2.vqa
Author: Westwood Studios
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-02-classic
./mods/ra/maps/intervention

View File

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

View File

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