context: #region Copyright & License Information
  /*
   * Copyright 2007-2020 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, either version 3 of
   * the License, or (at your option) any later version. For more
   * information, see COPYING.
   */
  #endregion
  
  using System;
  using System.IO;
  using Eluant;
  using OpenRA.Effects;
  using OpenRA.GameRules;
  using OpenRA.Mods.Common.Effects;
  using OpenRA.Mods.Common.Traits;
  using OpenRA.Primitives;
  using OpenRA.Scripting;
  using OpenRA.Video;
  
  namespace OpenRA.Mods.Common.Scripting
  {
  	[ScriptGlobal("Media")]
  	public class MediaGlobal : ScriptGlobal
  	{
  		readonly World world;
  		readonly MusicPlaylist playlist;
  
  		public MediaGlobal(ScriptContext context)
  			: base(context)
  		{
  			world = context.World;
  			playlist = world.WorldActor.Trait<MusicPlaylist>();
  		}
  
  		[Desc("Play an announcer voice listed in notifications.yaml")]
  		public void PlaySpeechNotification(Player player, string notification)
  		{
  			Game.Sound.PlayNotification(world.Map.Rules, player, "Speech", notification, player != null ? player.Faction.InternalName : null);
  		}
  
  		[Desc("Play a sound listed in notifications.yaml")]
  		public void PlaySoundNotification(Player player, string notification)
  		{
  			Game.Sound.PlayNotification(world.Map.Rules, player, "Sounds", notification, player != null ? player.Faction.InternalName : null);
  		}
  
  		[Desc("Play a sound file")]
  		public void PlaySound(string file)
  		{
  			// TODO: Investigate how scripts use this function, and think about exposing the UI vs World distinction if needed
  			Game.Sound.Play(SoundType.World, file);
  		}
  
  		[Desc("Play track defined in music.yaml or map.yaml, or keep track empty for playing a random song.")]
  		public void PlayMusic(string track = null, LuaFunction func = null)
  		{
  			if (!playlist.IsMusicAvailable)
  				return;
  
  			var musicInfo = !string.IsNullOrEmpty(track) ? GetMusicTrack(track)
  				: playlist.GetNextSong();
  
  			if (func != null)
  			{
  				var f = (LuaFunction)func.CopyReference();
  				Action onComplete = () =>
  				{
  					try
  					{
  						using (f)
  							f.Call().Dispose();
  					}
  					catch (LuaException e)
  					{
  						Context.FatalError(e.Message);
  					}
  				};
  
  				playlist.Play(musicInfo, onComplete);
  			}
  			else
  				playlist.Play(musicInfo);
  		}
  
  		[Desc("Play track defined in music.yaml or map.yaml as background music." +
  			" If music is already playing use Media.StopMusic() to stop it" +
  			" and the background music will start automatically." +
  			" Keep the track empty to disable background music.")]
  		public void SetBackgroundMusic(string track = null)
  		{
  			if (!playlist.IsMusicAvailable)
  				return;
  
  			playlist.SetBackgroundMusic(string.IsNullOrEmpty(track) ? null : GetMusicTrack(track));
  		}
  
  		MusicInfo GetMusicTrack(string track)
  		{
  			var music = world.Map.Rules.Music;
  			if (music.ContainsKey(track))
  				return music[track];
  
  			Log.Write("lua", "Missing music track: " + track);
  			return null;
  		}
  
  		[Desc("Stop the current song.")]
  		public void StopMusic()
  		{
  			playlist.Stop();
  		}
  
  		[Desc("Play a VQA video fullscreen. File name has to include the file extension.")]
  		public void PlayMovieFullscreen(string movie, LuaFunction func = null)
  		{
  			Action onCompleteFullscreen;
  			if (func != null)
  			{
  				var f = (LuaFunction)func.CopyReference();
  				onCompleteFullscreen = () =>
  				{
  					try
  					{
  						using (f)
  							f.Call().Dispose();
  					}
  					catch (LuaException e)
  					{
  						Context.FatalError(e.Message);
  					}
  				};
  			}
  			else
  				onCompleteFullscreen = () => { };
  
  			Media.PlayFMVFullscreen(world, movie, onCompleteFullscreen);
  		}
  
  		[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)
  		{
  			Action onCompleteRadar;
  			if (playComplete != null)
  			{
  				var f = (LuaFunction)playComplete.CopyReference();
  				onCompleteRadar = () =>
  				{
  					try
  					{
  						using (f)
  							f.Call().Dispose();
  					}
  					catch (LuaException e)
  					{
  						Context.FatalError(e.Message);
  					}
  				};
  			}
  			else
  				onCompleteRadar = () => { };
  
  			Stream s;
  			try
  			{
  				s = world.Map.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.LoadVideo);
  			IAsyncResult ar = l.BeginInvoke(s, null, null);
  			Action onLoadComplete = () =>
  			{
  				Media.StopFMVInRadar();
  				world.AddFrameEndTask(_ => Media.PlayFMVInRadar(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", Color? color = null)
  		{
  			if (string.IsNullOrEmpty(text))
  				return;
  
  			var c = color.HasValue ? color.Value : Color.White;
  			Game.AddChatLine(prefix, c, text);
  		}
  
  		[Desc("Display a system message to the player. If 'prefix' is nil the default system prefix is used.")]
  		public void DisplaySystemMessage(string text, string prefix = null)
  		{
  			if (string.IsNullOrEmpty(text))
  				return;
  
  			if (string.IsNullOrEmpty(prefix))
  				Game.AddSystemLine(text);
  			else
  				Game.AddSystemLine(prefix, text);
  		}
  
  		[Desc("Displays a debug message to the player, if \"Show Map Debug Messages\" is checked in the settings.")]
  		public void Debug(string text)
  		{
  			if (string.IsNullOrEmpty(text) || !Game.Settings.Debug.LuaDebug)
  				return;
  
  			Game.Debug(text);
  		}
  
  
gt: 		[Desc("Display a text message at the specified location.")]