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;
13 using System.Collections.Generic;
14 using System.Diagnostics.CodeAnalysis;
15 using OpenRA.Activities;
16 using OpenRA.FileSystem;
17 using OpenRA.GameRules;
18 using OpenRA.Graphics;
19 using OpenRA.Network;
20 using OpenRA.Primitives;
21 
22 namespace OpenRA.Traits
23 {
24 	public sealed class RequireExplicitImplementationAttribute : Attribute { }
25 
26 	[Flags]
27 	public enum DamageState
28 	{
29 		Undamaged = 1,
30 		Light = 2,
31 		Medium = 4,
32 		Heavy = 8,
33 		Critical = 16,
34 		Dead = 32
35 	}
36 
37 	// NOTE: Each subsequent category is a superset of the previous categories
38 	// and categories are mutually exclusive.
39 	public enum BlockedByActor
40 	{
41 		None,
42 		Immovable,
43 		Stationary,
44 		All
45 	}
46 
47 	/// <summary>
48 	/// Type tag for DamageTypes <see cref="Primitives.BitSet{T}"/>.
49 	/// </summary>
DamageType()50 	public sealed class DamageType { DamageType() { } }
51 
52 	public interface IHealthInfo : ITraitInfo
53 	{
54 		int MaxHP { get; }
55 	}
56 
57 	public interface IHealth
58 	{
59 		DamageState DamageState { get; }
60 		int HP { get; }
61 		int MaxHP { get; }
62 		int DisplayHP { get; }
63 		bool IsDead { get; }
64 
InflictDamage(Actor self, Actor attacker, Damage damage, bool ignoreModifiers)65 		void InflictDamage(Actor self, Actor attacker, Damage damage, bool ignoreModifiers);
Kill(Actor self, Actor attacker, BitSet<DamageType> damageTypes)66 		void Kill(Actor self, Actor attacker, BitSet<DamageType> damageTypes);
67 	}
68 
69 	// depends on the order of pips in WorldRenderer.cs!
70 	public enum PipType { Transparent, Green, Yellow, Red, Gray, Blue, Ammo, AmmoEmpty }
71 
72 	[Flags]
73 	public enum Stance
74 	{
75 		None = 0,
76 		Enemy = 1,
77 		Neutral = 2,
78 		Ally = 4,
79 	}
80 
81 	public static class StanceExts
82 	{
HasStance(this Stance s, Stance stance)83 		public static bool HasStance(this Stance s, Stance stance)
84 		{
85 			// PERF: Enum.HasFlag is slower and requires allocations.
86 			return (s & stance) == stance;
87 		}
88 	}
89 
90 	public class AttackInfo
91 	{
92 		public Damage Damage;
93 		public Actor Attacker;
94 		public DamageState DamageState;
95 		public DamageState PreviousDamageState;
96 	}
97 
98 	public class Damage
99 	{
100 		public readonly int Value;
101 		public readonly BitSet<DamageType> DamageTypes;
102 
Damage(int damage, BitSet<DamageType> damageTypes)103 		public Damage(int damage, BitSet<DamageType> damageTypes)
104 		{
105 			Value = damage;
106 			DamageTypes = damageTypes;
107 		}
108 
Damage(int damage)109 		public Damage(int damage)
110 		{
111 			Value = damage;
112 			DamageTypes = default(BitSet<DamageType>);
113 		}
114 	}
115 
116 	[RequireExplicitImplementation]
Tick(Actor self)117 	public interface ITick { void Tick(Actor self); }
118 	[RequireExplicitImplementation]
TickRender(WorldRenderer wr, Actor self)119 	public interface ITickRender { void TickRender(WorldRenderer wr, Actor self); }
120 	public interface IRender
121 	{
Render(Actor self, WorldRenderer wr)122 		IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr);
ScreenBounds(Actor self, WorldRenderer wr)123 		IEnumerable<Rectangle> ScreenBounds(Actor self, WorldRenderer wr);
124 	}
125 
126 	// TODO: Replace Rectangle with an int2[] polygon
MouseoverBounds(Actor self, WorldRenderer wr)127 	public interface IMouseBounds { Rectangle MouseoverBounds(Actor self, WorldRenderer wr); }
128 	public interface IMouseBoundsInfo : ITraitInfoInterface { }
AutoMouseoverBounds(Actor self, WorldRenderer wr)129 	public interface IAutoMouseBounds { Rectangle AutoMouseoverBounds(Actor self, WorldRenderer wr); }
130 
131 	// HACK: This provides a shim for legacy code until it can be rewritten
DecorationBounds(Actor self, WorldRenderer wr)132 	public interface IDecorationBounds { Rectangle DecorationBounds(Actor self, WorldRenderer wr); }
133 	public interface IDecorationBoundsInfo : ITraitInfoInterface { }
134 	public static class DecorationBoundsExtensions
135 	{
FirstNonEmptyBounds(this IEnumerable<IDecorationBounds> decorationBounds, Actor self, WorldRenderer wr)136 		public static Rectangle FirstNonEmptyBounds(this IEnumerable<IDecorationBounds> decorationBounds, Actor self, WorldRenderer wr)
137 		{
138 			// PERF: Avoid LINQ.
139 			foreach (var decoration in decorationBounds)
140 			{
141 				var bounds = decoration.DecorationBounds(self, wr);
142 				if (!bounds.IsEmpty)
143 					return bounds;
144 			}
145 
146 			return Rectangle.Empty;
147 		}
148 
FirstNonEmptyBounds(this IDecorationBounds[] decorationBounds, Actor self, WorldRenderer wr)149 		public static Rectangle FirstNonEmptyBounds(this IDecorationBounds[] decorationBounds, Actor self, WorldRenderer wr)
150 		{
151 			// PERF: Avoid LINQ.
152 			foreach (var decoration in decorationBounds)
153 			{
154 				var bounds = decoration.DecorationBounds(self, wr);
155 				if (!bounds.IsEmpty)
156 					return bounds;
157 			}
158 
159 			return Rectangle.Empty;
160 		}
161 	}
162 
163 	public interface IIssueOrder
164 	{
165 		IEnumerable<IOrderTargeter> Orders { get; }
IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)166 		Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued);
167 	}
168 
169 	[Flags]
170 	public enum TargetModifiers { None = 0, ForceAttack = 1, ForceQueue = 2, ForceMove = 4 }
171 
172 	public static class TargetModifiersExts
173 	{
HasModifier(this TargetModifiers self, TargetModifiers m)174 		public static bool HasModifier(this TargetModifiers self, TargetModifiers m)
175 		{
176 			// PERF: Enum.HasFlag is slower and requires allocations.
177 			return (self & m) == m;
178 		}
179 	}
180 
181 	public interface IOrderTargeter
182 	{
183 		string OrderID { get; }
184 		int OrderPriority { get; }
CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor)185 		bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, ref TargetModifiers modifiers, ref string cursor);
186 		bool IsQueued { get; }
TargetOverridesSelection(Actor self, Target target, List<Actor> actorsAt, CPos xy, TargetModifiers modifiers)187 		bool TargetOverridesSelection(Actor self, Target target, List<Actor> actorsAt, CPos xy, TargetModifiers modifiers);
188 	}
189 
ResolveOrder(Actor self, Order order)190 	public interface IResolveOrder { void ResolveOrder(Actor self, Order order); }
OrderValidation(OrderManager orderManager, World world, int clientId, Order order)191 	public interface IValidateOrder { bool OrderValidation(OrderManager orderManager, World world, int clientId, Order order); }
VoicePhraseForOrder(Actor self, Order order)192 	public interface IOrderVoice { string VoicePhraseForOrder(Actor self, Order order); }
193 
194 	[RequireExplicitImplementation]
Created(Actor self)195 	public interface INotifyCreated { void Created(Actor self); }
196 
197 	[RequireExplicitImplementation]
AddedToWorld(Actor self)198 	public interface INotifyAddedToWorld { void AddedToWorld(Actor self); }
199 	[RequireExplicitImplementation]
RemovedFromWorld(Actor self)200 	public interface INotifyRemovedFromWorld { void RemovedFromWorld(Actor self); }
201 
202 	[RequireExplicitImplementation]
Disposing(Actor self)203 	public interface INotifyActorDisposing { void Disposing(Actor self); }
OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)204 	public interface INotifyOwnerChanged { void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner); }
OnEffectiveOwnerChanged(Actor self, Player oldEffectiveOwner, Player newEffectiveOwner)205 	public interface INotifyEffectiveOwnerChanged { void OnEffectiveOwnerChanged(Actor self, Player oldEffectiveOwner, Player newEffectiveOwner); }
OnOwnerLost(Actor self)206 	public interface INotifyOwnerLost { void OnOwnerLost(Actor self); }
207 
208 	[RequireExplicitImplementation]
209 	public interface IVoiced
210 	{
211 		string VoiceSet { get; }
PlayVoice(Actor self, string phrase, string variant)212 		bool PlayVoice(Actor self, string phrase, string variant);
PlayVoiceLocal(Actor self, string phrase, string variant, float volume)213 		bool PlayVoiceLocal(Actor self, string phrase, string variant, float volume);
HasVoice(Actor self, string voice)214 		bool HasVoice(Actor self, string voice);
215 	}
216 
217 	[RequireExplicitImplementation]
218 	public interface IStoreResources { int Capacity { get; } }
219 
220 	public interface IEffectiveOwner
221 	{
222 		bool Disguised { get; }
223 		Player Owner { get; }
224 	}
225 
226 	public interface ITooltip
227 	{
228 		ITooltipInfo TooltipInfo { get; }
229 		Player Owner { get; }
230 	}
231 
232 	public interface ITooltipInfo : ITraitInfoInterface
233 	{
TooltipForPlayerStance(Stance stance)234 		string TooltipForPlayerStance(Stance stance);
235 		bool IsOwnerRowVisible { get; }
236 	}
237 
238 	public interface IProvideTooltipInfo
239 	{
IsTooltipVisible(Player forPlayer)240 		bool IsTooltipVisible(Player forPlayer);
241 		string TooltipText { get; }
242 	}
243 
244 	public interface IDisabledTrait { bool IsTraitDisabled { get; } }
245 
246 	public interface IDefaultVisibilityInfo : ITraitInfoInterface { }
IsVisible(Actor self, Player byPlayer)247 	public interface IDefaultVisibility { bool IsVisible(Actor self, Player byPlayer); }
IsVisible(Actor self, Player byPlayer)248 	public interface IVisibilityModifier { bool IsVisible(Actor self, Player byPlayer); }
249 
250 	public interface IActorMap
251 	{
GetActorsAt(CPos a)252 		IEnumerable<Actor> GetActorsAt(CPos a);
GetActorsAt(CPos a, SubCell sub)253 		IEnumerable<Actor> GetActorsAt(CPos a, SubCell sub);
HasFreeSubCell(CPos cell, bool checkTransient = true)254 		bool HasFreeSubCell(CPos cell, bool checkTransient = true);
FreeSubCell(CPos cell, SubCell preferredSubCell = SubCell.Any, bool checkTransient = true)255 		SubCell FreeSubCell(CPos cell, SubCell preferredSubCell = SubCell.Any, bool checkTransient = true);
FreeSubCell(CPos cell, SubCell preferredSubCell, Func<Actor, bool> checkIfBlocker)256 		SubCell FreeSubCell(CPos cell, SubCell preferredSubCell, Func<Actor, bool> checkIfBlocker);
AnyActorsAt(CPos a)257 		bool AnyActorsAt(CPos a);
AnyActorsAt(CPos a, SubCell sub, bool checkTransient = true)258 		bool AnyActorsAt(CPos a, SubCell sub, bool checkTransient = true);
AnyActorsAt(CPos a, SubCell sub, Func<Actor, bool> withCondition)259 		bool AnyActorsAt(CPos a, SubCell sub, Func<Actor, bool> withCondition);
AddInfluence(Actor self, IOccupySpace ios)260 		void AddInfluence(Actor self, IOccupySpace ios);
RemoveInfluence(Actor self, IOccupySpace ios)261 		void RemoveInfluence(Actor self, IOccupySpace ios);
AddCellTrigger(CPos[] cells, Action<Actor> onEntry, Action<Actor> onExit)262 		int AddCellTrigger(CPos[] cells, Action<Actor> onEntry, Action<Actor> onExit);
RemoveCellTrigger(int id)263 		void RemoveCellTrigger(int id);
AddProximityTrigger(WPos pos, WDist range, WDist vRange, Action<Actor> onEntry, Action<Actor> onExit)264 		int AddProximityTrigger(WPos pos, WDist range, WDist vRange, Action<Actor> onEntry, Action<Actor> onExit);
RemoveProximityTrigger(int id)265 		void RemoveProximityTrigger(int id);
UpdateProximityTrigger(int id, WPos newPos, WDist newRange, WDist newVRange)266 		void UpdateProximityTrigger(int id, WPos newPos, WDist newRange, WDist newVRange);
AddPosition(Actor a, IOccupySpace ios)267 		void AddPosition(Actor a, IOccupySpace ios);
RemovePosition(Actor a, IOccupySpace ios)268 		void RemovePosition(Actor a, IOccupySpace ios);
UpdatePosition(Actor a, IOccupySpace ios)269 		void UpdatePosition(Actor a, IOccupySpace ios);
ActorsInBox(WPos a, WPos b)270 		IEnumerable<Actor> ActorsInBox(WPos a, WPos b);
271 
272 		WDist LargestActorRadius { get; }
273 		WDist LargestBlockingActorRadius { get; }
274 
UpdateOccupiedCells(IOccupySpace ios)275 		void UpdateOccupiedCells(IOccupySpace ios);
276 		event Action<CPos> CellUpdated;
277 	}
278 
279 	[RequireExplicitImplementation]
280 	public interface IRenderModifier
281 	{
ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r)282 		IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r);
283 
284 		// HACK: This is here to support the WithShadow trait.
285 		// That trait should be rewritten using standard techniques, and then this interface method removed
ModifyScreenBounds(Actor self, WorldRenderer wr, IEnumerable<Rectangle> r)286 		IEnumerable<Rectangle> ModifyScreenBounds(Actor self, WorldRenderer wr, IEnumerable<Rectangle> r);
287 	}
288 
289 	[RequireExplicitImplementation]
290 	public interface IProvidesCursorPaletteInfo : ITraitInfoInterface
291 	{
292 		string Palette { get; }
ReadPalette(IReadOnlyFileSystem fileSystem)293 		ImmutablePalette ReadPalette(IReadOnlyFileSystem fileSystem);
294 	}
295 
LoadPalettes(WorldRenderer wr)296 	public interface ILoadsPalettes { void LoadPalettes(WorldRenderer wr); }
LoadPlayerPalettes(WorldRenderer wr, string playerName, Color playerColor, bool replaceExisting)297 	public interface ILoadsPlayerPalettes { void LoadPlayerPalettes(WorldRenderer wr, string playerName, Color playerColor, bool replaceExisting); }
AdjustPalette(IReadOnlyDictionary<string, MutablePalette> b)298 	public interface IPaletteModifier { void AdjustPalette(IReadOnlyDictionary<string, MutablePalette> b); }
GetPips(Actor self)299 	public interface IPips { IEnumerable<PipType> GetPips(Actor self); }
300 
301 	[RequireExplicitImplementation]
GetColor()302 	public interface ISelectionBar { float GetValue(); Color GetColor(); bool DisplayWhenEmpty { get; } }
303 
DrawRollover(Actor self, WorldRenderer worldRenderer)304 	public interface ISelectionDecorations { void DrawRollover(Actor self, WorldRenderer worldRenderer); }
305 
306 	public interface IMapPreviewSignatureInfo : ITraitInfoInterface
307 	{
PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<Pair<MPos, Color>> destinationBuffer)308 		void PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<Pair<MPos, Color>> destinationBuffer);
309 	}
310 
311 	public interface IOccupySpaceInfo : ITraitInfoInterface
312 	{
OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any)313 		IReadOnlyDictionary<CPos, SubCell> OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any);
314 		bool SharesCell { get; }
315 	}
316 
317 	public interface IOccupySpace
318 	{
319 		WPos CenterPosition { get; }
320 		CPos TopLeft { get; }
OccupiedCells()321 		Pair<CPos, SubCell>[] OccupiedCells();
322 	}
323 
324 	public enum SubCell : byte { Invalid = byte.MaxValue, Any = byte.MaxValue - 1, FullCell = 0, First = 1 }
325 
326 	public interface IPositionableInfo : IOccupySpaceInfo
327 	{
CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)328 		bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All);
329 	}
330 
331 	public interface IPositionable : IOccupySpace
332 	{
CanExistInCell(CPos location)333 		bool CanExistInCell(CPos location);
IsLeavingCell(CPos location, SubCell subCell = SubCell.Any)334 		bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any);
CanEnterCell(CPos location, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)335 		bool CanEnterCell(CPos location, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All);
GetValidSubCell(SubCell preferred = SubCell.Any)336 		SubCell GetValidSubCell(SubCell preferred = SubCell.Any);
GetAvailableSubCell(CPos location, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)337 		SubCell GetAvailableSubCell(CPos location, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All);
SetPosition(Actor self, CPos cell, SubCell subCell = SubCell.Any)338 		void SetPosition(Actor self, CPos cell, SubCell subCell = SubCell.Any);
SetPosition(Actor self, WPos pos)339 		void SetPosition(Actor self, WPos pos);
SetVisualPosition(Actor self, WPos pos)340 		void SetVisualPosition(Actor self, WPos pos);
341 	}
342 
343 	public interface ITemporaryBlockerInfo : ITraitInfoInterface { }
344 
345 	[RequireExplicitImplementation]
346 	public interface ITemporaryBlocker
347 	{
CanRemoveBlockage(Actor self, Actor blocking)348 		bool CanRemoveBlockage(Actor self, Actor blocking);
IsBlocking(Actor self, CPos cell)349 		bool IsBlocking(Actor self, CPos cell);
350 	}
351 
352 	public interface IFacing
353 	{
354 		int TurnSpeed { get; }
355 		int Facing { get; set; }
356 	}
357 
GetInitialFacing()358 	public interface IFacingInfo : ITraitInfoInterface { int GetInitialFacing(); }
359 
360 	public interface ITraitInfoInterface { }
Create(ActorInitializer init)361 	public interface ITraitInfo : ITraitInfoInterface { object Create(ActorInitializer init); }
362 
Create(ActorInitializer init)363 	public class TraitInfo<T> : ITraitInfo where T : new() { public virtual object Create(ActorInitializer init) { return new T(); } }
364 	public interface ILobbyCustomRulesIgnore { }
365 
366 	[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1302:InterfaceNamesMustBeginWithI", Justification = "Not a real interface, but more like a tag.")]
367 	public interface Requires<T> where T : class, ITraitInfoInterface { }
368 
369 	public interface IActivityInterface { }
370 
371 	[RequireExplicitImplementation]
Selected(Actor self)372 	public interface INotifySelected { void Selected(Actor self); }
373 	[RequireExplicitImplementation]
SelectionChanged()374 	public interface INotifySelection { void SelectionChanged(); }
375 
WorldLoaded(World w, WorldRenderer wr)376 	public interface IWorldLoaded { void WorldLoaded(World w, WorldRenderer wr); }
GameLoading(World w)377 	public interface INotifyGameLoading { void GameLoading(World w); }
GameLoaded(World w)378 	public interface INotifyGameLoaded { void GameLoaded(World w); }
GameSaved(World w)379 	public interface INotifyGameSaved { void GameSaved(World w); }
380 
381 	public interface IGameSaveTraitData
382 	{
IssueTraitData(Actor self)383 		List<MiniYamlNode> IssueTraitData(Actor self);
ResolveTraitData(Actor self, List<MiniYamlNode> data)384 		void ResolveTraitData(Actor self, List<MiniYamlNode> data);
385 	}
386 
387 	[RequireExplicitImplementation]
CreatePlayers(World w)388 	public interface ICreatePlayers { void CreatePlayers(World w); }
389 
390 	public interface IBotInfo : ITraitInfoInterface
391 	{
392 		string Type { get; }
393 		string Name { get; }
394 	}
395 
396 	public interface IBot
397 	{
Activate(Player p)398 		void Activate(Player p);
QueueOrder(Order order)399 		void QueueOrder(Order order);
400 		IBotInfo Info { get; }
401 		Player Player { get; }
402 	}
403 
404 	[RequireExplicitImplementation]
Render(WorldRenderer wr)405 	public interface IRenderOverlay { void Render(WorldRenderer wr); }
406 
407 	[RequireExplicitImplementation]
OnBecomingIdle(Actor self)408 	public interface INotifyBecomingIdle { void OnBecomingIdle(Actor self); }
409 
410 	[RequireExplicitImplementation]
TickIdle(Actor self)411 	public interface INotifyIdle { void TickIdle(Actor self); }
412 
RenderAboveWorld(Actor self, WorldRenderer wr)413 	public interface IRenderAboveWorld { void RenderAboveWorld(Actor self, WorldRenderer wr); }
RenderShroud(WorldRenderer wr)414 	public interface IRenderShroud { void RenderShroud(WorldRenderer wr); }
415 
416 	[RequireExplicitImplementation]
RenderTerrain(WorldRenderer wr, Viewport viewport)417 	public interface IRenderTerrain { void RenderTerrain(WorldRenderer wr, Viewport viewport); }
418 
419 	public interface IRenderAboveShroud
420 	{
RenderAboveShroud(Actor self, WorldRenderer wr)421 		IEnumerable<IRenderable> RenderAboveShroud(Actor self, WorldRenderer wr);
422 		bool SpatiallyPartitionable { get; }
423 	}
424 
425 	public interface IRenderAboveShroudWhenSelected
426 	{
RenderAboveShroud(Actor self, WorldRenderer wr)427 		IEnumerable<IRenderable> RenderAboveShroud(Actor self, WorldRenderer wr);
428 		bool SpatiallyPartitionable { get; }
429 	}
430 
431 	public interface IRenderAnnotations
432 	{
RenderAnnotations(Actor self, WorldRenderer wr)433 		IEnumerable<IRenderable> RenderAnnotations(Actor self, WorldRenderer wr);
434 		bool SpatiallyPartitionable { get; }
435 	}
436 
437 	public interface IRenderAnnotationsWhenSelected
438 	{
RenderAnnotations(Actor self, WorldRenderer wr)439 		IEnumerable<IRenderable> RenderAnnotations(Actor self, WorldRenderer wr);
440 		bool SpatiallyPartitionable { get; }
441 	}
442 
443 	public interface ISelection
444 	{
445 		int Hash { get; }
446 		IEnumerable<Actor> Actors { get; }
447 
Add(Actor a)448 		void Add(Actor a);
Remove(Actor a)449 		void Remove(Actor a);
Contains(Actor a)450 		bool Contains(Actor a);
Combine(World world, IEnumerable<Actor> newSelection, bool isCombine, bool isClick)451 		void Combine(World world, IEnumerable<Actor> newSelection, bool isCombine, bool isClick);
Clear()452 		void Clear();
DoControlGroup(World world, WorldRenderer worldRenderer, int group, Modifiers mods, int multiTapCount)453 		void DoControlGroup(World world, WorldRenderer worldRenderer, int group, Modifiers mods, int multiTapCount);
AddToControlGroup(Actor a, int group)454 		void AddToControlGroup(Actor a, int group);
RemoveFromControlGroup(Actor a)455 		void RemoveFromControlGroup(Actor a);
GetControlGroupForActor(Actor a)456 		int? GetControlGroupForActor(Actor a);
457 	}
458 
459 	/// <summary>
460 	/// Indicates target types as defined on <see cref="Traits.ITargetable"/> are present in a <see cref="Primitives.BitSet{T}"/>.
461 	/// </summary>
TargetableType()462 	public sealed class TargetableType { TargetableType() { } }
463 
464 	public interface ITargetableInfo : ITraitInfoInterface
465 	{
GetTargetTypes()466 		BitSet<TargetableType> GetTargetTypes();
467 	}
468 
469 	public interface ITargetable
470 	{
471 		// Check IsTraitEnabled or !IsTraitDisabled first
472 		BitSet<TargetableType> TargetTypes { get; }
TargetableBy(Actor self, Actor byActor)473 		bool TargetableBy(Actor self, Actor byActor);
474 		bool RequiresForceFire { get; }
475 	}
476 
477 	[RequireExplicitImplementation]
478 	public interface ITargetablePositions
479 	{
TargetablePositions(Actor self)480 		IEnumerable<WPos> TargetablePositions(Actor self);
481 		bool AlwaysEnabled { get; }
482 	}
483 
484 	public interface IMoveInfo : ITraitInfoInterface { }
485 
486 	[RequireExplicitImplementation]
GameOver(World world)487 	public interface IGameOver { void GameOver(World world); }
488 
489 	public interface IWarhead
490 	{
491 		int Delay { get; }
IsValidAgainst(Actor victim, Actor firedBy)492 		bool IsValidAgainst(Actor victim, Actor firedBy);
IsValidAgainst(FrozenActor victim, Actor firedBy)493 		bool IsValidAgainst(FrozenActor victim, Actor firedBy);
DoImpact(Target target, WarheadArgs args)494 		void DoImpact(Target target, WarheadArgs args);
495 	}
496 
RulesetLoaded(Ruleset rules, TInfo info)497 	public interface IRulesetLoaded<TInfo> { void RulesetLoaded(Ruleset rules, TInfo info); }
498 	public interface IRulesetLoaded : IRulesetLoaded<ActorInfo>, ITraitInfoInterface { }
499 
500 	[RequireExplicitImplementation]
501 	public interface ILobbyOptions : ITraitInfoInterface
502 	{
LobbyOptions(Ruleset rules)503 		IEnumerable<LobbyOption> LobbyOptions(Ruleset rules);
504 	}
505 
506 	public class LobbyOption
507 	{
508 		public readonly string Id;
509 		public readonly string Name;
510 		public readonly string Description;
511 		public readonly IReadOnlyDictionary<string, string> Values;
512 		public readonly string DefaultValue;
513 		public readonly bool IsLocked;
514 		public readonly bool IsVisible;
515 		public readonly int DisplayOrder;
516 
LobbyOption(string id, string name, string description, bool visible, int displayorder, IReadOnlyDictionary<string, string> values, string defaultValue, bool locked)517 		public LobbyOption(string id, string name, string description, bool visible, int displayorder,
518 			IReadOnlyDictionary<string, string> values, string defaultValue, bool locked)
519 		{
520 			Id = id;
521 			Name = name;
522 			Description = description;
523 			IsVisible = visible;
524 			DisplayOrder = displayorder;
525 			Values = values;
526 			DefaultValue = defaultValue;
527 			IsLocked = locked;
528 		}
529 
ValueChangedMessage(string playerName, string newValue)530 		public virtual string ValueChangedMessage(string playerName, string newValue)
531 		{
532 			return playerName + " changed " + Name + " to " + Values[newValue] + ".";
533 		}
534 	}
535 
536 	public class LobbyBooleanOption : LobbyOption
537 	{
538 		static readonly Dictionary<string, string> BoolValues = new Dictionary<string, string>()
539 		{
540 			{ true.ToString(), "enabled" },
541 			{ false.ToString(), "disabled" }
542 		};
543 
LobbyBooleanOption(string id, string name, string description, bool visible, int displayorder, bool defaultValue, bool locked)544 		public LobbyBooleanOption(string id, string name, string description, bool visible, int displayorder, bool defaultValue, bool locked)
545 			: base(id, name, description, visible, displayorder, new ReadOnlyDictionary<string, string>(BoolValues), defaultValue.ToString(), locked) { }
546 
ValueChangedMessage(string playerName, string newValue)547 		public override string ValueChangedMessage(string playerName, string newValue)
548 		{
549 			return playerName + " " + BoolValues[newValue] + " " + Name + ".";
550 		}
551 	}
552 
553 	[RequireExplicitImplementation]
554 	public interface IUnlocksRenderPlayer { bool RenderPlayerUnlocked { get; } }
555 
556 	[RequireExplicitImplementation]
GetCreationActivity()557 	public interface ICreationActivity { Activity GetCreationActivity(); }
558 }
559