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.Linq;
  using Eluant;
  using OpenRA.Effects;
  using OpenRA.Scripting;
  
  namespace OpenRA.Mods.Common.Scripting
  {
  	[ScriptGlobal("Trigger")]
  	public class TriggerGlobal : ScriptGlobal
  	{
  		public TriggerGlobal(ScriptContext context)
  			: base(context) { }
  
  		public static ScriptTriggers GetScriptTriggers(Actor a)
  		{
  			var events = a.TraitOrDefault<ScriptTriggers>();
  			if (events == null)
  				throw new LuaException("Actor '{0}' requires the ScriptTriggers trait before attaching a trigger".F(a.Info.Name));
  
  			return events;
  		}
  
  		[Desc("Call a function after a specified delay. The callback function will be called as func().")]
  		public void AfterDelay(int delay, LuaFunction func)
  		{
  			var f = (LuaFunction)func.CopyReference();
  			Action doCall = () =>
  			{
  				try
  				{
  					using (f)
  						f.Call().Dispose();
  				}
  				catch (Exception e)
  				{
  					Context.FatalError(e.Message);
  				}
  			};
  
  			Context.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, doCall)));
  		}
  
  		[Desc("Call a function for each passenger when it enters a transport. " +
  			"The callback function will be called as func(Actor transport, Actor passenger).")]
  		public void OnPassengerEntered(Actor a, LuaFunction func)
  		{
  			GetScriptTriggers(a).RegisterCallback(Trigger.OnPassengerEntered, func, Context);
  		}
  
  		[Desc("Call a function for each passenger when it exits a transport. " +
  			"The callback function will be called as func(Actor transport, Actor passenger).")]
  		public void OnPassengerExited(Actor a, LuaFunction func)
  		{
  			GetScriptTriggers(a).RegisterCallback(Trigger.OnPassengerExited, func, Context);
  		}
  
  		[Desc("Call a function each tick that the actor is idle. " +
  			"The callback function will be called as func(Actor self).")]
  		public void OnIdle(Actor a, LuaFunction func)
  		{
  			GetScriptTriggers(a).RegisterCallback(Trigger.OnIdle, func, Context);
  		}
  
  		[Desc("Call a function when the actor is damaged. The callback " +
  			"function will be called as func(Actor self, Actor attacker).")]
  		public void OnDamaged(Actor a, LuaFunction func)
  		{
  			GetScriptTriggers(a).RegisterCallback(Trigger.OnDamaged, func, Context);
  		}
  
  		[Desc("Call a function when the actor is killed. The callback " +
  			"function will be called as func(Actor self, Actor killer).")]
  		public void OnKilled(Actor a, LuaFunction func)
  		{
  			GetScriptTriggers(a).RegisterCallback(Trigger.OnKilled, func, Context);
  		}
  
  		[Desc("Call a function when all of the actors in a group are killed. The callback " +
  			"function will be called as func().")]
  		public void OnAllKilled(Actor[] actors, LuaFunction func)
  		{
  			var group = actors.ToList();
  			var f = (LuaFunction)func.CopyReference();
  			Action<Actor> onMemberKilled = m =>
  			{
  				try
  				{
  					group.Remove(m);
  					if (!group.Any())
  						using (f)
  							f.Call();
  				}
  				catch (Exception e)
  				{
  					Context.FatalError(e.Message);
  				}
  			};
  
  			foreach (var a in group)
  				GetScriptTriggers(a).OnKilledInternal += onMemberKilled;
  		}
  
  		[Desc("Call a function when one of the actors in a group is killed. The callback " +
  			"function will be called as func(Actor killed).")]
  		public void OnAnyKilled(Actor[] actors, LuaFunction func)
  		{
  			var called = false;
  			var f = (LuaFunction)func.CopyReference();
  			Action<Actor> onMemberKilled = m =>
  			{
  				try
  				{
  					if (called)
  						return;
  
  					using (f)
  					using (var killed = m.ToLuaValue(Context))
  						f.Call(killed).Dispose();
  
  					called = true;
  				}
  				catch (Exception e)
  				{
  					Context.FatalError(e.Message);
  				}
  			};
  
  			foreach (var a in actors)
  				GetScriptTriggers(a).OnKilledInternal += onMemberKilled;
  		}
  
  		[Desc("Call a function when this actor produces another actor. " +
  			"The callback function will be called as func(Actor producer, Actor produced).")]
  		public void OnProduction(Actor a, LuaFunction func)
  		{
  			GetScriptTriggers(a).RegisterCallback(Trigger.OnProduction, func, Context);
  		}
  
  		[Desc("Call a function when any actor produces another actor. The callback " +
  			"function will be called as func(Actor producer, Actor produced, string productionType).")]
  		public void OnAnyProduction(LuaFunction func)
  		{
  			GetScriptTriggers(Context.World.WorldActor).RegisterCallback(Trigger.OnOtherProduction, func, Context);
  		}
  
  		[Desc("Call a function when this player completes all primary objectives. " +
  			"The callback function will be called as func(Player player).")]
  		public void OnPlayerWon(Player player, LuaFunction func)
  		{
  			GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnPlayerWon, func, Context);
  		}
  
  		[Desc("Call a function when this player fails any primary objective. " +
  			"The callback function will be called as func(Player player).")]
  		public void OnPlayerLost(Player player, LuaFunction func)
  		{
  			GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnPlayerLost, func, Context);
  		}
  
  		[Desc("Call a function when this player is assigned a new objective. " +
  			"The callback function will be called as func(Player player, int objectiveID).")]
  		public void OnObjectiveAdded(Player player, LuaFunction func)
  		{
  			GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnObjectiveAdded, func, Context);
  		}
  
  		[Desc("Call a function when this player completes an objective. " +
  			"The callback function will be called as func(Player player, int objectiveID).")]
  		public void OnObjectiveCompleted(Player player, LuaFunction func)
  		{
  			GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnObjectiveCompleted, func, Context);
  		}
  
  		[Desc("Call a function when this player fails an objective. " +
  			"The callback function will be called as func(Player player, int objectiveID).")]
  		public void OnObjectiveFailed(Player player, LuaFunction func)
  		{
  			GetScriptTriggers(player.PlayerActor).RegisterCallback(Trigger.OnObjectiveFailed, func, Context);
  		}
  
  		[Desc("Call a function when this actor is added to the world. " +
  			"The callback function will be called as func(Actor self).")]
  		public void OnAddedToWorld(Actor a, LuaFunction func)
  		{
  			GetScriptTriggers(a).RegisterCallback(Trigger.OnAddedToWorld, func, Context);
  		}
  
  		[Desc("Call a function when this actor is removed from the world. " +
  			"The callback function will be called as func(Actor self).")]
  		public void OnRemovedFromWorld(Actor a, LuaFunction func)
  		{
  			GetScriptTriggers(a).RegisterCallback(Trigger.OnRemovedFromWorld, func, Context);
  		}
  
  		[Desc("Call a function when all of the actors in a group have been removed from the world. " +
  			"The callback function will be called as func().")]
  		public void OnAllRemovedFromWorld(Actor[] actors, LuaFunction func)
  		{
  			var group = actors.ToList();
  
  
gt: 			var f = (LuaFunction)func.CopyReference();