Implemented Floating Text and radar video

This commit is contained in:
DeadlySurprise
2014-12-14 14:39:41 +01:00
parent 5bcd56eb9d
commit 7b53582c5e
9 changed files with 209 additions and 40 deletions

View File

@@ -0,0 +1,38 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
namespace OpenRA.Effects
{
public class AsyncAction : IEffect
{
Action a;
IAsyncResult ar;
public AsyncAction(IAsyncResult ar, Action a)
{
this.a = a;
this.ar = ar;
}
public void Tick(World world)
{
if (ar.IsCompleted)
{
world.AddFrameEndTask(w => { w.Remove(this); a(); });
}
}
public IEnumerable<IRenderable> Render(WorldRenderer r) { yield break; }
}
}

View File

@@ -88,6 +88,7 @@
<Compile Include="GameRules\Warhead.cs" />
<Compile Include="Graphics\QuadRenderer.cs" />
<Compile Include="Download.cs" />
<Compile Include="Effects\AsyncAction.cs" />
<Compile Include="Effects\DelayedAction.cs" />
<Compile Include="Effects\FlashTarget.cs" />
<Compile Include="Effects\IEffect.cs" />

View File

@@ -21,6 +21,7 @@ namespace OpenRA.Widgets
public Hotkey CancelKey = new Hotkey(Keycode.ESCAPE, Modifiers.None);
public float AspectRatio = 1.2f;
public bool DrawOverlay = true;
public bool Skippable = true;
public bool Paused { get { return paused; } }
public VqaReader Video { get { return video; } }
@@ -48,15 +49,21 @@ namespace OpenRA.Widgets
{
if (filename == cachedVideo)
return;
var video = new VqaReader(GlobalFileSystem.Open(filename));
cachedVideo = filename;
Open(video);
}
public void Open(VqaReader video)
{
this.video = video;
stopped = true;
paused = true;
Sound.StopVideo();
onComplete = () => { };
cachedVideo = filename;
video = new VqaReader(GlobalFileSystem.Open(filename));
invLength = video.Framerate * 1f / video.Frames;
var size = Math.Max(video.Width, video.Height);
@@ -107,7 +114,8 @@ namespace OpenRA.Widgets
else
nextFrame = video.CurrentFrame + 1;
if (nextFrame > video.Frames)
// Without the 2nd check the sound playback sometimes ends before the final frame is displayed which causes the player to be stuck on the first frame
if (nextFrame > video.Frames || nextFrame < video.CurrentFrame)
{
Stop();
return;
@@ -136,7 +144,7 @@ namespace OpenRA.Widgets
public override bool HandleKeyPress(KeyInput e)
{
if (Hotkey.FromKeyInput(e) != CancelKey || e.Event != KeyInputEvent.Down)
if (Hotkey.FromKeyInput(e) != CancelKey || e.Event != KeyInputEvent.Down || !Skippable)
return false;
Stop();
@@ -188,5 +196,11 @@ namespace OpenRA.Widgets
videoSprite.Sheet.GetTexture().SetData(video.FrameData);
world.AddFrameEndTask(_ => onComplete());
}
public void CloseVideo()
{
Stop();
video = null;
}
}
}

View File

@@ -10,11 +10,15 @@
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using Eluant;
using OpenRA.Effects;
using OpenRA.FileFormats;
using OpenRA.FileSystem;
using OpenRA.GameRules;
using OpenRA.Mods.Common.Effects;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Scripting
{
@@ -40,33 +44,8 @@ namespace OpenRA.Mods.Common.Scripting
Sound.PlayNotification(world.Map.Rules, player, "Sounds", notification, player != null ? player.Country.Race : null);
}
Action onComplete;
[Desc("Play a VQA video including the file extension.")]
public void PlayMovieFullscreen(string movie, LuaFunction func = null)
{
if (func != null)
{
var f = func.CopyReference() as LuaFunction;
onComplete = () =>
{
try
{
using (f)
f.Call().Dispose();
}
catch (LuaException e)
{
Context.FatalError(e.Message);
}
};
}
else
onComplete = () => { };
Media.PlayFMVFullscreen(world, movie, onComplete);
}
MusicInfo previousMusic;
Action onComplete;
[Desc("Play track defined in music.yaml or keep it empty for a random song.")]
public void PlayMusic(string track = null, LuaFunction func = null)
{
@@ -103,6 +82,7 @@ namespace OpenRA.Mods.Common.Scripting
onComplete = () => { };
Sound.PlayMusicThen(musicInfo, onComplete);
previousMusic = Sound.CurrentMusic;
}
@@ -112,13 +92,100 @@ namespace OpenRA.Mods.Common.Scripting
Sound.StopMusic();
}
Action onCompleteFullscreen;
[Desc("Play a VQA video fullscreen. File name has to include the file extension.")]
public void PlayMovieFullscreen(string movie, LuaFunction func = null)
{
if (func != null)
{
var f = func.CopyReference() as LuaFunction;
onCompleteFullscreen = () =>
{
try
{
using (f)
f.Call().Dispose();
}
catch (LuaException e)
{
Context.FatalError(e.Message);
}
};
}
else
onCompleteFullscreen = () => { };
Media.PlayFMVFullscreen(world, movie, onCompleteFullscreen);
}
Action onLoadComplete;
Action onCompleteRadar;
[Desc("Play a VQA video in the radar window. File name has to include the file extension. Returns true on success, if the movie wasn't found the function returns false and the callback is executed.")]
public bool PlayMovieInRadar(string movie, LuaFunction playComplete = null)
{
if (playComplete != null)
{
var f = playComplete.CopyReference() as LuaFunction;
onCompleteRadar = () =>
{
try
{
using (f)
f.Call().Dispose();
}
catch (LuaException e)
{
Context.FatalError(e.Message);
}
};
}
else
onCompleteRadar = () => { };
Stream s = null;
try
{
s = GlobalFileSystem.Open(movie);
}
catch (FileNotFoundException e)
{
Log.Write("lua", "Couldn't play movie {0}! File doesn't exist.", e.FileName);
onCompleteRadar();
return false;
}
AsyncLoader l = new AsyncLoader(Media.LoadVqa);
IAsyncResult ar = l.BeginInvoke(s, null, null);
onLoadComplete = () =>
{
Media.StopFMVInRadar();
world.AddFrameEndTask(_ => Media.PlayFMVInRadar(world, l.EndInvoke(ar), onCompleteRadar));
};
world.AddFrameEndTask(w => w.Add(new AsyncAction(ar, onLoadComplete)));
return true;
}
[Desc("Display a text message to the player.")]
public void DisplayMessage(string text, string prefix = "Mission") // TODO: expose HSLColor to Lua and add as parameter
public void DisplayMessage(string text, string prefix = "Mission")
{
if (string.IsNullOrEmpty(text))
return;
Game.AddChatLine(Color.White, prefix, text);
}
Color c = Color.White;
Game.AddChatLine(c, prefix, text);
} // TODO: expose HSLColor to Lua and add as parameter
[Desc("Display a text message at the specified location.")]
public void FloatingText(string text, WPos position, int duration = 30)
{
if (string.IsNullOrEmpty(text) || !world.Map.Contains(world.Map.CellContaining(position)))
return;
Color c = Color.White;
world.AddFrameEndTask(w => w.Add(new FloatingText(position, c, text, duration)));
} // TODO: expose HSLColor to Lua and add as parameter
public delegate VqaReader AsyncLoader(Stream s);
}
}

View File

@@ -10,6 +10,7 @@
using System;
using System.IO;
using OpenRA.FileFormats;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Scripting
@@ -56,5 +57,28 @@ namespace OpenRA.Mods.Common.Scripting
onComplete();
});
}
public static void PlayFMVInRadar(World w, VqaReader movie, Action onComplete)
{
var player = Ui.Root.Get<VqaPlayerWidget>("PLAYER");
player.Open(movie);
player.PlayThen(() =>
{
onComplete();
player.CloseVideo();
});
}
public static void StopFMVInRadar()
{
var player = Ui.Root.Get<VqaPlayerWidget>("PLAYER");
player.Stop();
}
public static VqaReader LoadVqa(Stream s)
{
return new VqaReader(s);
}
}
}

View File

@@ -314,6 +314,12 @@ Container@PLAYER_WIDGETS:
WorldInteractionController: INTERACTION_CONTROLLER
Children:
LogicTicker@RADAR_TICKER:
VqaPlayer@PLAYER:
X: 1
Y: 1
Width: PARENT_RIGHT-2
Height: PARENT_BOTTOM-2
Skippable: false
Background@POWERBAR_PANEL:
Logic: IngamePowerBarLogic
X: 4

View File

@@ -161,6 +161,13 @@ Container@PLAYER_WIDGETS:
Y: 34
Width: 202
Height: 202
Children:
VqaPlayer@PLAYER:
X: 12
Y: 32
Width: 202
Height: 202
Skippable: false
Image@MINIMAP:
X: 12
Y: 34

View File

@@ -161,6 +161,13 @@ Container@PLAYER_WIDGETS:
Y: 41
Width: 220
Height: 220
Children:
VqaPlayer@PLAYER:
X: 8
Y: 40
Width: 220
Height: 220
Skippable: false
Label@GAME_TIMER:
Logic: GameTimerLogic
X: 3

View File

@@ -51,6 +51,11 @@ Container@PLAYER_WIDGETS:
X: 9
Width: 192
Height: 192
VqaPlayer@PLAYER:
X: 9
Width: 192
Height: 192
Skippable: false
ResourceBar@POWERBAR:
Logic: IngamePowerBarLogic
X: 42