Unstable 1.2.1.0
This commit is contained in:
@@ -34,7 +34,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (prefab.ConfigElement.GetAttribute("itemname") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in ArtifactEvent - use item identifier instead of the name of the item.");
|
||||
DebugConsole.ThrowError("Error in ArtifactEvent - use item identifier instead of the name of the item.",
|
||||
contentPackage: prefab?.ContentPackage);
|
||||
string itemName = prefab.ConfigElement.GetAttributeString("itemname", "");
|
||||
itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab;
|
||||
if (itemPrefab == null)
|
||||
@@ -44,11 +45,12 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
string itemIdentifier = prefab.ConfigElement.GetAttributeString("itemidentifier", "");
|
||||
itemPrefab = MapEntityPrefab.Find(null, itemIdentifier) as ItemPrefab;
|
||||
Identifier itemIdentifier = prefab.ConfigElement.GetAttributeIdentifier("itemidentifier", Identifier.Empty);
|
||||
itemPrefab = MapEntityPrefab.FindByIdentifier(itemIdentifier) as ItemPrefab;
|
||||
if (itemPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in ArtifactEvent - couldn't find an item prefab with the identifier " + itemIdentifier);
|
||||
DebugConsole.ThrowError("Error in ArtifactEvent - couldn't find an item prefab with the identifier " + itemIdentifier,
|
||||
contentPackage: prefab?.ContentPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Barotrauma
|
||||
|
||||
public Event(EventPrefab prefab)
|
||||
{
|
||||
this.prefab = prefab;
|
||||
this.prefab = prefab ?? throw new ArgumentNullException(nameof(prefab));
|
||||
}
|
||||
|
||||
public virtual IEnumerable<ContentFile> GetFilesToPreload()
|
||||
|
||||
+6
-3
@@ -14,12 +14,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (TargetTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction with no target tag! This will cause the check to automatically succeed.");
|
||||
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction with no target tag! This will cause the check to automatically succeed.",
|
||||
contentPackage: parentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
Conditional = PropertyConditional.FromXElement(element, IsNotTargetTagAttribute).FirstOrDefault();
|
||||
if (Conditional == null)
|
||||
{
|
||||
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction with no valid PropertyConditional! This will cause the check to automatically succeed.");
|
||||
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckConditionalAction with no valid PropertyConditional! This will cause the check to automatically succeed.",
|
||||
contentPackage: parentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
|
||||
static bool IsNotTargetTagAttribute(XAttribute attribute) => attribute.NameAsIdentifier() != "targettag";
|
||||
@@ -46,7 +48,8 @@ namespace Barotrauma
|
||||
}
|
||||
if (target == null)
|
||||
{
|
||||
DebugConsole.LogError($"{nameof(CheckConditionalAction)} error: {GetEventName()} uses a {nameof(CheckConditionalAction)} but no valid target was found for tag \"{TargetTag}\"! This will cause the check to automatically succeed.");
|
||||
DebugConsole.LogError($"{nameof(CheckConditionalAction)} error: {GetEventName()} uses a {nameof(CheckConditionalAction)} but no valid target was found for tag \"{TargetTag}\"! This will cause the check to automatically succeed.",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
if (target == null || Conditional == null)
|
||||
{
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Barotrauma
|
||||
Condition = element.GetAttributeString("value", string.Empty)!;
|
||||
if (string.IsNullOrEmpty(Condition))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in scripted event \"{parentEvent.Prefab.Identifier}\". CheckDataAction with no condition set ({element}).");
|
||||
DebugConsole.ThrowError($"Error in scripted event \"{parentEvent.Prefab.Identifier}\". CheckDataAction with no condition set ({element}).",
|
||||
contentPackage: element?.ContentPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +43,8 @@ namespace Barotrauma
|
||||
Condition = element.GetAttributeString("value", string.Empty)!;
|
||||
if (string.IsNullOrEmpty(Condition))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in scripted event \"{parentDebugString}\". CheckDataAction with no condition set ({element}).");
|
||||
DebugConsole.ThrowError($"Error in scripted event \"{parentDebugString}\". CheckDataAction with no condition set ({element}).",
|
||||
contentPackage: element?.ContentPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +61,8 @@ namespace Barotrauma
|
||||
(Operator, string value) = PropertyConditional.ExtractComparisonOperatorFromConditionString(Condition);
|
||||
if (Operator == PropertyConditional.ComparisonOperatorType.None)
|
||||
{
|
||||
DebugConsole.ThrowError($"{Condition} is invalid, it should start with an operator followed by a boolean or a floating point value.");
|
||||
DebugConsole.ThrowError($"{Condition} is invalid, it should start with an operator followed by a boolean or a floating point value.",
|
||||
contentPackage: ParentEvent?.Prefab?.ContentPackage);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,8 @@ namespace Barotrauma
|
||||
ItemIdentifiers.None() &&
|
||||
TargetTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". {nameof(CheckItemAction)} does't define either tags or identifiers of the item to check.");
|
||||
DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". {nameof(CheckItemAction)} does't define either tags or identifiers of the item to check.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
checkPercentage = element.GetAttribute(nameof(RequiredConditionalMatchPercentage)) is not null;
|
||||
if (checkPercentage && conditionals.None())
|
||||
@@ -86,7 +87,8 @@ namespace Barotrauma
|
||||
}
|
||||
if (Amount != 1 && checkPercentage)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". Cannot define both '{Amount}' and '{RequiredConditionalMatchPercentage}' in {nameof(CheckItemAction)}.");
|
||||
DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". Cannot define both '{Amount}' and '{RequiredConditionalMatchPercentage}' in {nameof(CheckItemAction)}.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ namespace Barotrauma
|
||||
var targetCharacters = ParentEvent.GetTargets(TargetTag);
|
||||
if (targetCharacters.None())
|
||||
{
|
||||
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckOrderAction but no valid target characters were found for tag \"{TargetTag}\"! This will cause the check to automatically fail.");
|
||||
DebugConsole.LogError($"CheckConditionalAction error: {GetEventName()} uses a CheckOrderAction but no valid target characters were found for tag \"{TargetTag}\"! This will cause the check to automatically fail.",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
return false;
|
||||
}
|
||||
foreach (var t in targetCharacters)
|
||||
|
||||
+4
-4
@@ -1,7 +1,5 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -31,7 +29,8 @@ namespace Barotrauma
|
||||
}
|
||||
default:
|
||||
{
|
||||
DebugConsole.ThrowError("CheckReputationAction requires a \"TargetType\" but none were specified.");
|
||||
DebugConsole.ThrowError("CheckReputationAction requires a \"TargetType\" but none were specified.",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -41,7 +40,8 @@ namespace Barotrauma
|
||||
|
||||
protected override bool GetBool(CampaignMode campaignMode)
|
||||
{
|
||||
DebugConsole.ThrowError("Boolean comparison cannot be applied to reputations.");
|
||||
DebugConsole.ThrowError("Boolean comparison cannot be applied to reputations.",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,13 +87,13 @@ namespace Barotrauma
|
||||
#if DEBUG
|
||||
void Error(string errorMsg)
|
||||
{
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
DebugConsole.ThrowError(errorMsg, contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
#else
|
||||
|
||||
void Error(string errorMsg)
|
||||
{
|
||||
DebugConsole.LogError(errorMsg);
|
||||
DebugConsole.LogError(errorMsg, contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
+2
-1
@@ -17,7 +17,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Cannot use the action {nameof(CheckTraitorEventStateAction)} in the event \"{parentEvent.Prefab.Identifier}\" because it's not a traitor event.");
|
||||
DebugConsole.ThrowError($"Cannot use the action {nameof(CheckTraitorEventStateAction)} in the event \"{parentEvent.Prefab.Identifier}\" because it's not a traitor event.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -16,7 +16,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (parentEvent is not TraitorEvent)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\" - {nameof(CheckTraitorVoteAction)} can only be used in traitor events.");
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\" - {nameof(CheckTraitorVoteAction)} can only be used in traitor events.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,8 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.ThrowError(
|
||||
$"Error in {nameof(EventObjectiveAction)} in the event \"{parentEvent.Prefab.Identifier}\"" +
|
||||
$" - unrecognized child element \"Replace\".");
|
||||
$" - unrecognized child element \"Replace\".",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,14 +61,16 @@ namespace Barotrauma
|
||||
}
|
||||
if (MinAmount > MaxAmount && MaxAmount > -1)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". {MinAmount} is larger than {MaxAmount} in {nameof(CountTargetsAction)}.");
|
||||
DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". {MinAmount} is larger than {MaxAmount} in {nameof(CountTargetsAction)}.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MinPercentageRelativeToTarget < 0.0f && MaxPercentageRelativeToTarget < 0.0f)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". Comparing to another target, but neither {nameof(MinPercentageRelativeToTarget)} or {nameof(MaxPercentageRelativeToTarget)} is set.");
|
||||
DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". Comparing to another target, but neither {nameof(MinPercentageRelativeToTarget)} or {nameof(MaxPercentageRelativeToTarget)} is set.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (e.Name.ToString().Equals("statuseffect", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event prefab \"{scriptedEvent.Prefab.Identifier}\". Status effect configured as a sub action (text: \"{Text}\"). Please configure status effects as child elements of a StatusEffectAction.");
|
||||
DebugConsole.ThrowError($"Error in event prefab \"{scriptedEvent.Prefab.Identifier}\". Status effect configured as a sub action (text: \"{Text}\"). Please configure status effects as child elements of a StatusEffectAction.",
|
||||
contentPackage: elem.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
var action = Instantiate(scriptedEvent, e);
|
||||
@@ -102,7 +103,7 @@ namespace Barotrauma
|
||||
|
||||
public EventAction(ScriptedEvent parentEvent, ContentXElement element)
|
||||
{
|
||||
ParentEvent = parentEvent;
|
||||
ParentEvent = parentEvent ?? throw new ArgumentNullException(nameof(parentEvent));
|
||||
SerializableProperty.DeserializeProperties(this, element);
|
||||
}
|
||||
|
||||
@@ -147,7 +148,8 @@ namespace Barotrauma
|
||||
}
|
||||
catch
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not find an {nameof(EventAction)} class of the type \"{element.Name}\".");
|
||||
DebugConsole.ThrowError($"Could not find an {nameof(EventAction)} class of the type \"{element.Name}\".",
|
||||
contentPackage: element.ContentPackage);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -162,7 +164,8 @@ namespace Barotrauma
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugConsole.ThrowError(ex.InnerException != null ? ex.InnerException.ToString() : ex.ToString());
|
||||
DebugConsole.ThrowError(ex.InnerException != null ? ex.InnerException.ToString() : ex.ToString(),
|
||||
contentPackage: element.ContentPackage);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (Id == Identifier.Empty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\". {nameof(EventLogAction)} with no id.");
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\". {nameof(EventLogAction)} with no id.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
//append the target tag so logs targeted to different players don't interfere with each other even if they use the same Id
|
||||
Id = (Id.ToString() + TargetTag).ToIdentifier();
|
||||
@@ -42,7 +43,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (Text.IsNullOrEmpty())
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\". {nameof(EventLogAction)} with no text set ({element}).");
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\". {nameof(EventLogAction)} with no text set ({element}).",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+4
-2
@@ -49,13 +49,15 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.ThrowError(
|
||||
$"Error in {nameof(EventObjectiveAction)} in the event \"{parentEvent.Prefab.Identifier}\""+
|
||||
$" - {nameof(TextTag)} will do nothing unless the action triggers a message box or a video.");
|
||||
$" - {nameof(TextTag)} will do nothing unless the action triggers a message box or a video.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
if (element.GetChildElement("Replace") != null)
|
||||
{
|
||||
DebugConsole.ThrowError(
|
||||
$"Error in {nameof(EventObjectiveAction)} in the event \"{parentEvent.Prefab.Identifier}\"" +
|
||||
$" - unrecognized child element \"Replace\".");
|
||||
$" - unrecognized child element \"Replace\".",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (TargetTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": {nameof(GiveExpAction)} without a target tag (the action needs to know whose skill to check).");
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": {nameof(GiveExpAction)} without a target tag (the action needs to know whose skill to check).",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (TargetTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": {nameof(GiveSkillExpAction)} without a target tag (the action needs to know whose skill to check).");
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": {nameof(GiveSkillExpAction)} without a target tag (the action needs to know whose skill to check).",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (MissionIdentifier.IsEmpty && MissionTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": neither MissionIdentifier or MissionTag has been configured.");
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": neither MissionIdentifier or MissionTag has been configured.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
if (!MissionIdentifier.IsEmpty && !MissionTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": both MissionIdentifier or MissionTag have been configured. The tag will be ignored.");
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": both MissionIdentifier or MissionTag have been configured. The tag will be ignored.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
LocationTypes = element.GetAttributeIdentifierArray("locationtype", Array.Empty<Identifier>()).ToImmutableArray();
|
||||
random = new MTRandom(parentEvent.RandomSeed);
|
||||
@@ -103,11 +105,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (!MissionIdentifier.IsEmpty)
|
||||
{
|
||||
unlockedMission = unlockLocation.UnlockMissionByIdentifier(MissionIdentifier);
|
||||
unlockedMission = unlockLocation.UnlockMissionByIdentifier(MissionIdentifier,
|
||||
invokingContentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
else if (!MissionTag.IsEmpty)
|
||||
{
|
||||
unlockedMission = unlockLocation.UnlockMissionByTag(MissionTag, random);
|
||||
unlockedMission = unlockLocation.UnlockMissionByTag(MissionTag, random,
|
||||
invokingContentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
if (campaign is MultiPlayerCampaign mpCampaign)
|
||||
{
|
||||
@@ -139,7 +143,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.AddWarning($"Failed to find a suitable location to unlock the mission \"{missionDebugId}\" (LocationType: {string.Join(", ", LocationTypes)}, MinLocationDistance: {MinLocationDistance}, UnlockFurtherOnMap: {UnlockFurtherOnMap})");
|
||||
DebugConsole.AddWarning($"Failed to find a suitable location to unlock the mission \"{missionDebugId}\" (LocationType: {string.Join(", ", LocationTypes)}, MinLocationDistance: {MinLocationDistance}, UnlockFurtherOnMap: {UnlockFurtherOnMap})",
|
||||
ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
isFinished = true;
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace Barotrauma
|
||||
State = element.GetAttributeInt("value", State);
|
||||
if (MissionIdentifier.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": MissionIdentifier has not been configured.");
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": MissionIdentifier has not been configured.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -43,7 +43,8 @@ namespace Barotrauma
|
||||
var faction = campaign.Factions.Find(f => f.Prefab.Identifier == Faction);
|
||||
if (faction == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in ModifyLocationAction ({ParentEvent.Prefab.Identifier}): could not find a faction with the identifier \"{Faction}\".");
|
||||
DebugConsole.ThrowError($"Error in ModifyLocationAction ({ParentEvent.Prefab.Identifier}): could not find a faction with the identifier \"{Faction}\".",
|
||||
contentPackage: ParentEvent?.Prefab?.ContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -55,7 +56,8 @@ namespace Barotrauma
|
||||
var secondaryFaction = campaign.Factions.Find(f => f.Prefab.Identifier == SecondaryFaction);
|
||||
if (secondaryFaction == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in ModifyLocationAction ({ParentEvent.Prefab.Identifier}): could not find a faction with the identifier \"{SecondaryFaction}\".");
|
||||
DebugConsole.ThrowError($"Error in ModifyLocationAction ({ParentEvent.Prefab.Identifier}): could not find a faction with the identifier \"{SecondaryFaction}\".",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -67,7 +69,8 @@ namespace Barotrauma
|
||||
var locationType = LocationType.Prefabs.Find(lt => lt.Identifier == Type);
|
||||
if (locationType == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in ModifyLocationAction ({ParentEvent.Prefab.Identifier}): could not find a location type with the identifier \"{Type}\".");
|
||||
DebugConsole.ThrowError($"Error in ModifyLocationAction ({ParentEvent.Prefab.Identifier}): could not find a location type with the identifier \"{Type}\".",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
else if (!location.LocationTypeChangesBlocked)
|
||||
{
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Barotrauma
|
||||
var enums = Enum.GetValues(typeof(CharacterTeamType)).Cast<CharacterTeamType>();
|
||||
if (!enums.Contains(TeamID))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in {nameof(NPCChangeTeamAction)} in the event {ParentEvent.Prefab.Identifier}. \"{TeamID}\" is not a valid Team ID. Valid values are {string.Join(',', Enum.GetNames(typeof(CharacterTeamType)))}.");
|
||||
DebugConsole.ThrowError($"Error in {nameof(NPCChangeTeamAction)} in the event {ParentEvent.Prefab.Identifier}. \"{TeamID}\" is not a valid Team ID. Valid values are {string.Join(',', Enum.GetNames(typeof(CharacterTeamType)))}.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,11 +13,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (Chance >= 1.0f)
|
||||
{
|
||||
DebugConsole.ThrowError($"Incorrectly configured RNG Action in event \"{parentEvent.Prefab.Identifier}\". Probability is 1.0 (100%) or more, the action will always succeed.");
|
||||
DebugConsole.ThrowError($"Incorrectly configured RNG Action in event \"{parentEvent.Prefab.Identifier}\". Probability is 1.0 (100%) or more, the action will always succeed.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
else if (Chance <= 0.0f)
|
||||
{
|
||||
DebugConsole.ThrowError($"Incorrectly configured RNG Action in event \"{parentEvent.Prefab.Identifier}\". Probability is 0 or less, the action will never succeed.");
|
||||
DebugConsole.ThrowError($"Incorrectly configured RNG Action in event \"{parentEvent.Prefab.Identifier}\". Probability is 0 or less, the action will never succeed.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Faction with the identifier \"{Identifier}\" was not found.");
|
||||
DebugConsole.ThrowError($"Faction with the identifier \"{Identifier}\" was not found.",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -66,7 +67,8 @@ namespace Barotrauma
|
||||
}
|
||||
default:
|
||||
{
|
||||
DebugConsole.ThrowError("ReputationAction requires a \"TargetType\" but none were specified.");
|
||||
DebugConsole.ThrowError("ReputationAction requires a \"TargetType\" but none were specified.",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Cannot use the action {nameof(SetTraitorEventStateAction)} in the event \"{parentEvent.Prefab.Identifier}\" because it's not a traitor event.");
|
||||
DebugConsole.ThrowError($"Cannot use the action {nameof(SetTraitorEventStateAction)} in the event \"{parentEvent.Prefab.Identifier}\" because it's not a traitor event.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (TargetTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": SkillCheckAction without a target tag (the action needs to know whose skill to check).");
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": SkillCheckAction without a target tag (the action needs to know whose skill to check).",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,8 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.ThrowError(
|
||||
$"Error in even \"{(parentEvent.Prefab?.Identifier.ToString() ?? "unknown")}\". " +
|
||||
$"The attribute \"submarinetype\" is not valid in {nameof(SpawnAction)}. Did you mean {nameof(SpawnLocation)}?");
|
||||
$"The attribute \"submarinetype\" is not valid in {nameof(SpawnAction)}. Did you mean {nameof(SpawnLocation)}?",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +234,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (MapEntityPrefab.FindByIdentifier(ItemIdentifier) is not ItemPrefab itemPrefab)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in SpawnAction (item prefab \"" + ItemIdentifier + "\" not found)");
|
||||
DebugConsole.ThrowError("Error in SpawnAction (item prefab \"" + ItemIdentifier + "\" not found)",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -256,7 +258,8 @@ namespace Barotrauma
|
||||
|
||||
if (spawnInventory == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not spawn \"{ItemIdentifier}\" in target inventory \"{TargetInventory}\" - matching target not found.");
|
||||
DebugConsole.ThrowError($"Could not spawn \"{ItemIdentifier}\" in target inventory \"{TargetInventory}\" - matching target not found.",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,19 @@ namespace Barotrauma
|
||||
|
||||
private bool isFinished = false;
|
||||
|
||||
private bool targetNotFound = false;
|
||||
/// <summary>
|
||||
/// If the action tags some entities directly (not trying to find targets on the fly),
|
||||
/// we may be able to determine that targets can not be found even if we'd recheck
|
||||
/// </summary>
|
||||
private bool cantFindTargets = false;
|
||||
|
||||
/// <summary>
|
||||
/// If the TagAction adds a target predicate (a criteria that keeps finding targets on the fly),
|
||||
/// we must keep checking if targets have been found to determine if the action can continue or not
|
||||
/// </summary>
|
||||
private bool mustRecheckTargets = false;
|
||||
|
||||
private bool taggingDone = false;
|
||||
|
||||
public TagAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
|
||||
{
|
||||
@@ -198,6 +210,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
ParentEvent.AddTargetPredicate(tag, predicate);
|
||||
mustRecheckTargets = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +218,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (entities.None())
|
||||
{
|
||||
targetNotFound = true;
|
||||
cantFindTargets = true;
|
||||
return;
|
||||
}
|
||||
if (ChoosePercentage > 0.0f)
|
||||
@@ -230,7 +243,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (entities.None())
|
||||
{
|
||||
targetNotFound = true;
|
||||
cantFindTargets = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -250,7 +263,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (entities.None())
|
||||
{
|
||||
targetNotFound = true;
|
||||
cantFindTargets = true;
|
||||
return;
|
||||
}
|
||||
ParentEvent.AddTarget(tag, entities.GetRandomUnsynced());
|
||||
@@ -260,26 +273,30 @@ namespace Barotrauma
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (isFinished || targetNotFound) { return; }
|
||||
if (isFinished || cantFindTargets) { return; }
|
||||
|
||||
string[] criteriaSplit = Criteria.Split(';');
|
||||
|
||||
targetNotFound = false;
|
||||
foreach (string entry in criteriaSplit)
|
||||
if (!taggingDone)
|
||||
{
|
||||
string[] kvp = entry.Split(':');
|
||||
Identifier key = kvp[0].Trim().ToIdentifier();
|
||||
Identifier value = kvp.Length > 1 ? kvp[1].Trim().ToIdentifier() : Identifier.Empty;
|
||||
if (Taggers.TryGetValue(key, out Action<Identifier> tagger))
|
||||
cantFindTargets = false;
|
||||
string[] criteriaSplit = Criteria.Split(';');
|
||||
foreach (string entry in criteriaSplit)
|
||||
{
|
||||
tagger(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMessage = $"Error in TagAction (event \"{ParentEvent.Prefab.Identifier}\") - unrecognized target criteria \"{key}\".";
|
||||
DebugConsole.ThrowError(errorMessage);
|
||||
GameAnalyticsManager.AddErrorEventOnce($"TagAction.Update:InvalidCriteria_{ParentEvent.Prefab.Identifier}_{key}", GameAnalyticsManager.ErrorSeverity.Error, errorMessage);
|
||||
string[] kvp = entry.Split(':');
|
||||
Identifier key = kvp[0].Trim().ToIdentifier();
|
||||
Identifier value = kvp.Length > 1 ? kvp[1].Trim().ToIdentifier() : Identifier.Empty;
|
||||
if (Taggers.TryGetValue(key, out Action<Identifier> tagger))
|
||||
{
|
||||
tagger(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMessage = $"Error in TagAction (event \"{ParentEvent.Prefab.Identifier}\") - unrecognized target criteria \"{key}\".";
|
||||
DebugConsole.ThrowError(errorMessage,
|
||||
contentPackage: ParentEvent.Prefab?.ContentPackage);
|
||||
GameAnalyticsManager.AddErrorEventOnce($"TagAction.Update:InvalidCriteria_{ParentEvent.Prefab.Identifier}_{key}", GameAnalyticsManager.ErrorSeverity.Error, errorMessage);
|
||||
}
|
||||
}
|
||||
taggingDone = true;
|
||||
}
|
||||
|
||||
if (ContinueIfNoTargetsFound)
|
||||
@@ -288,7 +305,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
isFinished = !targetNotFound;
|
||||
if (mustRecheckTargets)
|
||||
{
|
||||
isFinished = ParentEvent.GetTargets(Tag).Any();
|
||||
}
|
||||
else
|
||||
{
|
||||
isFinished = !cantFindTargets;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
var eventPrefab = EventSet.GetEventPrefab(Identifier);
|
||||
if (eventPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in TriggerEventAction - could not find an event with the identifier {Identifier}.");
|
||||
DebugConsole.ThrowError($"Error in TriggerEventAction - could not find an event with the identifier {Identifier}.",
|
||||
contentPackage: ParentEvent.Prefab.ContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@ partial class TutorialHighlightAction : EventAction
|
||||
{
|
||||
if (GameMain.NetworkMember != null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": {nameof(TutorialHighlightAction)} is not supported in multiplayer.");
|
||||
DebugConsole.ThrowError($"Error in event \"{parentEvent.Prefab.Identifier}\": {nameof(TutorialHighlightAction)} is not supported in multiplayer.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -28,7 +28,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (ItemTag.IsEmpty && ItemIdentifier.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". {nameof(WaitForItemFabricatedAction)} does't define either a tag or an identifier of the item to check.");
|
||||
DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". {nameof(WaitForItemFabricatedAction)} does't define either a tag or an identifier of the item to check.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
foreach (var item in Item.ItemList)
|
||||
{
|
||||
|
||||
@@ -518,7 +518,8 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Identifier missingId in subEventPrefab.GetMissingIdentifiers())
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event set \"{eventSet.Identifier}\" ({eventSet.ContentFile?.ContentPackage?.Name ?? "null"}) - could not find an event prefab with the identifier \"{missingId}\".");
|
||||
DebugConsole.ThrowError($"Error in event set \"{eventSet.Identifier}\" ({eventSet.ContentFile?.ContentPackage?.Name ?? "null"}) - could not find an event prefab with the identifier \"{missingId}\".",
|
||||
contentPackage: eventSet.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,16 +10,48 @@ namespace Barotrauma
|
||||
|
||||
public readonly ContentXElement ConfigElement;
|
||||
public readonly Type EventType;
|
||||
|
||||
/// <summary>
|
||||
/// The probability for the event to do something if it gets selected. For example, the probability for a MonsterEvent to spawn the monster(s).
|
||||
/// </summary>
|
||||
public readonly float Probability;
|
||||
|
||||
/// <summary>
|
||||
/// When this event occurs, should it trigger the event cooldown during which no new events are triggered?
|
||||
/// </summary>
|
||||
public readonly bool TriggerEventCooldown;
|
||||
|
||||
/// <summary>
|
||||
/// The commonness of the event (i.e. how likely it is for this specific event to be chosen from the event set it's configured in).
|
||||
/// Only valid if the event set is configured to choose a random event (as opposed to just executing all the events in the set).
|
||||
/// </summary>
|
||||
public readonly float Commonness;
|
||||
|
||||
/// <summary>
|
||||
/// If set, the event set can only be chosen in this biome.
|
||||
/// </summary>
|
||||
public readonly Identifier BiomeIdentifier;
|
||||
|
||||
/// <summary>
|
||||
/// If set, the event set can only be chosen in locations that belong to this faction.
|
||||
/// </summary>
|
||||
public readonly Identifier Faction;
|
||||
|
||||
public readonly LocalizedString Name;
|
||||
|
||||
/// <summary>
|
||||
/// If set, this event is used as an event that can unlock a path to the next biome.
|
||||
/// </summary>
|
||||
public readonly bool UnlockPathEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Only valid if UnlockPathEvent is set to true. The tooltip displayed on the pathway this event is blocking.
|
||||
/// </summary>
|
||||
public readonly string UnlockPathTooltip;
|
||||
|
||||
/// <summary>
|
||||
/// Only valid if UnlockPathEvent is set to true. The reputation requirement displayed on the pathway this event is blocking.
|
||||
/// </summary>
|
||||
public readonly int UnlockPathReputation;
|
||||
|
||||
public static EventPrefab Create(ContentXElement element, RandomEventsFile file, Identifier fallbackIdentifier = default)
|
||||
@@ -44,12 +76,14 @@ namespace Barotrauma
|
||||
EventType = Type.GetType("Barotrauma." + ConfigElement.Name, true, true);
|
||||
if (EventType == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not find an event class of the type \"" + ConfigElement.Name + "\".");
|
||||
DebugConsole.ThrowError("Could not find an event class of the type \"" + ConfigElement.Name + "\".",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
DebugConsole.ThrowError("Could not find an event class of the type \"" + ConfigElement.Name + "\".");
|
||||
DebugConsole.ThrowError("Could not find an event class of the type \"" + ConfigElement.Name + "\".",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
|
||||
Name = TextManager.Get($"eventname.{Identifier}").Fallback(Identifier.ToString());
|
||||
|
||||
@@ -23,6 +23,10 @@ namespace Barotrauma
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Event sets are sets of random events that occur within a level (most commonly, monster spawns and scripted events).
|
||||
/// Event sets can also be nested: a "parent set" can choose from several "subsets", either randomly or by some kind of criteria.
|
||||
/// </summary>
|
||||
sealed class EventSet : Prefab
|
||||
{
|
||||
internal class EventDebugStats
|
||||
@@ -78,21 +82,48 @@ namespace Barotrauma
|
||||
return GetAllEventPrefabs().Find(prefab => prefab.Identifier == identifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If enabled, this set can only be chosen in the campaign mode.
|
||||
/// </summary>
|
||||
public readonly bool IsCampaignSet;
|
||||
|
||||
//0-100
|
||||
public readonly float MinLevelDifficulty, MaxLevelDifficulty;
|
||||
/// <summary>
|
||||
/// The difficulty of the current level must be equal to or higher than this for this set to be chosen.
|
||||
/// </summary>
|
||||
public readonly float MinLevelDifficulty;
|
||||
/// <summary>
|
||||
/// The difficulty of the current level must be equal to or less than this for this set to be chosen.
|
||||
/// </summary>
|
||||
public readonly float MaxLevelDifficulty;
|
||||
|
||||
/// <summary>
|
||||
/// If set, the event set can only be chosen in this biome.
|
||||
/// </summary>
|
||||
public readonly Identifier BiomeIdentifier;
|
||||
|
||||
/// <summary>
|
||||
/// If set, the event set can only be chosen in this type of level (outpost level or a connection between outpost levels).
|
||||
/// </summary>
|
||||
public readonly LevelData.LevelType LevelType;
|
||||
|
||||
/// <summary>
|
||||
/// If set, the event set can only be chosen in locations of this type.
|
||||
/// </summary>
|
||||
public readonly ImmutableArray<Identifier> LocationTypeIdentifiers;
|
||||
|
||||
/// <summary>
|
||||
/// If set, the event set can only be chosen in locations that belong to this faction.
|
||||
/// </summary>
|
||||
public readonly Identifier Faction;
|
||||
|
||||
/// <summary>
|
||||
/// If set, one event, or a sub event set, is chosen randomly from this set.
|
||||
/// </summary>
|
||||
public readonly bool ChooseRandom;
|
||||
|
||||
/// <summary>
|
||||
/// Only valid if ChooseRandom is enabled. How many random events to choose from the set?
|
||||
/// </summary>
|
||||
private readonly int eventCount = 1;
|
||||
public readonly int SubSetCount = 1;
|
||||
private readonly Dictionary<Identifier, int> overrideEventCount = new Dictionary<Identifier, int>();
|
||||
@@ -102,47 +133,100 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public readonly bool Exhaustible;
|
||||
|
||||
/// <summary>
|
||||
/// The event set won't become active until the submarine has travelled at least this far. A value between 0-1, where 0 is the beginning of the level and 1 the end of the level (e.g. 0.5 would mean the sub needs to be half-way through the level).
|
||||
/// </summary>
|
||||
public readonly float MinDistanceTraveled;
|
||||
|
||||
/// <summary>
|
||||
/// The event set won't become active until the round has lasted at least this many seconds.
|
||||
/// </summary>
|
||||
public readonly float MinMissionTime;
|
||||
|
||||
//the events in this set are delayed if the current EventManager intensity is not between these values
|
||||
public readonly float MinIntensity, MaxIntensity;
|
||||
|
||||
/// <summary>
|
||||
/// If the event is not allowed at start, it won't become active until the submarine has moved at least 50 meters away from the beginning of the level. Only valid in LocationConnections (levels between locations).
|
||||
/// </summary>
|
||||
public readonly bool AllowAtStart;
|
||||
|
||||
/// <summary>
|
||||
/// Normally an event (such as a monster spawn) triggers a cooldown during which no new events are created. This can be used to ignore the cooldown.
|
||||
/// </summary>
|
||||
public readonly bool IgnoreCoolDown;
|
||||
|
||||
/// <summary>
|
||||
/// Should this event set trigger the event cooldown (during which no new events are created) when it becomes active?
|
||||
/// </summary>
|
||||
public readonly bool TriggerEventCooldown;
|
||||
|
||||
/// <summary>
|
||||
/// Normally events can only trigger if the intensity of the situation is low enough (e.g. you won't get new monster spawns if the submarine is already facing a disaster). This can be used to ignore the intensity.
|
||||
/// </summary>
|
||||
public readonly bool IgnoreIntensity;
|
||||
|
||||
public readonly bool PerRuin, PerCave, PerWreck;
|
||||
/// <summary>
|
||||
/// The set is applied once per each ruin in the level. Can be used to ensure there's a consistent amount of monster spawns in the ruins in the level regardless of how many there are (and that no ruin monsters spawn if there are no ruins).
|
||||
/// </summary>
|
||||
public readonly bool PerRuin;
|
||||
|
||||
/// <summary>
|
||||
/// The set is applied once per each cave in the level. Can be used to ensure there's a consistent amount of monster spawns in the cave in the level regardless of how many there are (and that no cave monsters spawn if there are no caves).
|
||||
/// </summary>
|
||||
public readonly bool PerCave;
|
||||
|
||||
/// <summary>
|
||||
/// The set is applied once per each wreck in the level. Can be used to ensure there's a consistent amount of monster spawns in the wreck in the level regardless of how many there are (and that no wreck monsters spawn if there are no wreck).
|
||||
/// </summary>
|
||||
public readonly bool PerWreck;
|
||||
|
||||
/// <summary>
|
||||
/// If enabled, this event will not be applied if the level contains hunting grounds.
|
||||
/// </summary>
|
||||
public readonly bool DisableInHuntingGrounds;
|
||||
|
||||
/// <summary>
|
||||
/// If true, events from this set can only occur once in the level.
|
||||
/// If enabled, events from this set can only occur once in the level.
|
||||
/// </summary>
|
||||
public readonly bool OncePerLevel;
|
||||
|
||||
/// <summary>
|
||||
/// Should the event set be delayed if at least half of the crew is away from the submarine? The maximum amount of time the events can get delayed is defined in event manager settings (<see cref="EventManagerSettings.FreezeDurationWhenCrewAway"/>)
|
||||
/// </summary>
|
||||
public readonly bool DelayWhenCrewAway;
|
||||
|
||||
public readonly bool TriggerEventCooldown;
|
||||
|
||||
/// <summary>
|
||||
/// Additive sets are important to be aware of when creating custom event sets! If an additive set gets chosen for a level, the game will also select a non-additive one.
|
||||
/// This means you can for example configure an additive set that spawns custom monsters (and make it very common if you want the monsters to spawn frequently), which will spawn those custom
|
||||
/// monsters in addition to the vanilla monsters spawned by vanilla sets, without you having to add your custom monsters to every single vanilla set.
|
||||
/// </summary>
|
||||
public readonly bool Additive;
|
||||
|
||||
/// <summary>
|
||||
/// The commonness of the event set (i.e. how likely it is for this specific set to be chosen).
|
||||
/// </summary>
|
||||
public readonly float DefaultCommonness;
|
||||
public readonly ImmutableDictionary<Identifier, float> OverrideCommonness;
|
||||
|
||||
/// <summary>
|
||||
/// If set, the event set can trigger again after this amount of seconds has passed since it last triggered.
|
||||
/// </summary>
|
||||
public readonly float ResetTime;
|
||||
|
||||
/// <summary>
|
||||
/// Used to force an event set based on how many other locations have been discovered before this. (Used for campaign tutorial event sets.)
|
||||
/// Used to force an event set based on how many other locations have been discovered before this (used for campaign tutorial event sets).
|
||||
/// </summary>
|
||||
public readonly int ForceAtDiscoveredNr;
|
||||
|
||||
/// <summary>
|
||||
/// Used to force an event set based on how many other outposts have been visited before this. (Used for campaign tutorial event sets.)
|
||||
/// Used to force an event set based on how many other outposts have been visited before this (used for campaign tutorial event sets).
|
||||
/// </summary>
|
||||
public readonly int ForceAtVisitedNr;
|
||||
|
||||
/// <summary>
|
||||
/// If enabled, this set can only occur when the campaign tutorial is enabled (generally used for the tutorial events).
|
||||
/// </summary>
|
||||
public readonly bool CampaignTutorialOnly;
|
||||
|
||||
public readonly struct SubEventPrefab
|
||||
@@ -224,7 +308,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.AddWarning($"{file.Path}: All root EventSets should have an identifier");
|
||||
DebugConsole.AddWarning($"{file.Path}: All root EventSets should have an identifier",
|
||||
file.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +349,8 @@ namespace Barotrauma
|
||||
string levelTypeStr = element.GetAttributeString("leveltype", parentSet?.LevelType.ToString() ?? "LocationConnection");
|
||||
if (!Enum.TryParse(levelTypeStr, true, out LevelType))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event set \"{Identifier}\". \"{levelTypeStr}\" is not a valid level type.");
|
||||
DebugConsole.ThrowError($"Error in event set \"{Identifier}\". \"{levelTypeStr}\" is not a valid level type.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
|
||||
Faction = element.GetAttributeIdentifier(nameof(Faction), Identifier.Empty);
|
||||
@@ -304,7 +390,8 @@ namespace Barotrauma
|
||||
ForceAtVisitedNr = element.GetAttributeInt(nameof(ForceAtVisitedNr), -1);
|
||||
if (ForceAtDiscoveredNr >= 0 && ForceAtVisitedNr >= 0)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error with event set \"{Identifier}\" - both ForceAtDiscoveredNr and ForceAtVisitedNr are defined, this could lead to unexpected behavior");
|
||||
DebugConsole.ThrowError($"Error with event set \"{Identifier}\" - both ForceAtDiscoveredNr and ForceAtVisitedNr are defined, this could lead to unexpected behavior",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
|
||||
DefaultCommonness = element.GetAttributeFloat("commonness", 1.0f);
|
||||
|
||||
+10
-6
@@ -123,7 +123,8 @@ namespace Barotrauma
|
||||
var itemsToDestroy = Item.ItemList.FindAll(it => it.Submarine?.Info.Type != SubmarineType.Player && it.HasTag(itemTag));
|
||||
if (!itemsToDestroy.Any())
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in mission \"{Prefab.Identifier}\". Could not find an item with the tag \"{itemTag}\".");
|
||||
DebugConsole.ThrowError($"Error in mission \"{Prefab.Identifier}\". Could not find an item with the tag \"{itemTag}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -135,10 +136,11 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (XElement element in itemConfig.Elements())
|
||||
{
|
||||
string itemIdentifier = element.GetAttributeString("identifier", "");
|
||||
if (!(MapEntityPrefab.Find(null, itemIdentifier) is ItemPrefab itemPrefab))
|
||||
Identifier itemIdentifier = element.GetAttributeIdentifier("identifier", Identifier.Empty);
|
||||
if (MapEntityPrefab.FindByIdentifier(itemIdentifier) is not ItemPrefab itemPrefab)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't spawn item for outpost destroy mission: item prefab \"" + itemIdentifier + "\" not found");
|
||||
DebugConsole.ThrowError("Couldn't spawn item for outpost destroy mission: item prefab \"" + itemIdentifier + "\" not found",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -189,7 +191,8 @@ namespace Barotrauma
|
||||
HumanPrefab humanPrefab = GetHumanPrefabFromElement(element);
|
||||
if (humanPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Couldn't spawn a human character for abandoned outpost mission: human prefab \"{element.GetAttributeString("identifier", string.Empty)}\" not found");
|
||||
DebugConsole.ThrowError($"Couldn't spawn a human character for abandoned outpost mission: human prefab \"{element.GetAttributeString("identifier", string.Empty)}\" not found",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < count; i++)
|
||||
@@ -203,7 +206,8 @@ namespace Barotrauma
|
||||
var characterPrefab = CharacterPrefab.FindBySpeciesName(speciesName);
|
||||
if (characterPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Couldn't spawn a character for abandoned outpost mission: character prefab \"{speciesName}\" not found");
|
||||
DebugConsole.ThrowError($"Couldn't spawn a character for abandoned outpost mission: character prefab \"{speciesName}\" not found",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < count; i++)
|
||||
|
||||
@@ -51,12 +51,14 @@ namespace Barotrauma
|
||||
TargetRuin = Level.Loaded?.Ruins?.GetRandom(randSync: Rand.RandSync.ServerAndClient);
|
||||
if (TargetRuin == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to initialize an Alien Ruin mission (\"{Prefab.Identifier}\"): level contains no alien ruins");
|
||||
DebugConsole.ThrowError($"Failed to initialize an Alien Ruin mission (\"{Prefab.Identifier}\"): level contains no alien ruins",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
if (targetItemIdentifiers.Length < 1 && targetEnemyIdentifiers.Length < 1)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to initialize an Alien Ruin mission (\"{Prefab.Identifier}\"): no target identifiers set in the mission definition");
|
||||
DebugConsole.ThrowError($"Failed to initialize an Alien Ruin mission (\"{Prefab.Identifier}\"): no target identifiers set in the mission definition",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
foreach (var item in Item.ItemList)
|
||||
@@ -88,12 +90,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): could not find a character prefab with the species \"{identifier}\"");
|
||||
DebugConsole.ThrowError($"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): could not find a character prefab with the species \"{identifier}\"",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
if (enemyPrefabs.None())
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): no enemy species defined that could be used to spawn more ({minEnemyCount - existingEnemyCount}) enemies");
|
||||
DebugConsole.ThrowError($"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): no enemy species defined that could be used to spawn more ({minEnemyCount - existingEnemyCount}) enemies",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < (minEnemyCount - existingEnemyCount); i++)
|
||||
@@ -102,7 +106,8 @@ namespace Barotrauma
|
||||
var spawnPos = TargetRuin.Submarine.GetWaypoints(false).GetRandomUnsynced(w => w.CurrentHull != null)?.WorldPosition;
|
||||
if (!spawnPos.HasValue)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): no valid spawn positions could be found for the additional ({minEnemyCount - existingEnemyCount}) enemies to be spawned");
|
||||
DebugConsole.ThrowError($"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): no valid spawn positions could be found for the additional ({minEnemyCount - existingEnemyCount}) enemies to be spawned",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
var newEnemy = Character.Create(prefab.Identifier, spawnPos.Value, ToolBox.RandomSeed(8), createNetworkEvent: false);
|
||||
@@ -151,7 +156,8 @@ namespace Barotrauma
|
||||
#if DEBUG
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in Alien Ruin mission (\"{Prefab.Identifier}\"): unexpected target of type {target?.GetType()?.ToString()}");
|
||||
DebugConsole.ThrowError($"Error in Alien Ruin mission (\"{Prefab.Identifier}\"): unexpected target of type {target?.GetType()?.ToString()}",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
sonarLabel = TextManager.Get("beaconstationsonarlabel");
|
||||
DebugConsole.NewMessage("Initialized beacon mission: " + prefab.Identifier, Color.LightSkyBlue, debugOnly: true);
|
||||
}
|
||||
|
||||
private void LoadMonsters(XElement monsterElement, MonsterSet set)
|
||||
@@ -65,7 +66,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in beacon mission \"{Prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".");
|
||||
DebugConsole.ThrowError($"Error in beacon mission \"{Prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -238,7 +238,8 @@ namespace Barotrauma
|
||||
|
||||
if (itemConfig == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to initialize items for cargo mission (itemConfig == null)");
|
||||
DebugConsole.ThrowError("Failed to initialize items for cargo mission (itemConfig == null)",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -262,7 +263,7 @@ namespace Barotrauma
|
||||
SpawnedInCurrentOutpost = true,
|
||||
AllowStealing = false
|
||||
};
|
||||
item.AddTag("cargomission");
|
||||
item.AddTag(Tags.CargoMissionItem);
|
||||
item.AddTag(Prefab.Identifier);
|
||||
foreach (var tag in Prefab.Tags)
|
||||
{
|
||||
|
||||
@@ -110,12 +110,14 @@ namespace Barotrauma
|
||||
bossPrefab = CharacterPrefab.FindBySpeciesName(speciesName);
|
||||
if (bossPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in end mission \"{prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".");
|
||||
DebugConsole.ThrowError($"Error in end mission \"{prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in end mission \"{prefab.Identifier}\". Monster file not set.");
|
||||
DebugConsole.ThrowError($"Error in end mission \"{prefab.Identifier}\". Monster file not set.",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
|
||||
Identifier minionName = prefab.ConfigElement.GetAttributeIdentifier("minionfile", Identifier.Empty);
|
||||
@@ -124,7 +126,8 @@ namespace Barotrauma
|
||||
minionPrefab = CharacterPrefab.FindBySpeciesName(minionName);
|
||||
if (minionPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in end mission \"{prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".");
|
||||
DebugConsole.ThrowError($"Error in end mission \"{prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +140,8 @@ namespace Barotrauma
|
||||
projectilePrefab = MapEntityPrefab.FindByIdentifier(projectileId) as ItemPrefab;
|
||||
if (projectilePrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in end mission \"{prefab.Identifier}\". Could not find an item prefab with the name \"{projectileId}\".");
|
||||
DebugConsole.ThrowError($"Error in end mission \"{prefab.Identifier}\". Could not find an item prefab with the name \"{projectileId}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +156,8 @@ namespace Barotrauma
|
||||
bossSpawnPoint = WayPoint.WayPointList.FirstOrDefault(wp => wp.Tags.Contains(spawnPointTag));
|
||||
if (bossSpawnPoint == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in end mission \"{Prefab.Identifier}\". Could not find a spawn point \"{spawnPointTag}\".");
|
||||
DebugConsole.ThrowError($"Error in end mission \"{Prefab.Identifier}\". Could not find a spawn point \"{spawnPointTag}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
if (!IsClient)
|
||||
@@ -171,14 +176,16 @@ namespace Barotrauma
|
||||
}
|
||||
if (destructibleItemTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in end mission \"{Prefab.Identifier}\". Destructible item tag not set.");
|
||||
DebugConsole.ThrowError($"Error in end mission \"{Prefab.Identifier}\". Destructible item tag not set.",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
destructibleItems.Clear();
|
||||
destructibleItems.AddRange(Item.ItemList.FindAll(it => it.HasTag(destructibleItemTag)));
|
||||
if (destructibleItems.None())
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in end mission \"{Prefab.Identifier}\". Could not find any destructible items with the tag \"{spawnPointTag}\".");
|
||||
DebugConsole.ThrowError($"Error in end mission \"{Prefab.Identifier}\". Could not find any destructible items with the tag \"{spawnPointTag}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (inMission)
|
||||
{
|
||||
DebugConsole.ThrowError("MainSub was null when trying to retrieve submarine size for determining escorted character count!");
|
||||
DebugConsole.ThrowError("MainSub was null when trying to retrieve submarine size for determining escorted character count!",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -180,7 +181,8 @@ namespace Barotrauma
|
||||
|
||||
if (scalingCharacterCount * characterConfig.Elements().Count() != characters.Count)
|
||||
{
|
||||
DebugConsole.AddWarning("Character count did not match expected character count in InitCharacters of EscortMission");
|
||||
DebugConsole.AddWarning("Character count did not match expected character count in InitCharacters of EscortMission",
|
||||
Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
int i = 0;
|
||||
@@ -220,7 +222,8 @@ namespace Barotrauma
|
||||
|
||||
if (characterConfig == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to initialize characters for escort mission (characterConfig == null)");
|
||||
DebugConsole.ThrowError("Failed to initialize characters for escort mission (characterConfig == null)",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -258,7 +261,7 @@ namespace Barotrauma
|
||||
{
|
||||
character.Speak(TextManager.Get("dialogterroristannounce").Value, null, Rand.Range(0.5f, 3f));
|
||||
}
|
||||
XElement randomElement = itemConfig.Elements().GetRandomUnsynced(e => e.GetAttributeFloat(0f, "mindifficulty") <= Level.Loaded.Difficulty);
|
||||
ContentXElement randomElement = itemConfig.Elements().GetRandomUnsynced(e => e.GetAttributeFloat(0f, "mindifficulty") <= Level.Loaded.Difficulty);
|
||||
if (randomElement != null)
|
||||
{
|
||||
HumanPrefab.InitializeItem(character, randomElement, character.Submarine, humanPrefab: null, createNetworkEvents: true);
|
||||
|
||||
@@ -119,14 +119,16 @@ namespace Barotrauma
|
||||
{
|
||||
if (MapEntityPrefab.FindByIdentifier(identifier) is not ItemPrefab prefab)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in MineralMission: couldn't find an item prefab (identifier: \"{identifier}\")");
|
||||
DebugConsole.ThrowError($"Error in MineralMission: couldn't find an item prefab (identifier: \"{identifier}\")",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
|
||||
var spawnedResources = level.GenerateMissionResources(prefab, amount, positionType, caves);
|
||||
if (spawnedResources.Count < amount)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in MineralMission: spawned only {spawnedResources.Count}/{amount} of {prefab.Name}");
|
||||
DebugConsole.ThrowError($"Error in MineralMission: spawned only {spawnedResources.Count}/{amount} of {prefab.Name}",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
|
||||
if (spawnedResources.None()) { continue; }
|
||||
|
||||
@@ -347,7 +347,8 @@ namespace Barotrauma
|
||||
var eventPrefab = EventSet.GetAllEventPrefabs().Find(p => p.Identifier == trigger.EventIdentifier);
|
||||
if (eventPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Mission \"{Name}\" failed to trigger an event (couldn't find an event with the identifier \"{trigger.EventIdentifier}\").");
|
||||
DebugConsole.ThrowError($"Mission \"{Name}\" failed to trigger an event (couldn't find an event with the identifier \"{trigger.EventIdentifier}\").",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
if (GameMain.GameSession?.EventManager != null)
|
||||
@@ -378,7 +379,7 @@ namespace Barotrauma
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Unknown error while giving mission rewards.";
|
||||
DebugConsole.ThrowError(errorMsg, e);
|
||||
DebugConsole.ThrowError(errorMsg, e, contentPackage: Prefab.ContentPackage);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Mission.End:GiveReward", GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + e.StackTrace);
|
||||
#if SERVER
|
||||
GameMain.Server?.SendChatMessage(errorMsg + "\n" + e.StackTrace, Networking.ChatMessageType.Error);
|
||||
@@ -547,7 +548,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (element.Attribute("name") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in mission \"" + Name + "\" - use character identifiers instead of names to configure the characters.");
|
||||
DebugConsole.ThrowError($"Error in mission \"{Name}\" - use character identifiers instead of names to configure the characters.",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -556,7 +558,8 @@ namespace Barotrauma
|
||||
HumanPrefab humanPrefab = NPCSet.Get(characterFrom, characterIdentifier);
|
||||
if (humanPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Couldn't spawn character for mission: character prefab \"{characterIdentifier}\" not found in the NPC set \"{characterFrom}\".");
|
||||
DebugConsole.ThrowError($"Couldn't spawn character for mission: character prefab \"{characterIdentifier}\" not found in the NPC set \"{characterFrom}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -587,12 +590,14 @@ namespace Barotrauma
|
||||
ItemPrefab itemPrefab;
|
||||
if (element.Attribute("name") != null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in mission \"{Name}\" - use item identifiers instead of names to configure the items");
|
||||
DebugConsole.ThrowError($"Error in mission \"{Name}\" - use item identifiers instead of names to configure the items",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
string itemName = element.GetAttributeString("name", "");
|
||||
itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab;
|
||||
if (itemPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Couldn't spawn item for mission \"{Name}\": item prefab \"{itemName}\" not found");
|
||||
DebugConsole.ThrowError($"Couldn't spawn item for mission \"{Name}\": item prefab \"{itemName}\" not found",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -601,7 +606,8 @@ namespace Barotrauma
|
||||
itemPrefab = MapEntityPrefab.Find(null, itemIdentifier) as ItemPrefab;
|
||||
if (itemPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Couldn't spawn item for mission \"{Name}\": item prefab \"{itemIdentifier}\" not found");
|
||||
DebugConsole.ThrowError($"Couldn't spawn item for mission \"{Name}\": item prefab \"{itemIdentifier}\" not found",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
return itemPrefab;
|
||||
@@ -614,14 +620,16 @@ namespace Barotrauma
|
||||
WayPoint cargoSpawnPos = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub, useSyncedRand: true);
|
||||
if (cargoSpawnPos == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Couldn't spawn items for mission \"{Name}\": no waypoints marked as Cargo were found");
|
||||
DebugConsole.ThrowError($"Couldn't spawn items for mission \"{Name}\": no waypoints marked as Cargo were found",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return null;
|
||||
}
|
||||
|
||||
var cargoRoom = cargoSpawnPos.CurrentHull;
|
||||
if (cargoRoom == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Couldn't spawn items for mission \"{Name}\": waypoints marked as Cargo must be placed inside a room");
|
||||
DebugConsole.ThrowError($"Couldn't spawn items for mission \"{Name}\": waypoints marked as Cargo must be placed inside a room",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,8 +94,19 @@ namespace Barotrauma
|
||||
DataRewards = new List<(Identifier Identifier, object Value, SetDataAction.OperationType OperationType)>();
|
||||
|
||||
public readonly int Commonness;
|
||||
/// <summary>
|
||||
/// Displayed difficulty (indicator)
|
||||
/// </summary>
|
||||
public readonly int? Difficulty;
|
||||
public const int MinDifficulty = 1, MaxDifficulty = 4;
|
||||
/// <summary>
|
||||
/// The actual minimum difficulty of the level allowed for this mission to trigger.
|
||||
/// </summary>
|
||||
public readonly int MinLevelDifficulty = 0;
|
||||
/// <summary>
|
||||
/// The actual maximum difficulty of the level allowed for this mission to trigger.
|
||||
/// </summary>
|
||||
public readonly int MaxLevelDifficulty = 100;
|
||||
|
||||
public readonly int Reward;
|
||||
|
||||
@@ -211,6 +222,10 @@ namespace Barotrauma
|
||||
int difficulty = element.GetAttributeInt("difficulty", MinDifficulty);
|
||||
Difficulty = Math.Clamp(difficulty, MinDifficulty, MaxDifficulty);
|
||||
}
|
||||
MinLevelDifficulty = element.GetAttributeInt(nameof(MinLevelDifficulty), MinLevelDifficulty);
|
||||
MaxLevelDifficulty = element.GetAttributeInt(nameof(MaxLevelDifficulty), MaxLevelDifficulty);
|
||||
MinLevelDifficulty = Math.Clamp(MinLevelDifficulty, 0, Math.Min(MaxLevelDifficulty, 100));
|
||||
MaxLevelDifficulty = Math.Clamp(MaxLevelDifficulty, Math.Max(MinLevelDifficulty, 0), 100);
|
||||
|
||||
ShowProgressBar = element.GetAttributeBool(nameof(ShowProgressBar), false);
|
||||
ShowProgressInNumbers = element.GetAttributeBool(nameof(ShowProgressInNumbers), false);
|
||||
@@ -372,7 +387,8 @@ namespace Barotrauma
|
||||
}
|
||||
if (constructor == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to find a constructor for the mission type \"{Type}\"!");
|
||||
DebugConsole.ThrowError($"Failed to find a constructor for the mission type \"{Type}\"!",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
|
||||
InitProjSpecific(element);
|
||||
|
||||
@@ -48,7 +48,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in monster mission \"{prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".");
|
||||
DebugConsole.ThrowError($"Error in monster mission \"{prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".",
|
||||
contentPackage: prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +79,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in monster mission \"{prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".");
|
||||
DebugConsole.ThrowError($"Error in monster mission \"{prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".",
|
||||
contentPackage: prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,19 +120,19 @@ namespace Barotrauma
|
||||
float minDistBetweenMonsterMissions = 10000;
|
||||
float mindDistFromSub = Level.Loaded.Size.X * 0.3f;
|
||||
var monsterMissions = GameMain.GameSession.Missions.Select(e => e as MonsterMission).Where(m => m != null && m != this && m.spawnPos.HasValue);
|
||||
if (!Level.Loaded.TryGetInterestingPosition(useSyncedRand: true, spawnPosType, mindDistFromSub, out Vector2 spawnPos,
|
||||
if (!Level.Loaded.TryGetInterestingPosition(useSyncedRand: true, spawnPosType, mindDistFromSub, out Level.InterestingPosition spawnPos,
|
||||
filter: p => monsterMissions.None(m => Vector2.DistanceSquared(p.Position.ToVector2(), m.spawnPos.Value) < minDistBetweenMonsterMissions * minDistBetweenMonsterMissions),
|
||||
suppressWarning: true))
|
||||
{
|
||||
Level.Loaded.TryGetInterestingPosition(useSyncedRand: true, spawnPosType, mindDistFromSub, out spawnPos);
|
||||
}
|
||||
this.spawnPos = spawnPos;
|
||||
this.spawnPos = spawnPos.Position.ToVector2();
|
||||
foreach (var (character, amountRange) in monsterPrefabs)
|
||||
{
|
||||
int amount = Rand.Range(amountRange.X, amountRange.Y + 1);
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
monsters.Add(Character.Create(character.Identifier, spawnPos, ToolBox.RandomSeed(8), createNetworkEvent: false));
|
||||
monsters.Add(Character.Create(character.Identifier, this.spawnPos.Value, ToolBox.RandomSeed(8), createNetworkEvent: false));
|
||||
}
|
||||
}
|
||||
InitializeMonsters(monsters);
|
||||
|
||||
@@ -85,7 +85,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in monster mission \"{prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".");
|
||||
DebugConsole.ThrowError($"Error in monster mission \"{prefab.Identifier}\". Could not find a character prefab with the name \"{speciesName}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +175,8 @@ namespace Barotrauma
|
||||
var itemIdentifier = subElement.GetAttributeIdentifier("identifier", Identifier.Empty);
|
||||
if (MapEntityPrefab.FindByIdentifier(itemIdentifier) is not ItemPrefab itemPrefab)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't spawn item for nest mission: item prefab \"" + itemIdentifier + "\" not found");
|
||||
DebugConsole.ThrowError("Couldn't spawn item for nest mission: item prefab \"" + itemIdentifier + "\" not found",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -285,7 +287,8 @@ namespace Barotrauma
|
||||
}
|
||||
if (Level.Loaded.IsPositionInsideWall(nestPosition))
|
||||
{
|
||||
DebugConsole.AddWarning($"Error in nest mission \"{Prefab.Identifier}\": nest position was inside a wall ({nestPosition}).");
|
||||
DebugConsole.AddWarning($"Error in nest mission \"{Prefab.Identifier}\": nest position was inside a wall ({nestPosition}).",
|
||||
Prefab.ContentPackage);
|
||||
}
|
||||
monsterPrefabs.Clear();
|
||||
break;
|
||||
|
||||
@@ -11,9 +11,9 @@ namespace Barotrauma
|
||||
{
|
||||
partial class PirateMission : Mission
|
||||
{
|
||||
private readonly XElement submarineTypeConfig;
|
||||
private readonly XElement characterConfig;
|
||||
private readonly XElement characterTypeConfig;
|
||||
private readonly ContentXElement submarineTypeConfig;
|
||||
private readonly ContentXElement characterConfig;
|
||||
private readonly ContentXElement characterTypeConfig;
|
||||
private readonly float addedMissionDifficultyPerPlayer;
|
||||
|
||||
private float missionDifficulty;
|
||||
@@ -103,7 +103,8 @@ namespace Barotrauma
|
||||
var characterTypeElement = characterTypeConfig.Elements().FirstOrDefault(e => e.GetAttributeString("typeidentifier", string.Empty) == characterId);
|
||||
if (characterTypeElement == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in mission \"{prefab.Identifier}\". Could not find a character type element for the character \"{characterId}\".");
|
||||
DebugConsole.ThrowError($"Error in mission \"{prefab.Identifier}\". Could not find a character type element for the character \"{characterId}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
//make sure all defined character types can be found from human prefabs
|
||||
@@ -116,7 +117,8 @@ namespace Barotrauma
|
||||
HumanPrefab humanPrefab = NPCSet.Get(characterFrom, characterIdentifier);
|
||||
if (humanPrefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in mission \"{prefab.Identifier}\". Character prefab \"{characterIdentifier}\" not found in the NPC set \"{characterFrom}\".");
|
||||
DebugConsole.ThrowError($"Error in mission \"{prefab.Identifier}\". Character prefab \"{characterIdentifier}\" not found in the NPC set \"{characterFrom}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,7 +153,8 @@ namespace Barotrauma
|
||||
ContentPath submarinePath = submarineConfig.GetAttributeContentPath("path", Prefab.ContentPackage);
|
||||
if (submarinePath.IsNullOrEmpty())
|
||||
{
|
||||
DebugConsole.ThrowError($"No path used for submarine for the pirate mission \"{Prefab.Identifier}\"!");
|
||||
DebugConsole.ThrowError($"No path used for submarine for the pirate mission \"{Prefab.Identifier}\"!",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -165,7 +168,8 @@ namespace Barotrauma
|
||||
|
||||
if (contentFile == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"No submarine file found from the path {submarinePath}!");
|
||||
DebugConsole.ThrowError($"No submarine file found from the path {submarinePath}!",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -201,16 +205,28 @@ namespace Barotrauma
|
||||
|
||||
private void CreateMissionPositions(out Vector2 preferredSpawnPos)
|
||||
{
|
||||
Vector2 patrolPos = enemySub.WorldPosition;
|
||||
Vector2 patrolPos = Level.Loaded.EndPosition;
|
||||
Point subSize = enemySub.GetDockedBorders().Size;
|
||||
|
||||
if (!Level.Loaded.TryGetInterestingPosition(true, Level.PositionType.MainPath, Level.Loaded.Size.X * 0.3f, out preferredSpawnPos))
|
||||
preferredSpawnPos = Level.Loaded.EndPosition;
|
||||
|
||||
if (Level.Loaded.TryGetInterestingPosition(true, Level.PositionType.MainPath, Level.Loaded.Size.X * 0.3f, out var potentialSpawnPos))
|
||||
{
|
||||
DebugConsole.ThrowError("Could not spawn pirate submarine in an interesting location! " + this);
|
||||
preferredSpawnPos = potentialSpawnPos.Position.ToVector2();
|
||||
}
|
||||
if (!Level.Loaded.TryGetInterestingPositionAwayFromPoint(true, Level.PositionType.MainPath, Level.Loaded.Size.X * 0.3f, out patrolPos, preferredSpawnPos, minDistFromPoint: 10000f))
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Could not give pirate submarine an interesting location to patrol to! " + this);
|
||||
DebugConsole.ThrowError("Could not spawn pirate submarine in an interesting location! " + this,
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
if (Level.Loaded.TryGetInterestingPositionAwayFromPoint(true, Level.PositionType.MainPath, Level.Loaded.Size.X * 0.3f, out var potentialPatrolPos, preferredSpawnPos, minDistFromPoint: 10000f))
|
||||
{
|
||||
patrolPos = potentialPatrolPos.Position.ToVector2();
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Could not give pirate submarine an interesting location to patrol to! " + this,
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
|
||||
patrolPos = enemySub.FindSpawnPos(patrolPos, subSize);
|
||||
@@ -266,7 +282,8 @@ namespace Barotrauma
|
||||
|
||||
if (characterConfig == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to initialize characters for escort mission (characterConfig == null)");
|
||||
DebugConsole.ThrowError("Failed to initialize characters for escort mission (characterConfig == null)",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -281,7 +298,7 @@ namespace Barotrauma
|
||||
Random rand = new MTRandom(ToolBox.StringToInt(levelData.Seed));
|
||||
|
||||
bool commanderAssigned = false;
|
||||
foreach (XElement element in characterConfig.Elements())
|
||||
foreach (ContentXElement element in characterConfig.Elements())
|
||||
{
|
||||
// it is possible to get more than the "max" amount of characters if the modified difficulty is high enough; this is intentional
|
||||
// if necessary, another "hard max" value could be used to clamp the value for performance/gameplay concerns
|
||||
@@ -293,7 +310,8 @@ namespace Barotrauma
|
||||
|
||||
if (characterType == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"No character types defined in CharacterTypes for a declared type identifier in mission \"{Prefab.Identifier}\".");
|
||||
DebugConsole.ThrowError($"No character types defined in CharacterTypes for a declared type identifier in mission \"{Prefab.Identifier}\".",
|
||||
contentPackage: element.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -356,12 +374,12 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.ThrowError(submarineInfo == null ?
|
||||
$"Error in PirateMission: enemy sub was not created (submarineInfo == null)." :
|
||||
$"Error in PirateMission: enemy sub was not created.");
|
||||
$"Error in PirateMission: enemy sub was not created.",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 spawnPos = Level.Loaded.EndPosition; // in case TryGetInterestingPosition fails, though this should not happen
|
||||
CreateMissionPositions(out spawnPos); // patrol positions are not explicitly replicated, instead they are acquired the same way the server acquires them
|
||||
CreateMissionPositions(out Vector2 spawnPos); // patrol positions are not explicitly replicated, instead they are acquired the same way the server acquires them
|
||||
#if DEBUG
|
||||
if (IsClient)
|
||||
{
|
||||
|
||||
@@ -106,12 +106,14 @@ namespace Barotrauma
|
||||
|
||||
if (element.GetAttribute("itemname") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in SalvageMission - use item identifier instead of the name of the item.");
|
||||
DebugConsole.ThrowError("Error in SalvageMission - use item identifier instead of the name of the item.",
|
||||
contentPackage: element.ContentPackage);
|
||||
string itemName = element.GetAttributeString("itemname", "");
|
||||
ItemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab;
|
||||
if (ItemPrefab == null && ExistingItemTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in SalvageMission: couldn't find an item prefab with the name \"{itemName}\"");
|
||||
DebugConsole.ThrowError($"Error in SalvageMission: couldn't find an item prefab with the name \"{itemName}\"",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -128,7 +130,8 @@ namespace Barotrauma
|
||||
}
|
||||
if (ItemPrefab == null && ExistingItemTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in SalvageMission - couldn't find an item prefab with the identifier \"{itemIdentifier}\"");
|
||||
DebugConsole.ThrowError($"Error in SalvageMission - couldn't find an item prefab with the identifier \"{itemIdentifier}\"",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +289,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (target.ItemPrefab == null && target.ContainerTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to find a target item for the mission \"{Prefab.Identifier}\". Item tag: {target.ExistingItemTag}");
|
||||
DebugConsole.ThrowError($"Failed to find a target item for the mission \"{Prefab.Identifier}\". Item tag: {target.ExistingItemTag}",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
target.Item = new Item(target.ItemPrefab, position, null);
|
||||
@@ -379,7 +383,8 @@ namespace Barotrauma
|
||||
if (target.Item == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Error in salvage mission " + Prefab.Identifier + " (item was null)");
|
||||
DebugConsole.ThrowError("Error in salvage mission " + Prefab.Identifier + " (item was null)",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,8 @@ namespace Barotrauma
|
||||
|
||||
if (itemConfig == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to initialize a Scan mission: item config is not set");
|
||||
DebugConsole.ThrowError("Failed to initialize a Scan mission: item config is not set",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -77,7 +78,8 @@ namespace Barotrauma
|
||||
TargetRuin = Level.Loaded?.Ruins?.GetRandom(randSync: Rand.RandSync.ServerAndClient);
|
||||
if (TargetRuin == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to initialize a Scan mission: level contains no alien ruins");
|
||||
DebugConsole.ThrowError("Failed to initialize a Scan mission: level contains no alien ruins",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,7 +87,8 @@ namespace Barotrauma
|
||||
ruinWaypoints.RemoveAll(wp => wp.CurrentHull == null);
|
||||
if (ruinWaypoints.Count < targetsToScan)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to initialize a Scan mission: target ruin has less waypoints than required as scan targets ({ruinWaypoints.Count} < {targetsToScan})");
|
||||
DebugConsole.ThrowError($"Failed to initialize a Scan mission: target ruin has less waypoints than required as scan targets ({ruinWaypoints.Count} < {targetsToScan})",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
return;
|
||||
}
|
||||
var availableWaypoints = new List<WayPoint>();
|
||||
@@ -107,7 +110,8 @@ namespace Barotrauma
|
||||
if (availableWaypoints.None())
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets available on try #{tries + 1} to reach the required scan target count (current targets: {scanTargets.Count}, required targets: {targetsToScan})");
|
||||
DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets available on try #{tries + 1} to reach the required scan target count (current targets: {scanTargets.Count}, required targets: {targetsToScan})",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -131,7 +135,8 @@ namespace Barotrauma
|
||||
}
|
||||
if (scanTargets.Count < targetsToScan)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets (current targets: {scanTargets.Count}, required targets: {targetsToScan})");
|
||||
DebugConsole.ThrowError($"Error initializing a Scan mission: not enough targets (current targets: {scanTargets.Count}, required targets: {targetsToScan})",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,45 @@ namespace Barotrauma
|
||||
{
|
||||
class MonsterEvent : Event
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the species to spawn
|
||||
/// </summary>
|
||||
public readonly Identifier SpeciesName;
|
||||
public readonly int MinAmount, MaxAmount;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum amount of monsters to spawn. You can also use "Amount" if you want to spawn a fixed number of monsters.
|
||||
/// </summary>
|
||||
public readonly int MinAmount;
|
||||
/// <summary>
|
||||
/// Maximum amount of monsters to spawn. You can also use "Amount" if you want to spawn a fixed number of monsters.
|
||||
/// </summary>
|
||||
public readonly int MaxAmount;
|
||||
|
||||
private readonly List<Character> monsters = new List<Character>();
|
||||
|
||||
/// <summary>
|
||||
/// The monsters are spawned at least this distance away from the players and submarines.
|
||||
/// </summary>
|
||||
public readonly float SpawnDistance;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of random variance in the spawn position, in pixels. Can be used to prevent all the monsters from spawning at the exact same position.
|
||||
/// </summary>
|
||||
private readonly float scatter;
|
||||
|
||||
/// <summary>
|
||||
/// Used for offsetting the spawns towards the end position of the level, so that they spawn farther afront the sub than normally. In pixels.
|
||||
/// </summary>
|
||||
private readonly float offset;
|
||||
|
||||
/// <summary>
|
||||
/// Delay between spawning the monsters. Only relevant if the event spawns more than one monster.
|
||||
/// </summary>
|
||||
private readonly float delayBetweenSpawns;
|
||||
|
||||
/// <summary>
|
||||
/// Number seconds before the event resets after all the monsters are dead. Can be used to make the event spawn monsters multiple times.
|
||||
/// </summary>
|
||||
private float resetTime;
|
||||
private float resetTimer;
|
||||
|
||||
@@ -25,11 +56,22 @@ namespace Barotrauma
|
||||
|
||||
private bool disallowed;
|
||||
|
||||
/// <summary>
|
||||
/// Where should the monster spawn?
|
||||
/// </summary>
|
||||
public readonly Level.PositionType SpawnPosType;
|
||||
|
||||
/// <summary>
|
||||
/// If set, the monsters will spawn at a spawnpoint that has this tag. Only relevant for events that spawn monsters in a submarine, beacon station, wreck, outpost or ruin.
|
||||
/// </summary>
|
||||
private readonly string spawnPointTag;
|
||||
|
||||
private bool spawnPending, spawnReady;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of the specific type of monster in the entire level. Can be used to prevent the event from spawning more monsters if there's
|
||||
/// already enough of that type of monster, e.g. spawned by another event or by a mission.
|
||||
/// </summary>
|
||||
public readonly int MaxAmountPerLevel = int.MaxValue;
|
||||
|
||||
public IReadOnlyList<Character> Monsters => monsters;
|
||||
@@ -82,13 +124,7 @@ namespace Barotrauma
|
||||
|
||||
MaxAmountPerLevel = prefab.ConfigElement.GetAttributeInt("maxamountperlevel", int.MaxValue);
|
||||
|
||||
var spawnPosTypeStr = prefab.ConfigElement.GetAttributeString("spawntype", "");
|
||||
if (string.IsNullOrWhiteSpace(spawnPosTypeStr) ||
|
||||
!Enum.TryParse(spawnPosTypeStr, true, out SpawnPosType))
|
||||
{
|
||||
SpawnPosType = Level.PositionType.MainPath;
|
||||
}
|
||||
|
||||
SpawnPosType = prefab.ConfigElement.GetAttributeEnum("spawntype", Level.PositionType.MainPath);
|
||||
//backwards compatibility
|
||||
if (prefab.ConfigElement.GetAttributeBool("spawndeep", false))
|
||||
{
|
||||
@@ -127,7 +163,8 @@ namespace Barotrauma
|
||||
var file = CharacterPrefab.FindBySpeciesName(SpeciesName)?.ContentFile;
|
||||
if (file == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to find config file for species \"{SpeciesName}\"");
|
||||
DebugConsole.ThrowError($"Failed to find config file for species \"{SpeciesName}\".",
|
||||
contentPackage: Prefab.ContentPackage);
|
||||
yield break;
|
||||
}
|
||||
else
|
||||
@@ -159,7 +196,8 @@ namespace Barotrauma
|
||||
Character createdCharacter = Character.Create(SpeciesName, Vector2.Zero, seed, characterInfo: null, isRemotePlayer: false, hasAi: true, createNetworkEvent: true, throwErrorIfNotFound: false);
|
||||
if (createdCharacter == null)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error in MonsterEvent: failed to spawn the character \"{SpeciesName}\". Content package: \"{prefab.ConfigElement?.ContentPackage?.Name ?? "unknown"}\".");
|
||||
DebugConsole.AddWarning($"Error in MonsterEvent: failed to spawn the character \"{SpeciesName}\". Content package: \"{prefab.ConfigElement?.ContentPackage?.Name ?? "unknown"}\".",
|
||||
Prefab.ContentPackage);
|
||||
disallowed = true;
|
||||
continue;
|
||||
}
|
||||
@@ -355,29 +393,28 @@ namespace Barotrauma
|
||||
{
|
||||
if (offset > 0)
|
||||
{
|
||||
Vector2 dir;
|
||||
var waypoints = WayPoint.WayPointList.FindAll(wp => wp.Submarine == null && wp.Ruin == null);
|
||||
var nearestWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, spawnPos.Value)).FirstOrDefault();
|
||||
if (nearestWaypoint != null)
|
||||
var tunnelType = chosenPosition.PositionType == Level.PositionType.MainPath ? Level.TunnelType.MainPath : Level.TunnelType.SidePath;
|
||||
var waypoints = WayPoint.WayPointList.FindAll(wp =>
|
||||
wp.Submarine == null &&
|
||||
wp.Ruin == null &&
|
||||
wp.Tunnel?.Type == tunnelType &&
|
||||
wp.WorldPosition.X > spawnPos.Value.X);
|
||||
|
||||
if (waypoints.None())
|
||||
{
|
||||
int currentIndex = waypoints.IndexOf(nearestWaypoint);
|
||||
var nextWaypoint = waypoints[Math.Min(currentIndex + 20, waypoints.Count - 1)];
|
||||
dir = Vector2.Normalize(nextWaypoint.WorldPosition - nearestWaypoint.WorldPosition);
|
||||
// Ensure that the spawn position is not offset to the left.
|
||||
if (dir.X < 0)
|
||||
{
|
||||
dir.X = 0;
|
||||
}
|
||||
DebugConsole.AddWarning($"Failed to find a spawn position offset from {spawnPos.Value}.",
|
||||
Prefab.ContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = new Vector2(1, Rand.Range(-1f, 1f));
|
||||
}
|
||||
Vector2 targetPos = spawnPos.Value + dir * offset;
|
||||
var targetWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, targetPos)).FirstOrDefault();
|
||||
if (targetWaypoint != null)
|
||||
{
|
||||
spawnPos = targetWaypoint.WorldPosition;
|
||||
float offsetSqr = offset * offset;
|
||||
//find the waypoint whose distance from the spawnPos is closest to the desired offset
|
||||
var targetWaypoint = waypoints.OrderBy(wp =>
|
||||
Math.Abs(Vector2.DistanceSquared(wp.WorldPosition, spawnPos.Value) - offsetSqr)).FirstOrDefault();
|
||||
if (targetWaypoint != null)
|
||||
{
|
||||
spawnPos = targetWaypoint.WorldPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure that the position is not inside a submarine (in practice wrecks).
|
||||
|
||||
@@ -50,7 +50,8 @@ namespace Barotrauma
|
||||
}
|
||||
if (elementId == "statuseffect")
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event prefab \"{prefab.Identifier}\". Status effect configured as an action. Please configure status effects as child elements of a StatusEffectAction.");
|
||||
DebugConsole.ThrowError($"Error in event prefab \"{prefab.Identifier}\". Status effect configured as an action. Please configure status effects as child elements of a StatusEffectAction.",
|
||||
contentPackage: prefab.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
var action = EventAction.Instantiate(this, element);
|
||||
@@ -59,7 +60,8 @@ namespace Barotrauma
|
||||
|
||||
if (!Actions.Any())
|
||||
{
|
||||
DebugConsole.ThrowError($"Scripted event \"{prefab.Identifier}\" has no actions. The event will do nothing.");
|
||||
DebugConsole.ThrowError($"Scripted event \"{prefab.Identifier}\" has no actions. The event will do nothing.",
|
||||
contentPackage: prefab.ContentPackage);
|
||||
}
|
||||
|
||||
requiredDestinationTypes = prefab.ConfigElement.GetAttributeStringArray("requireddestinationtypes", null);
|
||||
@@ -69,8 +71,9 @@ namespace Barotrauma
|
||||
foreach (var gotoAction in allActions.OfType<GoTo>())
|
||||
{
|
||||
if (allActions.None(a => a is Label label && label.Name == gotoAction.Name))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{prefab.Identifier}\". Could not find a label matching the GoTo \"{gotoAction.Name}\".");
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in event \"{prefab.Identifier}\". Could not find a label matching the GoTo \"{gotoAction.Name}\".",
|
||||
contentPackage: prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +111,8 @@ namespace Barotrauma
|
||||
if (target is Character character) { return character.Name; }
|
||||
if (target is Hull hull) { return hull.DisplayName.Value; }
|
||||
if (target is Submarine sub) { return sub.Info.DisplayName.Value; }
|
||||
DebugConsole.AddWarning($"Failed to get the name of the event target {target} as a replacement for the tag {tag} in an event text.");
|
||||
DebugConsole.AddWarning($"Failed to get the name of the event target {target} as a replacement for the tag {tag} in an event text.",
|
||||
prefab.ContentPackage);
|
||||
return target.ToString();
|
||||
}
|
||||
else
|
||||
@@ -349,7 +353,8 @@ namespace Barotrauma
|
||||
}
|
||||
if (CurrentActionIndex == -1)
|
||||
{
|
||||
DebugConsole.AddWarning($"Could not find the GoTo label \"{goTo}\" in the event \"{Prefab.Identifier}\". Ending the event.");
|
||||
DebugConsole.AddWarning($"Could not find the GoTo label \"{goTo}\" in the event \"{Prefab.Identifier}\". Ending the event.",
|
||||
prefab.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user