Files
OpenRA/OpenRA.Mods.Common/Scripting/Global/TriggerGlobal.cs

442 lines
13 KiB
C#

#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 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 = func.CopyReference() as LuaFunction;
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 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 copy = (LuaFunction)func.CopyReference();
Action<Actor> onMemberKilled = m =>
{
try
{
group.Remove(m);
if (!group.Any())
{
copy.Call();
copy.Dispose();
}
}
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 copy = (LuaFunction)func.CopyReference();
Action<Actor> onMemberKilled = m =>
{
try
{
if (called)
return;
using (var killed = m.ToLuaValue(Context))
copy.Call(killed).Dispose();
copy.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 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();
var copy = (LuaFunction)func.CopyReference();
Action<Actor> onMemberRemoved = m =>
{
try
{
if (!group.Remove(m))
return;
if (!group.Any())
{
copy.Call().Dispose();
copy.Dispose();
}
}
catch (Exception e)
{
Context.FatalError(e.Message);
}
};
foreach (var a in group)
GetScriptTriggers(a).OnRemovedInternal += onMemberRemoved;
}
[Desc("Call a function when this actor is captured. The callback function " +
"will be called as func(Actor self, Actor captor, Player oldOwner, Player newOwner).")]
public void OnCapture(Actor a, LuaFunction func)
{
GetScriptTriggers(a).RegisterCallback(Trigger.OnCapture, func, Context);
}
[Desc("Call a function when this actor is killed or captured. " +
"The callback function will be called as func().")]
public void OnKilledOrCaptured(Actor a, LuaFunction func)
{
var called = false;
var copy = (LuaFunction)func.CopyReference();
Action<Actor> onKilledOrCaptured = m =>
{
try
{
if (called)
return;
copy.Call().Dispose();
copy.Dispose();
called = true;
}
catch (Exception e)
{
Context.FatalError(e.Message);
}
};
GetScriptTriggers(a).OnCapturedInternal += onKilledOrCaptured;
GetScriptTriggers(a).OnKilledInternal += onKilledOrCaptured;
}
[Desc("Call a function when all of the actors in a group have been killed or captured. " +
"The callback function will be called as func().")]
public void OnAllKilledOrCaptured(Actor[] actors, LuaFunction func)
{
var group = actors.ToList();
var copy = (LuaFunction)func.CopyReference();
Action<Actor> onMemberKilledOrCaptured = m =>
{
try
{
if (!group.Remove(m))
return;
if (!group.Any())
{
copy.Call().Dispose();
copy.Dispose();
}
}
catch (Exception e)
{
Context.FatalError(e.Message);
}
};
foreach (var a in group)
{
GetScriptTriggers(a).OnCapturedInternal += onMemberKilledOrCaptured;
GetScriptTriggers(a).OnKilledInternal += onMemberKilledOrCaptured;
}
}
[Desc("Call a function when a ground-based actor enters this cell footprint." +
"Returns the trigger id for later removal using RemoveFootprintTrigger(int id)." +
"The callback function will be called as func(Actor a, int id).")]
public int OnEnteredFootprint(CPos[] cells, LuaFunction func)
{
var triggerId = 0;
var onEntry = (LuaFunction)func.CopyReference();
Action<Actor> invokeEntry = a =>
{
try
{
using (var luaActor = a.ToLuaValue(Context))
using (var id = triggerId.ToLuaValue(Context))
onEntry.Call(luaActor, id).Dispose();
}
catch (Exception e)
{
Context.FatalError(e.Message);
}
};
triggerId = Context.World.ActorMap.AddCellTrigger(cells, invokeEntry, null);
return triggerId;
}
[Desc("Call a function when a ground-based actor leaves this cell footprint." +
"Returns the trigger id for later removal using RemoveFootprintTrigger(int id)." +
"The callback function will be called as func(Actor a, int id).")]
public int OnExitedFootprint(CPos[] cells, LuaFunction func)
{
var triggerId = 0;
var onExit = (LuaFunction)func.CopyReference();
Action<Actor> invokeExit = a =>
{
try
{
using (var luaActor = a.ToLuaValue(Context))
using (var id = triggerId.ToLuaValue(Context))
onExit.Call(luaActor, id).Dispose();
}
catch (Exception e)
{
Context.FatalError(e.Message);
}
};
triggerId = Context.World.ActorMap.AddCellTrigger(cells, null, invokeExit);
return triggerId;
}
[Desc("Removes a previously created footprint trigger.")]
public void RemoveFootprintTrigger(int id)
{
Context.World.ActorMap.RemoveCellTrigger(id);
}
[Desc("Call a function when an actor enters this range." +
"Returns the trigger id for later removal using RemoveProximityTrigger(int id)." +
"The callback function will be called as func(Actor a, int id).")]
public int OnEnteredProximityTrigger(WPos pos, WRange range, LuaFunction func)
{
var triggerId = 0;
var onEntry = (LuaFunction)func.CopyReference();
Action<Actor> invokeEntry = a =>
{
try
{
using (var luaActor = a.ToLuaValue(Context))
using (var id = triggerId.ToLuaValue(Context))
onEntry.Call(luaActor, id).Dispose();
}
catch (Exception e)
{
Context.FatalError(e.Message);
}
};
triggerId = Context.World.ActorMap.AddProximityTrigger(pos, range, invokeEntry, null);
return triggerId;
}
[Desc("Call a function when an actor leaves this range." +
"Returns the trigger id for later removal using RemoveProximityTrigger(int id)." +
"The callback function will be called as func(Actor a, int id).")]
public int OnExitedProximityTrigger(WPos pos, WRange range, LuaFunction func)
{
var triggerId = 0;
var onExit = (LuaFunction)func.CopyReference();
Action<Actor> invokeExit = a =>
{
try
{
using (var luaActor = a.ToLuaValue(Context))
using (var id = triggerId.ToLuaValue(Context))
onExit.Call(luaActor, id).Dispose();
}
catch (Exception e)
{
Context.FatalError(e.Message);
}
};
triggerId = Context.World.ActorMap.AddProximityTrigger(pos, range, null, invokeExit);
return triggerId;
}
[Desc("Removes a previously created proximitry trigger.")]
public void RemoveProximityTrigger(int id)
{
Context.World.ActorMap.RemoveProximityTrigger(id);
}
[Desc("Call a function when this actor is infiltrated. The callback function " +
"will be called as func(Actor self, Actor infiltrator).")]
public void OnInfiltrated(Actor a, LuaFunction func)
{
GetScriptTriggers(a).RegisterCallback(Trigger.OnInfiltrated, func, Context);
}
[Desc("Call a function when this actor is discovered by an enemy or a player with a Neutral stance. " +
"The callback function will be called as func(Actor discovered, Player discoverer)")]
public void OnDiscovered(Actor a, LuaFunction func)
{
GetScriptTriggers(a).RegisterCallback(Trigger.OnDiscovered, func, Context);
}
[Desc("Call a function when this player is discovered by an enemy or neutral player. " +
"The callback function will be called as func(Player discovered, Player discoverer, Actor discoveredActor)")]
public void OnPlayerDiscovered(Player discovered, LuaFunction func)
{
GetScriptTriggers(discovered.PlayerActor).RegisterCallback(Trigger.OnPlayerDiscovered, func, Context);
}
[Desc("Removes all triggers from this actor." +
"Note that the removal will only take effect at the end of a tick, " +
"so you must not add new triggers at the same time that you are calling this function.")]
public void ClearAll(Actor a)
{
GetScriptTriggers(a).ClearAll();
}
[Desc("Removes the specified trigger from this actor." +
"Note that the removal will only take effect at the end of a tick, " +
"so you must not add new triggers at the same time that you are calling this function.")]
public void Clear(Actor a, string triggerName)
{
var trigger = (Trigger)Enum.Parse(typeof(Trigger), triggerName);
GetScriptTriggers(a).Clear(trigger);
}
}
}