1 #region Copyright & License Information
2 /*
3  * Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4  * This file is part of OpenRA, which is free software. It is made
5  * available to you under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, either version 3 of
7  * the License, or (at your option) any later version. For more
8  * information, see COPYING.
9  */
10 #endregion
11 
12 using System.Linq;
13 using Eluant;
14 using OpenRA.Mods.Common.Traits;
15 using OpenRA.Scripting;
16 
17 namespace OpenRA.Mods.Common.Scripting
18 {
19 	[ScriptGlobal("Map")]
20 	public class MapGlobal : ScriptGlobal
21 	{
22 		readonly SpawnMapActors sma;
23 		readonly World world;
24 
MapGlobal(ScriptContext context)25 		public MapGlobal(ScriptContext context)
26 			: base(context)
27 		{
28 			sma = context.World.WorldActor.Trait<SpawnMapActors>();
29 			world = context.World;
30 
31 			// Register map actors as globals (yuck!)
32 			foreach (var kv in sma.Actors)
33 				context.RegisterMapActor(kv.Key, kv.Value);
34 		}
35 
36 		[Desc("Returns a table of all actors within the requested region, filtered using the specified function.")]
ActorsInCircle(WPos location, WDist radius, LuaFunction filter = null)37 		public Actor[] ActorsInCircle(WPos location, WDist radius, LuaFunction filter = null)
38 		{
39 			var actors = Context.World.FindActorsInCircle(location, radius);
40 			return FilteredObjects(actors, filter).ToArray();
41 		}
42 
43 		[Desc("Returns a table of all actors within the requested rectangle, filtered using the specified function.")]
ActorsInBox(WPos topLeft, WPos bottomRight, LuaFunction filter = null)44 		public Actor[] ActorsInBox(WPos topLeft, WPos bottomRight, LuaFunction filter = null)
45 		{
46 			var actors = Context.World.ActorMap.ActorsInBox(topLeft, bottomRight);
47 			return FilteredObjects(actors, filter).ToArray();
48 		}
49 
50 		[Desc("Returns the location of the top-left corner of the map (assuming zero terrain height).")]
51 		public WPos TopLeft
52 		{
53 			get
54 			{
55 				// HACK: This api method abuses the coordinate system, and should be removed
56 				// in favour of proper actor queries.  See #8549.
57 				return Context.World.Map.ProjectedTopLeft;
58 			}
59 		}
60 
61 		[Desc("Returns the location of the bottom-right corner of the map (assuming zero terrain height).")]
62 		public WPos BottomRight
63 		{
64 			get
65 			{
66 				// HACK: This api method abuses the coordinate system, and should be removed
67 				// in favour of proper actor queries.  See #8549.
68 				return Context.World.Map.ProjectedBottomRight;
69 			}
70 		}
71 
72 		[Desc("Returns a random cell inside the visible region of the map.")]
RandomCell()73 		public CPos RandomCell()
74 		{
75 			return Context.World.Map.ChooseRandomCell(Context.World.SharedRandom);
76 		}
77 
78 		[Desc("Returns a random cell on the visible border of the map.")]
RandomEdgeCell()79 		public CPos RandomEdgeCell()
80 		{
81 			return Context.World.Map.ChooseRandomEdgeCell(Context.World.SharedRandom);
82 		}
83 
84 		[Desc("Returns the closest cell on the visible border of the map from the given cell.")]
ClosestEdgeCell(CPos givenCell)85 		public CPos ClosestEdgeCell(CPos givenCell)
86 		{
87 			return Context.World.Map.ChooseClosestEdgeCell(givenCell);
88 		}
89 
90 		[Desc("Returns the first cell on the visible border of the map from the given cell,",
91 			"matching the filter function called as function(CPos cell).")]
ClosestMatchingEdgeCell(CPos givenCell, LuaFunction filter)92 		public CPos ClosestMatchingEdgeCell(CPos givenCell, LuaFunction filter)
93 		{
94 			return FilteredObjects(Context.World.Map.AllEdgeCells.OrderBy(c => (givenCell - c).Length), filter).FirstOrDefault();
95 		}
96 
97 		[Desc("Returns the center of a cell in world coordinates.")]
CenterOfCell(CPos cell)98 		public WPos CenterOfCell(CPos cell)
99 		{
100 			return Context.World.Map.CenterOfCell(cell);
101 		}
102 
103 		[Desc("Returns the type of the terrain at the target cell.")]
TerrainType(CPos cell)104 		public string TerrainType(CPos cell)
105 		{
106 			return Context.World.Map.GetTerrainInfo(cell).Type;
107 		}
108 
109 		[Desc("Returns true if there is only one human player.")]
110 		public bool IsSinglePlayer { get { return Context.World.LobbyInfo.NonBotPlayers.Count() == 1; } }
111 
112 		[Desc("Returns the value of a `ScriptLobbyDropdown` selected in the game lobby.")]
LobbyOption(string id)113 		public LuaValue LobbyOption(string id)
114 		{
115 			var option = Context.World.WorldActor.TraitsImplementing<ScriptLobbyDropdown>()
116 				.FirstOrDefault(sld => sld.Info.ID == id);
117 
118 			if (option == null)
119 				throw new YamlException("A ScriptLobbyDropdown with ID `" + id + "` was not found.");
120 
121 			return option.Value;
122 		}
123 
124 		[Desc("Returns a table of all the actors that were specified in the map file.")]
125 		public Actor[] NamedActors { get { return sma.Actors.Values.ToArray(); } }
126 
127 		[Desc("Returns the actor that was specified with a given name in " +
128 			"the map file (or nil, if the actor is dead or not found).")]
NamedActor(string actorName)129 		public Actor NamedActor(string actorName)
130 		{
131 			Actor ret;
132 
133 			if (!sma.Actors.TryGetValue(actorName, out ret))
134 				return null;
135 
136 			if (ret.Disposed)
137 				return null;
138 
139 			return ret;
140 		}
141 
142 		[Desc("Returns true if actor was originally specified in the map file.")]
IsNamedActor(Actor actor)143 		public bool IsNamedActor(Actor actor)
144 		{
145 			return actor.ActorID <= sma.LastMapActorID && actor.ActorID > sma.LastMapActorID - sma.Actors.Count;
146 		}
147 
148 		[Desc("Returns a table of all actors tagged with the given string.")]
ActorsWithTag(string tag)149 		public Actor[] ActorsWithTag(string tag)
150 		{
151 			return Context.World.ActorsHavingTrait<ScriptTags>(t => t.HasTag(tag)).ToArray();
152 		}
153 
154 		[Desc("Returns a table of all the actors that are currently on the map/in the world.")]
155 		public Actor[] ActorsInWorld { get { return world.Actors.ToArray(); } }
156 	}
157 }
158