Client LuaCsForBarotrauma
BarotraumaShared/SharedSource/Events/Missions/Mission.cs
3 using Microsoft.Xna.Framework;
4 using System;
5 using System.Collections.Generic;
6 using System.Collections.Immutable;
7 using System.Globalization;
8 using System.Linq;
9 using System.Xml.Linq;
10 
11 namespace Barotrauma
12 {
13  abstract partial class Mission
14  {
15  public readonly MissionPrefab Prefab;
16  private bool completed;
17  protected bool failed;
18 
19  protected Level level;
20 
21  protected int state;
22  public virtual int State
23  {
24  get { return state; }
25  set
26  {
27  if (state != value)
28  {
29  state = value;
30  TryTriggerEvents(state);
31 #if SERVER
32  GameMain.Server?.UpdateMissionState(this);
33 #elif CLIENT
34  if (Prefab.ShowProgressBar)
35  {
37  }
38 #endif
40  OnMissionStateChanged?.Invoke(this);
41  }
42  }
43  }
44 
45  public int TimesAttempted { get; set; }
46 
47  protected static bool IsClient => GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;
48 
49  private readonly CheckDataAction completeCheckDataAction;
50 
51  public readonly ImmutableArray<LocalizedString> Headers;
52  public readonly ImmutableArray<LocalizedString> Messages;
53 
58  private int? finalReward;
59 
60  public virtual LocalizedString Name => Prefab.Name;
61 
62  private readonly LocalizedString successMessage;
64  {
65  get { return successMessage; }
66  //private set { successMessage = value; }
67  }
68 
69  private readonly LocalizedString failureMessage;
71  {
72  get { return failureMessage; }
73  //private set { failureMessage = value; }
74  }
75 
78  {
79  get { return description; }
80  //private set { description = value; }
81  }
82 
84 
85  public virtual bool AllowUndocking
86  {
87  get { return true; }
88  }
89 
90  public virtual int Reward
91  {
92  get
93  {
94  return Prefab.Reward;
95  }
96  }
97 
99  {
100  get { return Prefab.ReputationRewards; }
101  }
102 
103  public bool Completed
104  {
105  get { return completed; }
106  set { completed = value; }
107  }
108 
109  public bool Failed
110  {
111  get { return failed; }
112  }
113 
114  public virtual bool AllowRespawn
115  {
116  get { return true; }
117  }
118 
119  public virtual int TeamCount
120  {
121  get { return 1; }
122  }
123 
125  {
126  get { return null; }
127  }
128 
129  public virtual IEnumerable<(LocalizedString Label, Vector2 Position)> SonarLabels
130  {
131  get { return Enumerable.Empty<(LocalizedString Label, Vector2 Position)>(); }
132  }
133 
134  public Identifier SonarIconIdentifier => Prefab.SonarIconIdentifier;
135 
141 
142  public readonly Location[] Locations;
143 
144  public int? Difficulty
145  {
146  get { return Prefab.Difficulty; }
147  }
148 
149  private class DelayedTriggerEvent
150  {
151  public readonly MissionPrefab.TriggerEvent TriggerEvent;
152  public float Delay;
153 
154  public DelayedTriggerEvent(MissionPrefab.TriggerEvent triggerEvent, float delay)
155  {
156  TriggerEvent = triggerEvent;
157  Delay = delay;
158  }
159  }
160 
161  private readonly List<DelayedTriggerEvent> delayedTriggerEvents = new List<DelayedTriggerEvent>();
162 
163  public Action<Mission> OnMissionStateChanged;
164 
165  public Mission(MissionPrefab prefab, Location[] locations, Submarine sub)
166  {
167  System.Diagnostics.Debug.Assert(locations.Length == 2);
168 
169  Prefab = prefab;
170 
171  description = prefab.Description.Value;
172  successMessage = prefab.SuccessMessage.Value;
173  failureMessage = prefab.FailureMessage.Value;
174  Headers = prefab.Headers;
175  var messages = prefab.Messages.ToArray();
176 
177  OriginLocation = locations[0];
178  Locations = locations;
179 
180  var endConditionElement = prefab.ConfigElement.GetChildElement(nameof(completeCheckDataAction));
181  if (endConditionElement != null)
182  {
183  completeCheckDataAction = new CheckDataAction(endConditionElement, $"Mission ({prefab.Identifier})");
184  }
185 
188  successMessage = ReplaceVariablesInMissionMessage(successMessage, sub);
189  failureMessage = ReplaceVariablesInMissionMessage(failureMessage, sub);
190  for (int m = 0; m < messages.Length; m++)
191  {
192  messages[m] = ReplaceVariablesInMissionMessage(messages[m], sub);
193  }
194  Messages = messages.ToImmutableArray();
195  }
196 
197  public LocalizedString ReplaceVariablesInMissionMessage(LocalizedString message, Submarine sub, bool replaceReward = true)
198  {
199  for (int locationIndex = 0; locationIndex < 2; locationIndex++)
200  {
201  string locationName = $"‖color:gui.orange‖{Locations[locationIndex].DisplayName}‖end‖";
202  message = message.Replace("[location" + (locationIndex + 1) + "]", locationName);
203  }
204  if (replaceReward)
205  {
206  string rewardText = $"‖color:gui.orange‖{string.Format(CultureInfo.InvariantCulture, "{0:N0}", GetReward(sub))}‖end‖";
207  message = message.Replace("[reward]", rewardText);
208  }
209  return message;
210  }
211 
212  public virtual void SetLevel(LevelData level) { }
213 
214  public static Mission LoadRandom(Location[] locations, string seed, bool requireCorrectLocationType, MissionType missionType, bool isSinglePlayer = false, float? difficultyLevel = null)
215  {
216  return LoadRandom(locations, new MTRandom(ToolBox.StringToInt(seed)), requireCorrectLocationType, missionType, isSinglePlayer, difficultyLevel);
217  }
218 
219  public static Mission LoadRandom(Location[] locations, MTRandom rand, bool requireCorrectLocationType, MissionType missionType, bool isSinglePlayer = false, float? difficultyLevel = null)
220  {
221  List<MissionPrefab> allowedMissions = new List<MissionPrefab>();
222  if (missionType == MissionType.None)
223  {
224  return null;
225  }
226  else
227  {
228  allowedMissions.AddRange(MissionPrefab.Prefabs.Where(m => m.Type.HasAnyFlag(missionType)));
229  }
230  allowedMissions.RemoveAll(m => isSinglePlayer ? m.MultiplayerOnly : m.SingleplayerOnly);
231  if (requireCorrectLocationType)
232  {
233  allowedMissions.RemoveAll(m => !m.IsAllowed(locations[0], locations[1]));
234  }
235  if (difficultyLevel.HasValue)
236  {
237  allowedMissions.RemoveAll(m => !m.IsAllowedDifficulty(difficultyLevel.Value));
238  }
239  if (allowedMissions.Count == 0) { return null; }
240  MissionPrefab missionPrefab = ToolBox.SelectWeightedRandom(allowedMissions, m => m.Commonness, rand);
241  return missionPrefab.Instantiate(locations, Submarine.MainSub);
242  }
243 
247  public virtual int GetBaseReward(Submarine sub)
248  {
249  return Prefab.Reward;
250  }
251 
255  public int GetReward(Submarine sub)
256  {
257  int reward = GetBaseReward(sub);
258 
259  // Some modifiers should apply universally to all implementations of GetBaseReward
260  if (GameMain.GameSession?.Campaign is CampaignMode campaign)
261  {
262  reward = (int)Math.Round(reward * campaign.Settings.MissionRewardMultiplier);
263  }
264 
265  return reward;
266  }
267 
268  public void Start(Level level)
269  {
270  state = 0;
271 #if CLIENT
272  shownMessages.Clear();
273 #endif
274  delayedTriggerEvents.Clear();
275  foreach (string categoryToShow in Prefab.UnhideEntitySubCategories)
276  {
277  foreach (MapEntity entityToShow in MapEntity.MapEntityList.Where(me => me.Prefab?.HasSubCategory(categoryToShow) ?? false))
278  {
279  entityToShow.IsLayerHidden = false;
280  }
281  }
282  this.level = level;
283  TryTriggerEvents(0);
285  }
286 
287  protected virtual void StartMissionSpecific(Level level) { }
288 
289  public void Update(float deltaTime)
290  {
291  for (int i = delayedTriggerEvents.Count - 1; i>=0;i--)
292  {
293  delayedTriggerEvents[i].Delay -= deltaTime;
294  if (delayedTriggerEvents[i].Delay <= 0.0f)
295  {
296  TriggerEvent(delayedTriggerEvents[i].TriggerEvent);
297  delayedTriggerEvents.RemoveAt(i);
298  }
299  }
300  UpdateMissionSpecific(deltaTime);
301  }
302 
303  protected virtual void UpdateMissionSpecific(float deltaTime) { }
304 
305  protected void ShowMessage(int missionState)
306  {
307  ShowMessageProjSpecific(missionState);
308  }
309 
310  partial void ShowMessageProjSpecific(int missionState);
311 
312  protected virtual LocalizedString ModifyMessage(LocalizedString message, bool color = true)
313  {
314  return message;
315  }
316 
317  private void TryTriggerEvents(int state)
318  {
319  foreach (var triggerEvent in Prefab.TriggerEvents)
320  {
321  if (triggerEvent.State == state)
322  {
323  TryTriggerEvent(triggerEvent);
324  }
325  }
326  }
327 
331  private void TryTriggerEvent(MissionPrefab.TriggerEvent trigger)
332  {
333  if (trigger.CampaignOnly && GameMain.GameSession?.Campaign == null) { return; }
334  if (trigger.Delay > 0 || trigger.State == 0)
335  {
336  if (!delayedTriggerEvents.Any(t => t.TriggerEvent == trigger))
337  {
338  delayedTriggerEvents.Add(new DelayedTriggerEvent(trigger, trigger.Delay));
339  }
340  }
341  else
342  {
343  TriggerEvent(trigger);
344  }
345  }
346 
350  private void TriggerEvent(MissionPrefab.TriggerEvent trigger)
351  {
352  if (trigger.CampaignOnly && GameMain.GameSession?.Campaign == null) { return; }
353  var eventPrefab = EventSet.GetAllEventPrefabs().Find(p => p.Identifier == trigger.EventIdentifier);
354  if (eventPrefab == null)
355  {
356  DebugConsole.ThrowError($"Mission \"{Name}\" failed to trigger an event (couldn't find an event with the identifier \"{trigger.EventIdentifier}\").",
357  contentPackage: Prefab.ContentPackage);
358  return;
359  }
360  if (GameMain.GameSession?.EventManager != null)
361  {
362  var newEvent = eventPrefab.CreateInstance(GameMain.GameSession.EventManager.RandomSeed);
363  GameMain.GameSession.EventManager.ActivateEvent(newEvent);
364  }
365  }
366 
370  public void End()
371  {
372  if (GameMain.NetworkMember is not { IsClient: true })
373  {
374  completed =
375  DetermineCompleted() &&
376  (completeCheckDataAction == null ||completeCheckDataAction.GetSuccess());
377  }
378  if (completed)
379  {
380  if (Prefab.LocationTypeChangeOnCompleted != null)
381  {
382  ChangeLocationType(Prefab.LocationTypeChangeOnCompleted);
383  }
384  try
385  {
386  GiveReward();
387  }
388  catch (Exception e)
389  {
390  string errorMsg = "Unknown error while giving mission rewards.";
391  DebugConsole.ThrowError(errorMsg, e, contentPackage: Prefab.ContentPackage);
392  GameAnalyticsManager.AddErrorEventOnce("Mission.End:GiveReward", GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + e.StackTrace);
393 #if SERVER
394  GameMain.Server?.SendChatMessage(errorMsg + "\n" + e.StackTrace, Networking.ChatMessageType.Error);
395 #endif
396  }
397  }
398 
399  TimesAttempted++;
400 
401  EndMissionSpecific(completed);
402  }
403 
404  protected abstract bool DetermineCompleted();
405 
406  protected virtual void EndMissionSpecific(bool completed) { }
407 
411  public int GetFinalReward(Submarine sub)
412  {
413  return finalReward ?? GetReward(sub);
414  }
415 
420  private void CalculateFinalReward(Submarine sub)
421  {
422  int reward = GetReward(sub);
423  IEnumerable<Character> crewCharacters = GameSession.GetSessionCrewCharacters(CharacterType.Both);
424  var missionMoneyGainMultiplier = new AbilityMissionMoneyGainMultiplier(this, 1f);
425  CharacterTalent.CheckTalentsForCrew(crewCharacters, AbilityEffectType.OnGainMissionMoney, missionMoneyGainMultiplier);
426  crewCharacters.ForEach(c => missionMoneyGainMultiplier.Value += c.GetStatValue(StatTypes.MissionMoneyGainMultiplier));
427  finalReward = (int)(reward * missionMoneyGainMultiplier.Value);
428  }
429 
430  private void GiveReward()
431  {
432  if (GameMain.GameSession.GameMode is not CampaignMode campaign) { return; }
433  int reward = GetReward(Submarine.MainSub);
434 
435  float baseExperienceGain = reward * 0.09f;
436 
437  float difficultyMultiplier = 1 + level.Difficulty / 100f;
438  baseExperienceGain *= difficultyMultiplier;
439 
440  IEnumerable<Character> crewCharacters = GameSession.GetSessionCrewCharacters(CharacterType.Both);
441 
442  // use multipliers here so that we can easily add them together without introducing multiplicative XP stacking
443  var experienceGainMultiplier = new AbilityMissionExperienceGainMultiplier(this, 1f, character: null);
444  crewCharacters.ForEach(c => experienceGainMultiplier.Value += c.GetStatValue(StatTypes.MissionExperienceGainMultiplier));
445 
446  DistributeExperienceToCrew(crewCharacters, (int)(baseExperienceGain * experienceGainMultiplier.Value));
447 
448  CalculateFinalReward(Submarine.MainSub);
449 #if SERVER
450  finalReward = DistributeRewardsToCrew(GameSession.GetSessionCrewCharacters(CharacterType.Player), finalReward.Value);
451 #endif
452  bool isSingleplayerOrServer = GameMain.IsSingleplayer || GameMain.NetworkMember is { IsServer: true };
453  if (isSingleplayerOrServer)
454  {
455  if (finalReward > 0)
456  {
457  campaign.Bank.Give(finalReward.Value);
458  }
459 
460  foreach (Character character in crewCharacters)
461  {
462  character.Info.MissionsCompletedSinceDeath++;
463  }
464 
465  foreach (var reputationReward in ReputationRewards)
466  {
467  var reputationGainMultiplier = new AbilityMissionReputationGainMultiplier(this, 1f, character: null);
468  foreach (var c in crewCharacters) { c.CheckTalents(AbilityEffectType.OnCrewGainMissionReputation, reputationGainMultiplier); }
469  float amount = reputationReward.Amount * reputationGainMultiplier.Value;
470 
471  if (reputationReward.FactionIdentifier == "location")
472  {
474  TryGiveReputationForOpposingFaction(OriginLocation.Faction, reputationReward.AmountForOpposingFaction);
475  }
476  else
477  {
478  Faction faction = campaign.Factions.Find(faction1 => faction1.Prefab.Identifier == reputationReward.FactionIdentifier);
479  if (faction != null)
480  {
481  faction.Reputation.AddReputation(amount);
482  TryGiveReputationForOpposingFaction(faction, reputationReward.AmountForOpposingFaction);
483  }
484  }
485  }
486 
487  void TryGiveReputationForOpposingFaction(Faction thisFaction, float amount)
488  {
489  if (MathUtils.NearlyEqual(amount, 0.0f)) { return; }
490  if (thisFaction?.Prefab != null &&
491  !thisFaction.Prefab.OpposingFaction.IsEmpty)
492  {
493  Faction faction = campaign.Factions.Find(faction1 => faction1.Prefab.Identifier == thisFaction.Prefab.OpposingFaction);
494  faction?.Reputation.AddReputation(amount);
495  }
496  }
497  }
498 
499  if (Prefab.DataRewards != null)
500  {
501  foreach (var (identifier, value, operation) in Prefab.DataRewards)
502  {
503  SetDataAction.PerformOperation(campaign.CampaignMetadata, identifier, value, operation);
504  }
505  }
506  }
507 
508  partial void DistributeExperienceToCrew(IEnumerable<Character> crew, int experienceGain);
509 
510  public static int GetRewardDistibutionSum(IEnumerable<Character> crew, int rewardDistribution = 0) => crew.Sum(c => c.Wallet.RewardDistribution) + rewardDistribution;
511 
512  public static (int Amount, int Percentage, float Sum) GetRewardShare(int rewardDistribution, IEnumerable<Character> crew, Option<int> reward)
513  {
514  float sum = GetRewardDistibutionSum(crew, rewardDistribution);
515  if (MathUtils.NearlyEqual(sum, 0)) { return (0, 0, sum); }
516 
517  float rewardWeight = sum > 100 ? rewardDistribution / sum : rewardDistribution / 100f;
518  int rewardPercentage = (int)(rewardWeight * 100);
519 
520  int amount = reward.TryUnwrap(out var a) ? a : 0;
521 
522  return ((int)(amount * rewardWeight), rewardPercentage, sum);
523  }
524 
525  protected void ChangeLocationType(LocationTypeChange change)
526  {
527  if (change == null) { throw new ArgumentException(); }
528  if (GameMain.GameSession.GameMode is CampaignMode campaign && !IsClient)
529  {
530  int srcIndex = -1;
531  for (int i = 0; i < Locations.Length; i++)
532  {
533  if (Locations[i].Type.Identifier == change.CurrentType)
534  {
535  srcIndex = i;
536  break;
537  }
538  }
539  if (srcIndex == -1) { return; }
540  var location = Locations[srcIndex];
541 
542  if (location.LocationTypeChangesBlocked) { return; }
543 
544  if (change.RequiredDurationRange.X > 0)
545  {
546  location.PendingLocationTypeChange = (change, Rand.Range(change.RequiredDurationRange.X, change.RequiredDurationRange.Y), Prefab);
547  }
548  else
549  {
550  location.ChangeType(campaign, LocationType.Prefabs[change.ChangeToType]);
551  location.LocationTypeChangeCooldown = change.CooldownAfterChange;
552  }
553  }
554  }
555 
556  public virtual void AdjustLevelData(LevelData levelData) { }
557 
558  // putting these here since both escort and pirate missions need them. could be tucked away into another class that they can inherit from (or use composition)
559  protected HumanPrefab GetHumanPrefabFromElement(XElement element)
560  {
561  if (element.Attribute("name") != null)
562  {
563  DebugConsole.ThrowError($"Error in mission \"{Name}\" - use character identifiers instead of names to configure the characters.",
564  contentPackage: Prefab.ContentPackage);
565  return null;
566  }
567 
568  Identifier characterIdentifier = element.GetAttributeIdentifier("identifier", Identifier.Empty);
569  Identifier characterFrom = element.GetAttributeIdentifier("from", Identifier.Empty);
570  HumanPrefab humanPrefab = NPCSet.Get(characterFrom, characterIdentifier);
571  if (humanPrefab == null)
572  {
573  DebugConsole.ThrowError($"Couldn't spawn character for mission: character prefab \"{characterIdentifier}\" not found in the NPC set \"{characterFrom}\".",
574  contentPackage: Prefab.ContentPackage);
575  return null;
576  }
577 
578  return humanPrefab;
579  }
580 
581  protected static Character CreateHuman(HumanPrefab humanPrefab, List<Character> characters, Dictionary<Character, List<Item>> characterItems, Submarine submarine, CharacterTeamType teamType, ISpatialEntity positionToStayIn = null, Rand.RandSync humanPrefabRandSync = Rand.RandSync.ServerAndClient)
582  {
583  var characterInfo = humanPrefab.CreateCharacterInfo(Rand.RandSync.ServerAndClient);
584  characterInfo.TeamID = teamType;
585 
586  positionToStayIn ??=
587  WayPoint.GetRandom(SpawnType.Human, characterInfo.Job?.Prefab, submarine) ??
588  WayPoint.GetRandom(SpawnType.Human, null, submarine);
589 
590  Character spawnedCharacter = Character.Create(characterInfo.SpeciesName, positionToStayIn.WorldPosition, ToolBox.RandomSeed(8), characterInfo, createNetworkEvent: false);
591  spawnedCharacter.HumanPrefab = humanPrefab;
592  humanPrefab.InitializeCharacter(spawnedCharacter, positionToStayIn);
593  humanPrefab.GiveItems(spawnedCharacter, submarine, positionToStayIn as WayPoint, Rand.RandSync.ServerAndClient, createNetworkEvents: false);
594  characters.Add(spawnedCharacter);
595  characterItems.Add(spawnedCharacter, spawnedCharacter.Inventory.FindAllItems(recursive: true));
596 
597  return spawnedCharacter;
598  }
599 
600  protected ItemPrefab FindItemPrefab(XElement element)
601  {
602  ItemPrefab itemPrefab;
603  if (element.Attribute("name") != null)
604  {
605  DebugConsole.ThrowError($"Error in mission \"{Name}\" - use item identifiers instead of names to configure the items",
606  contentPackage: Prefab.ContentPackage);
607  string itemName = element.GetAttributeString("name", "");
608  itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab;
609  if (itemPrefab == null)
610  {
611  DebugConsole.ThrowError($"Couldn't spawn item for mission \"{Name}\": item prefab \"{itemName}\" not found",
612  contentPackage: Prefab.ContentPackage);
613  }
614  }
615  else
616  {
617  string itemIdentifier = element.GetAttributeString("identifier", "");
618  itemPrefab = MapEntityPrefab.Find(null, itemIdentifier) as ItemPrefab;
619  if (itemPrefab == null)
620  {
621  DebugConsole.ThrowError($"Couldn't spawn item for mission \"{Name}\": item prefab \"{itemIdentifier}\" not found",
622  contentPackage: Prefab.ContentPackage);
623  }
624  }
625  return itemPrefab;
626  }
627 
628  protected Vector2? GetCargoSpawnPosition(ItemPrefab itemPrefab, out Submarine cargoRoomSub)
629  {
630  cargoRoomSub = null;
631 
632  WayPoint cargoSpawnPos = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub, useSyncedRand: true);
633  if (cargoSpawnPos == null)
634  {
635  DebugConsole.ThrowError($"Couldn't spawn items for mission \"{Name}\": no waypoints marked as Cargo were found",
636  contentPackage: Prefab.ContentPackage);
637  return null;
638  }
639 
640  var cargoRoom = cargoSpawnPos.CurrentHull;
641  if (cargoRoom == null)
642  {
643  DebugConsole.ThrowError($"Couldn't spawn items for mission \"{Name}\": waypoints marked as Cargo must be placed inside a room",
644  contentPackage: Prefab.ContentPackage);
645  return null;
646  }
647 
648  cargoRoomSub = cargoRoom.Submarine;
649 
650  return new Vector2(
651  cargoSpawnPos.Position.X + Rand.Range(-20.0f, 20.0f, Rand.RandSync.ServerAndClient),
652  cargoRoom.Rect.Y - cargoRoom.Rect.Height + itemPrefab.Size.Y / 2);
653  }
654  }
655 
657  {
658  public AbilityMissionMoneyGainMultiplier(Mission mission, float moneyGainMultiplier)
659  {
660  Value = moneyGainMultiplier;
661  Mission = mission;
662  }
663  public float Value { get; set; }
664  public Mission Mission { get; set; }
665  }
666 
668  {
669  public AbilityMissionExperienceGainMultiplier(Mission mission, float missionExperienceGainMultiplier, Character character)
670  {
671  Value = missionExperienceGainMultiplier;
672  Mission = mission;
673  Character = character;
674  }
675 
676  public float Value { get; set; }
677  public Mission Mission { get; set; }
678  public Character Character { get; set; }
679  }
680 
682  {
683  public AbilityMissionReputationGainMultiplier(Mission mission, float reputationMultiplier, Character character)
684  {
685  Value = reputationMultiplier;
686  Mission = mission;
687  Character = character;
688  }
689 
690  public float Value { get; set; }
691  public Mission Mission { get; set; }
692  public Character Character { get; set; }
693  }
694 
695 }
AbilityMissionExperienceGainMultiplier(Mission mission, float missionExperienceGainMultiplier, Character character)
AbilityMissionReputationGainMultiplier(Mission mission, float reputationMultiplier, Character character)
static Character Create(CharacterInfo characterInfo, Vector2 position, string seed, ushort id=Entity.NullEntityID, bool isRemotePlayer=false, bool hasAi=true, RagdollParams ragdoll=null, bool spawnInitialItems=true)
Create a new character
static void CheckTalentsForCrew(IEnumerable< Character > crew, AbilityEffectType type, AbilityObject abilityObject)
Checks talents for a given AbilityObject taking into account non-stackable talents.
Can be used to check arbitrary campaign metadata set using SetDataAction.
ContentXElement? GetChildElement(string name)
Submarine Submarine
Definition: Entity.cs:53
static GameSession?? GameSession
Definition: GameMain.cs:88
static NetworkMember NetworkMember
Definition: GameMain.cs:190
static ImmutableHashSet< Character > GetSessionCrewCharacters(CharacterType type)
Returns a list of crew characters currently in the game with a given filter.
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:228
void InitializeCharacter(Character npc, ISpatialEntity positionToStayIn=null)
Definition: HumanPrefab.cs:164
bool GiveItems(Character character, Submarine submarine, WayPoint spawnPoint, Rand.RandSync randSync=Rand.RandSync.Unsynced, bool createNetworkEvents=true)
Definition: HumanPrefab.cs:205
List< Item > FindAllItems(Func< Item, bool > predicate=null, bool recursive=false, List< Item > list=null)
Defines a point in the event that GoTo actions can jump to.
Definition: Label.cs:7
LocalizedString Replace(Identifier find, LocalizedString replace, StringComparison stringComparison=StringComparison.Ordinal)
Reputation Reputation
Definition: Location.cs:103
readonly int CooldownAfterChange
The location can't change it's type for this many turns after this location type changes occurs
static readonly PrefabCollection< LocationType > Prefabs
Definition: LocationType.cs:15
Mersenne Twister based random
Definition: MTRandom.cs:9
static readonly List< MapEntity > MapEntityList
bool IsLayerHidden
Is the layer this entity is in currently hidden? If it is, the entity is not updated and should do no...
static MapEntityPrefab Find(string name, string identifier=null, bool showErrorMessages=true)
Find a matching map entity prefab
LocalizedString ReplaceVariablesInMissionMessage(LocalizedString message, Submarine sub, bool replaceReward=true)
int GetReward(Submarine sub)
Calculates the available reward, taking into account universal modifiers such as campaign settings
static Character CreateHuman(HumanPrefab humanPrefab, List< Character > characters, Dictionary< Character, List< Item >> characterItems, Submarine submarine, CharacterTeamType teamType, ISpatialEntity positionToStayIn=null, Rand.RandSync humanPrefabRandSync=Rand.RandSync.ServerAndClient)
virtual LocalizedString ModifyMessage(LocalizedString message, bool color=true)
static Mission LoadRandom(Location[] locations, MTRandom rand, bool requireCorrectLocationType, MissionType missionType, bool isSinglePlayer=false, float? difficultyLevel=null)
readonly ImmutableArray< LocalizedString > Headers
static int GetRewardDistibutionSum(IEnumerable< Character > crew, int rewardDistribution=0)
abstract bool DetermineCompleted()
virtual IEnumerable<(LocalizedString Label, Vector2 Position)> SonarLabels
Location OriginLocation
Where was this mission received from? Affects which faction we give reputation for if the mission is ...
static Mission LoadRandom(Location[] locations, string seed, bool requireCorrectLocationType, MissionType missionType, bool isSinglePlayer=false, float? difficultyLevel=null)
ImmutableList< MissionPrefab.ReputationReward > ReputationRewards
Mission(MissionPrefab prefab, Location[] locations, Submarine sub)
Vector2? GetCargoSpawnPosition(ItemPrefab itemPrefab, out Submarine cargoRoomSub)
int GetFinalReward(Submarine sub)
Get the final reward, taking talent bonuses into account if the mission has concluded and the talents...
readonly ImmutableArray< LocalizedString > Messages
virtual int GetBaseReward(Submarine sub)
Calculates the base reward, can be overridden for different mission types
void End()
End the mission and give a reward if it was completed successfully
static readonly PrefabCollection< MissionPrefab > Prefabs
readonly List<(Identifier Identifier, object Value, SetDataAction.OperationType OperationType)> DataRewards
Mission Instantiate(Location[] locations, Submarine sub)
Prefab(ContentFile file, Identifier identifier)
Definition: Prefab.cs:40
ContentPackage? ContentPackage
Definition: Prefab.cs:37
void AddReputation(float reputationChange, float maxReputationChangePerRound=float.MaxValue)
Definition: Reputation.cs:95
static WayPoint GetRandom(SpawnType spawnType=SpawnType.Human, JobPrefab assignedJob=null, Submarine sub=null, bool useSyncedRand=false, string spawnPointTag=null, bool ignoreSubmarine=false)
AbilityEffectType
Definition: Enums.cs:125
CharacterType
Definition: Enums.cs:685
StatTypes
StatTypes are used to alter several traits of a character. They are mostly used by talents.
Definition: Enums.cs:180