Client LuaCsForBarotrauma
SpawnAction.cs
2 using Microsoft.Xna.Framework;
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 
7 namespace Barotrauma
8 {
13  {
14  public enum SpawnLocationType
15  {
16  Any,
17  MainSub,
18  Outpost,
19  MainPath,
20  Cave,
21  AbyssCave,
22  Ruin,
23  Wreck,
25  NearMainSub
26  }
27 
28  [Serialize("", IsPropertySaveable.Yes, description: "Species name of the character to spawn.")]
29  public Identifier SpeciesName { get; set; }
30 
31  [Serialize("", IsPropertySaveable.Yes, description: "Identifier of the NPC set to choose from.")]
32  public Identifier NPCSetIdentifier { get; set; }
33 
34  [Serialize("", IsPropertySaveable.Yes, description: "Identifier of the NPC.")]
35  public Identifier NPCIdentifier { get; set; }
36 
37  [Serialize(true, IsPropertySaveable.Yes, description: "Should taking the items of this npc be considered as stealing?")]
38  public bool LootingIsStealing { get; set; }
39 
40  [Serialize("", IsPropertySaveable.Yes, description: "Identifier of the item to spawn.")]
41  public Identifier ItemIdentifier { get; set; }
42 
43  [Serialize("", IsPropertySaveable.Yes, description: "Tag of the item to spawn.")]
44  public Identifier ItemTag { get; set; }
45 
46  [Serialize("", IsPropertySaveable.Yes, description: "The spawned entity will be assigned this tag. The tag can be used to refer to the entity by other actions of the event.")]
47  public Identifier TargetTag { get; set; }
48 
49  [Serialize("", IsPropertySaveable.Yes, description: "Tag of an entity with an inventory to spawn the item into.")]
50  public Identifier TargetInventory { get; set; }
51 
52  [Serialize(SpawnLocationType.Any, IsPropertySaveable.Yes, description: "Where should the entity spawn? This can be restricted further with the other spawn point options.")]
53  public SpawnLocationType SpawnLocation { get; set; }
54 
55  [Serialize(SpawnType.Human, IsPropertySaveable.Yes, description: "Type of spawnpoint to spawn the entity at. Ignored if SpawnPointTag is set.")]
56  public SpawnType SpawnPointType { get; set; }
57 
58  [Serialize("", IsPropertySaveable.Yes, description: "Tag of a spawnpoint to spawn the entity at.")]
59  public Identifier SpawnPointTag { get; set; }
60 
61  [Serialize(CharacterTeamType.FriendlyNPC, IsPropertySaveable.Yes, description: "Team of the NPC to spawn. Only valid when spawning a character.")]
62  public CharacterTeamType TeamID { get; protected set; }
63 
64  [Serialize(false, IsPropertySaveable.Yes, description: "Should we spawn the entity even when no spawn points with matching tags were found?")]
65  public bool RequireSpawnPointTag { get; set; }
66 
67  private readonly HashSet<Identifier> targetModuleTags = new HashSet<Identifier>();
68 
69  [Serialize(true, IsPropertySaveable.Yes, description: "If false, we won't spawn another character if one with the same identifier has already been spawned.")]
70  public bool AllowDuplicates { get; set; }
71 
72  [Serialize(1, IsPropertySaveable.Yes, description: "Number of entities to spawn.")]
73  public int Amount { get; set; }
74 
75  [Serialize(true, IsPropertySaveable.Yes, description: "Should the item be spawned even if the target inventory is full (just spawning it at the position of the target)? Only valid if spawning an item in an inventory.")]
76  public bool SpawnIfInventoryFull { get; set; }
77 
78  [Serialize(100.0f, IsPropertySaveable.Yes, description: "Random offset to add to the spawn position.")]
79  public float Offset { get; set; }
80 
81  [Serialize("", IsPropertySaveable.Yes, "What outpost module tags does the entity prefer to spawn in.")]
82  public string TargetModuleTags
83  {
84  get => string.Join(",", targetModuleTags);
85  set
86  {
87  targetModuleTags.Clear();
88  if (!string.IsNullOrWhiteSpace(value))
89  {
90  string[] splitTags = value.Split(',');
91  foreach (var s in splitTags)
92  {
93  targetModuleTags.Add(s.ToIdentifier());
94  }
95  }
96  }
97  }
98 
99  [Serialize(false, IsPropertySaveable.Yes, description: "Should the AI ignore this item. This will prevent outpost NPCs cleaning up or otherwise using important items intended to be left for the players.")]
100  public bool IgnoreByAI { get; set; }
101 
102  [Serialize(true, IsPropertySaveable.Yes, description: "If disabled, the action will choose a spawn position away from players' views if one is available.")]
103  public bool AllowInPlayerView { get; set; }
104 
105  [Serialize(false, IsPropertySaveable.Yes, description: "Should the event continue even if the entity failed to spawn for whatever reason?")]
106  public bool ContinueIfFailedToSpawn { get; set; }
107 
108  private bool spawned;
109  private Entity spawnedEntity;
110 
111  private readonly bool ignoreSpawnPointType;
112 
113  public SpawnAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
114  {
115  ignoreSpawnPointType = element.GetAttribute("spawnpointtype") == null;
116  //backwards compatibility
117  TeamID = element.GetAttributeEnum("teamtag", element.GetAttributeEnum("team", TeamID));
118  if (element.GetAttribute("submarinetype") != null)
119  {
120  DebugConsole.ThrowError(
121  $"Error in even \"{(parentEvent.Prefab?.Identifier.ToString() ?? "unknown")}\". " +
122  $"The attribute \"submarinetype\" is not valid in {nameof(SpawnAction)}. Did you mean {nameof(SpawnLocation)}?",
123  contentPackage: ParentEvent.Prefab.ContentPackage);
124  }
125  }
126 
127  public override bool IsFinished(ref string goTo)
128  {
129  if (spawnedEntity != null || ContinueIfFailedToSpawn)
130  {
131  return spawned;
132  }
133  else
134  {
135  return false;
136  }
137  }
138 
139  public override void Reset()
140  {
141  spawned = false;
142  spawnedEntity = null;
143  }
144 
145  public override void Update(float deltaTime)
146  {
147  if (spawned) { return; }
148 
149  if (!NPCSetIdentifier.IsEmpty && !NPCIdentifier.IsEmpty)
150  {
151  HumanPrefab humanPrefab = null;
152  if (Level.Loaded?.StartLocation is Location startLocation)
153  {
154  humanPrefab =
155  TryFindHumanPrefab(startLocation.Faction) ??
156  TryFindHumanPrefab(startLocation.SecondaryFaction);
157  }
158  HumanPrefab TryFindHumanPrefab(Faction faction)
159  {
160  if (faction == null) { return null; }
161  return
162  NPCSet.Get(NPCSetIdentifier,
163  NPCIdentifier.Replace("[faction]".ToIdentifier(), faction.Prefab.Identifier),
164  logError: false) ??
165  //try to spawn a coalition NPC if a correct one can't be found
166  NPCSet.Get(NPCSetIdentifier,
167  NPCIdentifier.Replace("[faction]".ToIdentifier(), "coalition".ToIdentifier()),
168  logError: false);
169  }
170 
171  humanPrefab ??= NPCSet.Get(NPCSetIdentifier, NPCIdentifier, logError: true);
172 
173  if (humanPrefab != null)
174  {
175  if (!AllowDuplicates &&
176  Character.CharacterList.Any(c => c.Info?.HumanPrefabIds.NpcIdentifier == NPCIdentifier && c.Info?.HumanPrefabIds.NpcSetIdentifier == NPCSetIdentifier))
177  {
178  spawned = true;
179  return;
180  }
181  ISpatialEntity spawnPos = GetSpawnPos();
182  if (spawnPos != null)
183  {
184  for (int i = 0; i < Amount; i++)
185  {
186  Entity.Spawner.AddCharacterToSpawnQueue(CharacterPrefab.HumanSpeciesName, OffsetSpawnPos(spawnPos.WorldPosition, Rand.Range(0.0f, Offset)), humanPrefab.CreateCharacterInfo(), onSpawn: newCharacter =>
187  {
188  if (newCharacter == null) { return; }
189  newCharacter.HumanPrefab = humanPrefab;
190  //don't set the TeamID directly: we want to leave the character's original team untouched,
191  //so they can behave offensively (and otherwise act "normally") if we spawn them in a hostile team inside a sub/outpost that doesn't belong to that team
192 
193  //process the team change immediately in case the character is killed or made unconscious by the event (in which case the team change would not be processed)
194  newCharacter.SetOriginalTeamAndChangeTeam(TeamID, processImmediately: true);
195  newCharacter.EnableDespawn = false;
196  humanPrefab.GiveItems(newCharacter, newCharacter.Submarine, spawnPos as WayPoint);
197  if (LootingIsStealing)
198  {
199  foreach (Item item in newCharacter.Inventory.FindAllItems(recursive: true))
200  {
201  item.SpawnedInCurrentOutpost = true;
202  item.AllowStealing = false;
203  }
204  }
205  humanPrefab.InitializeCharacter(newCharacter, spawnPos);
206  if (!TargetTag.IsEmpty && newCharacter != null)
207  {
208  ParentEvent.AddTarget(TargetTag, newCharacter);
209  }
210  spawnedEntity = newCharacter;
211  if (Level.Loaded?.StartOutpost?.Info is { } outPostInfo)
212  {
213  outPostInfo.AddOutpostNPCIdentifierOrTag(newCharacter, humanPrefab.Identifier);
214  foreach (Identifier tag in humanPrefab.GetTags())
215  {
216  outPostInfo.AddOutpostNPCIdentifierOrTag(newCharacter, tag);
217  }
218  }
219 #if SERVER
220  newCharacter.LoadTalents();
221  GameMain.NetworkMember.CreateEntityEvent(newCharacter, new Character.UpdateTalentsEventData());
222 #endif
223  });
224  }
225  }
226  }
227  }
228  else if (!SpeciesName.IsEmpty)
229  {
230  if (!AllowDuplicates && Character.CharacterList.Any(c => c.SpeciesName == SpeciesName))
231  {
232  spawned = true;
233  return;
234  }
235  ISpatialEntity spawnPos = GetSpawnPos();
236  if (spawnPos != null)
237  {
238  for (int i = 0; i < Amount; i++)
239  {
240  Entity.Spawner.AddCharacterToSpawnQueue(SpeciesName, OffsetSpawnPos(spawnPos.WorldPosition, Rand.Range(0.0f, Offset)), onSpawn: newCharacter =>
241  {
242  if (!TargetTag.IsEmpty && newCharacter != null)
243  {
244  ParentEvent.AddTarget(TargetTag, newCharacter);
245  }
246  spawnedEntity = newCharacter;
247  });
248  }
249  }
250  }
251  else if (!ItemIdentifier.IsEmpty || !ItemTag.IsEmpty)
252  {
253  ItemPrefab itemPrefab = null;
254  if (!ItemIdentifier.IsEmpty)
255  {
256  itemPrefab = MapEntityPrefab.FindByIdentifier(ItemIdentifier) as ItemPrefab;
257  if (itemPrefab == null)
258  {
259  DebugConsole.ThrowError($"Error in SpawnAction (item prefab \"{ItemIdentifier}\" not found)",
260  contentPackage: ParentEvent.Prefab.ContentPackage);
261  }
262  }
263  else if (!ItemTag.IsEmpty)
264  {
265  itemPrefab = ItemPrefab.Prefabs.Where(ip => ip.Tags.Contains(ItemTag)).GetRandom(Rand.RandSync.Unsynced);
266  }
267 
268  Inventory spawnInventory = null;
269  if (!TargetInventory.IsEmpty)
270  {
271  var targets = ParentEvent.GetTargets(TargetInventory);
272  if (targets.Any())
273  {
274  var target = targets.First(t => t is Item || t is Character);
275  if (target is Character character)
276  {
277  spawnInventory = character.Inventory;
278  }
279  else if (target is Item item)
280  {
281  spawnInventory = item.OwnInventory;
282  }
283  }
284 
285  if (spawnInventory == null)
286  {
287  DebugConsole.ThrowError($"Could not spawn \"{ItemIdentifier}\" in target inventory \"{TargetInventory}\" - matching target not found.",
288  contentPackage: ParentEvent.Prefab.ContentPackage);
289  }
290  }
291 
292  if (spawnInventory == null)
293  {
294  ISpatialEntity spawnPos = GetSpawnPos();
295  if (spawnPos != null)
296  {
297  for (int i = 0; i < Amount; i++)
298  {
299  Entity.Spawner.AddItemToSpawnQueue(itemPrefab, OffsetSpawnPos(spawnPos.WorldPosition, Rand.Range(0.0f, Offset)), onSpawned: onSpawned);
300  }
301  }
302  }
303  else
304  {
305  for (int i = 0; i < Amount; i++)
306  {
307  Entity.Spawner.AddItemToSpawnQueue(itemPrefab, spawnInventory, spawnIfInventoryFull: SpawnIfInventoryFull, onSpawned: onSpawned);
308 
309  }
310  }
311  void onSpawned(Item newItem)
312  {
313  if (newItem != null)
314  {
315  if (!TargetTag.IsEmpty)
316  {
317  ParentEvent.AddTarget(TargetTag, newItem);
318  }
319  if (IgnoreByAI)
320  {
321  newItem.AddTag("ignorebyai");
322  }
323  }
324  spawnedEntity = newItem;
325  }
326 
327  }
328 
329  spawned = true;
330  }
331 
332  public static Vector2 OffsetSpawnPos(Vector2 pos, float offset)
333  {
334  Hull hull = Hull.FindHull(pos);
335  pos += Rand.Vector(offset);
336  if (hull != null)
337  {
338  float margin = 50.0f;
339  pos = new Vector2(
340  MathHelper.Clamp(pos.X, hull.WorldRect.X + margin, hull.WorldRect.Right - margin),
341  MathHelper.Clamp(pos.Y, hull.WorldRect.Y - hull.WorldRect.Height + margin, hull.WorldRect.Y - margin));
342  }
343  return pos;
344  }
345 
346  private ISpatialEntity GetSpawnPos()
347  {
348  if (!SpawnPointTag.IsEmpty)
349  {
350  IEnumerable<Item> potentialItems = Item.ItemList.Where(it => IsValidSubmarineType(SpawnLocation, it.Submarine));
351  if (!AllowInPlayerView)
352  {
353  potentialItems = GetEntitiesNotInPlayerView(potentialItems);
354  }
355  var item = potentialItems.Where(it => it.HasTag(SpawnPointTag)).GetRandomUnsynced();
356  if (item != null) { return item; }
357 
358  var potentialTargets = ParentEvent.GetTargets(SpawnPointTag).Where(t => IsValidSubmarineType(SpawnLocation, t.Submarine));
359  if (!AllowInPlayerView)
360  {
361  potentialTargets = GetEntitiesNotInPlayerView(potentialTargets);
362  }
363  var target = potentialTargets.GetRandomUnsynced();
364  if (target != null) { return target; }
365  }
366 
367  SpawnType? spawnPointType = null;
368  if (!ignoreSpawnPointType) { spawnPointType = SpawnPointType; }
369 
370  return GetSpawnPos(SpawnLocation, spawnPointType, targetModuleTags, SpawnPointTag.ToEnumerable(), requireTaggedSpawnPoint: RequireSpawnPointTag, allowInPlayerView: AllowInPlayerView);
371  }
372 
373  private static bool IsValidSubmarineType(SpawnLocationType spawnLocation, Submarine submarine)
374  {
375  return spawnLocation switch
376  {
377  SpawnLocationType.Any => true,
378  SpawnLocationType.MainSub => submarine == Submarine.MainSub,
379  SpawnLocationType.NearMainSub or SpawnLocationType.MainPath or SpawnLocationType.Cave or SpawnLocationType.AbyssCave => submarine == null,
380  SpawnLocationType.Outpost => submarine is { Info.IsOutpost: true },
381  SpawnLocationType.Wreck => submarine is { Info.IsWreck: true },
382  SpawnLocationType.Ruin => submarine is { Info.IsRuin: true },
383  SpawnLocationType.BeaconStation => submarine?.Info?.BeaconStationInfo != null,
384  _ => throw new NotImplementedException(),
385  };
386  }
387 
391  private static IEnumerable<T> GetEntitiesNotInPlayerView<T>(IEnumerable<T> entities) where T : ISpatialEntity
392  {
393  if (entities.Any(e => !IsInPlayerView(e)))
394  {
395  return entities.Where(e => !IsInPlayerView(e));
396  }
397  return entities;
398  }
399 
400  private static bool IsInPlayerView(ISpatialEntity entity)
401  {
402  foreach (var character in Character.CharacterList)
403  {
404  if (!character.IsPlayer || character.IsDead) { continue; }
405  if (character.CanSeeTarget(entity)) { return true; }
406  }
407  return false;
408  }
409 
410  public static WayPoint GetSpawnPos(SpawnLocationType spawnLocation, SpawnType? spawnPointType, IEnumerable<Identifier> moduleFlags = null, IEnumerable<Identifier> spawnpointTags = null, bool asFarAsPossibleFromAirlock = false, bool requireTaggedSpawnPoint = false, bool allowInPlayerView = true)
411  {
412  bool requireHull = spawnLocation == SpawnLocationType.MainSub || spawnLocation == SpawnLocationType.Outpost;
413  List<WayPoint> potentialSpawnPoints = WayPoint.WayPointList.FindAll(wp => IsValidSubmarineType(spawnLocation, wp.Submarine) && (wp.CurrentHull != null || !requireHull));
414  potentialSpawnPoints = potentialSpawnPoints.FindAll(wp => wp.ConnectedDoor == null && wp.Ladders == null && wp.IsTraversable);
415  if (moduleFlags != null && moduleFlags.Any())
416  {
417  var spawnPoints = potentialSpawnPoints.Where(wp => wp.CurrentHull is Hull h && h.OutpostModuleTags.Any(moduleFlags.Contains));
418  if (spawnPoints.Any())
419  {
420  potentialSpawnPoints = spawnPoints.ToList();
421  }
422  }
423  if (spawnpointTags != null && spawnpointTags.Any())
424  {
425  var spawnPoints = potentialSpawnPoints.Where(wp => spawnpointTags.Any(tag => wp.Tags.Contains(tag) && wp.ConnectedDoor == null && wp.IsTraversable));
426  if (requireTaggedSpawnPoint || spawnPoints.Any())
427  {
428  potentialSpawnPoints = spawnPoints.ToList();
429  }
430  }
431  if (potentialSpawnPoints.None())
432  {
433  if (requireTaggedSpawnPoint && spawnpointTags != null && spawnpointTags.Any())
434  {
435  DebugConsole.NewMessage($"Could not find a spawn point for a SpawnAction (spawn location: {spawnLocation} (tag: {string.Join(",", spawnpointTags)}), skipping.", color: Color.White);
436  }
437  else
438  {
439  DebugConsole.ThrowError($"Could not find a spawn point for a SpawnAction (spawn location: {spawnLocation})");
440  }
441  return null;
442  }
443 
444  IEnumerable<WayPoint> validSpawnPoints;
445  if (spawnPointType.HasValue)
446  {
447  validSpawnPoints = potentialSpawnPoints.FindAll(wp => spawnPointType.Value.HasFlag(wp.SpawnType));
448  }
449  else
450  {
451  validSpawnPoints = potentialSpawnPoints.FindAll(wp => wp.SpawnType != SpawnType.Path);
452  if (!validSpawnPoints.Any()) { validSpawnPoints = potentialSpawnPoints; }
453  }
454 
455  //don't spawn in an airlock module if there are other options
456  var airlockSpawnPoints = potentialSpawnPoints.Where(wp => wp.CurrentHull?.OutpostModuleTags.Contains("airlock".ToIdentifier()) ?? false);
457  if (airlockSpawnPoints.Count() < validSpawnPoints.Count())
458  {
459  validSpawnPoints = validSpawnPoints.Except(airlockSpawnPoints);
460  }
461 
462  if (validSpawnPoints.None())
463  {
464  DebugConsole.ThrowError($"Could not find a spawn point of the correct type for a SpawnAction (spawn location: {spawnLocation}, type: {spawnPointType}, module flags: {((moduleFlags == null || !moduleFlags.Any()) ? "none" : string.Join(", ", moduleFlags))})");
465  return potentialSpawnPoints.GetRandomUnsynced();
466  }
467 
468  switch (spawnLocation)
469  {
470  case SpawnLocationType.MainPath:
471  case SpawnLocationType.NearMainSub:
472  validSpawnPoints = validSpawnPoints.Where(p =>
473  Submarine.Loaded.None(s => ToolBox.GetWorldBounds(s.Borders.Center, s.Borders.Size).ContainsWorld(p.WorldPosition)));
474  if (Level.Loaded != null)
475  {
476  validSpawnPoints = validSpawnPoints.Where(p =>
477  p.WorldPosition.Y > Level.Loaded.AbyssStart &&
478  p.Cave == null && p.Ruin == null);
479  }
480  break;
481  case SpawnLocationType.Cave:
482  validSpawnPoints = validSpawnPoints.Where(p => p.WorldPosition.Y > Level.Loaded.AbyssStart && p.Cave != null);
483  break;
484  case SpawnLocationType.AbyssCave:
485  validSpawnPoints = validSpawnPoints.Where(p => p.WorldPosition.Y < Level.Loaded.AbyssStart && p.Cave != null);
486  break;
487  }
488 
489  //avoid using waypoints if there's any actual spawnpoints available
490  if (validSpawnPoints.Any(wp => wp.SpawnType != SpawnType.Path))
491  {
492  validSpawnPoints = validSpawnPoints.Where(wp => wp.SpawnType != SpawnType.Path);
493  }
494 
495  //if not trying to spawn at a tagged spawnpoint, favor spawnpoints without tags
496  if (spawnpointTags == null || spawnpointTags.None())
497  {
498  var spawnPoints = validSpawnPoints.Where(wp => !wp.Tags.Any());
499  if (spawnPoints.Any())
500  {
501  validSpawnPoints = spawnPoints.ToList();
502  }
503  }
504 
505  if (!allowInPlayerView)
506  {
507  validSpawnPoints = GetEntitiesNotInPlayerView(validSpawnPoints);
508  }
509 
510  if (spawnLocation == SpawnLocationType.NearMainSub && Submarine.MainSub != null)
511  {
512  WayPoint closestPoint = validSpawnPoints.First();
513  float closestDist = float.PositiveInfinity;
514  foreach (WayPoint wp in validSpawnPoints)
515  {
516  float dist = Vector2.DistanceSquared(wp.WorldPosition, Submarine.MainSub.WorldPosition);
517  if (dist < closestDist)
518  {
519  closestDist = dist;
520  closestPoint = wp;
521  }
522  }
523  return closestPoint;
524  }
525  else if (asFarAsPossibleFromAirlock && airlockSpawnPoints.Any())
526  {
527  WayPoint furthestPoint = validSpawnPoints.First();
528  float furthestDist = 0.0f;
529  foreach (WayPoint waypoint in validSpawnPoints)
530  {
531  float dist = Vector2.DistanceSquared(waypoint.WorldPosition, airlockSpawnPoints.First().WorldPosition);
532  if (dist > furthestDist)
533  {
534  furthestDist = dist;
535  furthestPoint = waypoint;
536  }
537  }
538  return furthestPoint;
539  }
540  else
541  {
542  return validSpawnPoints.GetRandomUnsynced();
543  }
544  }
545 
546  public override string ToDebugString()
547  {
548  return $"{ToolBox.GetDebugSymbol(spawned)} {nameof(SpawnAction)} -> (Spawned entity: {spawnedEntity.ColorizeObject()})";
549  }
550  }
551 }
static readonly Identifier HumanSpeciesName
XAttribute? GetAttribute(string name)
static EntitySpawner Spawner
Definition: Entity.cs:31
virtual Vector2 WorldPosition
Definition: Entity.cs:49
void AddCharacterToSpawnQueue(Identifier speciesName, Vector2 worldPosition, Action< Character > onSpawn=null)
readonly ScriptedEvent ParentEvent
Definition: EventAction.cs:106
EventPrefab Prefab
Definition: Event.cs:16
FactionPrefab Prefab
Definition: Factions.cs:18
static NetworkMember NetworkMember
Definition: GameMain.cs:190
IEnumerable< Identifier > OutpostModuleTags
Inherited flags from outpost generation.
static Hull FindHull(Vector2 position, Hull guess=null, bool useWorldCoordinates=true, bool inclusive=true)
Returns the hull which contains the point (or null if it isn't inside any)
CharacterInfo CreateCharacterInfo(Rand.RandSync randSync=Rand.RandSync.Unsynced)
Creates a character info from the human prefab. If there are custom character infos defined,...
Definition: HumanPrefab.cs:231
void InitializeCharacter(Character npc, ISpatialEntity positionToStayIn=null)
Definition: HumanPrefab.cs:167
bool GiveItems(Character character, Submarine submarine, WayPoint spawnPoint, Rand.RandSync randSync=Rand.RandSync.Unsynced, bool createNetworkEvents=true)
Definition: HumanPrefab.cs:208
static readonly List< Item > ItemList
ContentPackage? ContentPackage
Definition: Prefab.cs:37
Spawns an entity (e.g. item, NPC, monster).
Definition: SpawnAction.cs:13
static Vector2 OffsetSpawnPos(Vector2 pos, float offset)
Definition: SpawnAction.cs:332
SpawnType SpawnPointType
Definition: SpawnAction.cs:56
override bool IsFinished(ref string goTo)
Has the action finished.
Definition: SpawnAction.cs:127
Identifier SpeciesName
Definition: SpawnAction.cs:29
override string ToDebugString()
Rich test to display in debugdraw
Definition: SpawnAction.cs:546
Identifier SpawnPointTag
Definition: SpawnAction.cs:59
Identifier NPCIdentifier
Definition: SpawnAction.cs:35
Identifier ItemIdentifier
Definition: SpawnAction.cs:41
Identifier NPCSetIdentifier
Definition: SpawnAction.cs:32
CharacterTeamType TeamID
Definition: SpawnAction.cs:62
override void Reset()
Definition: SpawnAction.cs:139
SpawnAction(ScriptedEvent parentEvent, ContentXElement element)
Definition: SpawnAction.cs:113
static WayPoint GetSpawnPos(SpawnLocationType spawnLocation, SpawnType? spawnPointType, IEnumerable< Identifier > moduleFlags=null, IEnumerable< Identifier > spawnpointTags=null, bool asFarAsPossibleFromAirlock=false, bool requireTaggedSpawnPoint=false, bool allowInPlayerView=true)
Definition: SpawnAction.cs:410
override void Update(float deltaTime)
Definition: SpawnAction.cs:145
Identifier TargetInventory
Definition: SpawnAction.cs:50
SpawnLocationType SpawnLocation
Definition: SpawnAction.cs:53
static Submarine MainSub
Note that this can be null in some situations, e.g. editors and missions that don't load a submarine.
@ Character
Characters only