Unstable 0.1500.8.0
This commit is contained in:
@@ -688,8 +688,10 @@ namespace Barotrauma
|
|||||||
new GUIFrame(
|
new GUIFrame(
|
||||||
new RectTransform(Vector2.One * 0.7f, dropdownButton.RectTransform, Anchor.CenterLeft)
|
new RectTransform(Vector2.One * 0.7f, dropdownButton.RectTransform, Anchor.CenterLeft)
|
||||||
{ RelativeOffset = new Vector2(0.05f, 0.0f) }, style: null);
|
{ RelativeOffset = new Vector2(0.05f, 0.0f) }, style: null);
|
||||||
|
Color? previewingColor = null;
|
||||||
dropdown.OnSelected = (component, color) =>
|
dropdown.OnSelected = (component, color) =>
|
||||||
{
|
{
|
||||||
|
previewingColor = null;
|
||||||
setter((Color)color);
|
setter((Color)color);
|
||||||
buttonFrame.Color = getter();
|
buttonFrame.Color = getter();
|
||||||
buttonFrame.HoverColor = getter();
|
buttonFrame.HoverColor = getter();
|
||||||
@@ -727,25 +729,24 @@ namespace Barotrauma
|
|||||||
dropdown.Select(dropdown.ListBox.Content.GetChildIndex(childToSelect));
|
dropdown.Select(dropdown.ListBox.Content.GetChildIndex(childToSelect));
|
||||||
|
|
||||||
//The following exists to track mouseover to preview colors before selecting them
|
//The following exists to track mouseover to preview colors before selecting them
|
||||||
bool previewingColor = false;
|
|
||||||
new GUICustomComponent(new RectTransform(Vector2.One, buttonFrame.RectTransform),
|
new GUICustomComponent(new RectTransform(Vector2.One, buttonFrame.RectTransform),
|
||||||
onUpdate: (deltaTime, component) =>
|
onUpdate: (deltaTime, component) =>
|
||||||
{
|
{
|
||||||
if (GUI.MouseOn is GUIFrame { Parent: { } p } hoveredFrame && dropdown.ListBox.Content.IsParentOf(hoveredFrame))
|
if (GUI.MouseOn is GUIFrame { Parent: { } p } hoveredFrame && dropdown.ListBox.Content.IsParentOf(hoveredFrame))
|
||||||
{
|
{
|
||||||
previewingColor = true;
|
previewingColor ??= getter();
|
||||||
Color color = (Color)(dropdown.ListBox.Content.FindChild(c =>
|
Color color = (Color)(dropdown.ListBox.Content.FindChild(c =>
|
||||||
c == hoveredFrame || c.IsParentOf(hoveredFrame))?.UserData ?? dropdown.SelectedData);
|
c == hoveredFrame || c.IsParentOf(hoveredFrame))?.UserData ?? dropdown.SelectedData ?? getter());
|
||||||
setter(color);
|
setter(color);
|
||||||
buttonFrame.Color = getter();
|
buttonFrame.Color = getter();
|
||||||
buttonFrame.HoverColor = getter();
|
buttonFrame.HoverColor = getter();
|
||||||
}
|
}
|
||||||
else if (previewingColor)
|
else if (previewingColor.HasValue)
|
||||||
{
|
{
|
||||||
setter((Color)dropdown.SelectedData);
|
setter(previewingColor.Value);
|
||||||
buttonFrame.Color = getter();
|
buttonFrame.Color = getter();
|
||||||
buttonFrame.HoverColor = getter();
|
buttonFrame.HoverColor = getter();
|
||||||
previewingColor = false;
|
previewingColor = null;
|
||||||
}
|
}
|
||||||
}, onDraw: null)
|
}, onDraw: null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case ServerNetObject.ENTITY_EVENT:
|
case ServerNetObject.ENTITY_EVENT:
|
||||||
int eventType = msg.ReadRangedInteger(0, 12);
|
int eventType = msg.ReadRangedInteger(0, 13);
|
||||||
switch (eventType)
|
switch (eventType)
|
||||||
{
|
{
|
||||||
case 0: //NetEntityEvent.Type.InventoryState
|
case 0: //NetEntityEvent.Type.InventoryState
|
||||||
@@ -476,6 +476,18 @@ namespace Barotrauma
|
|||||||
int moneyAmount = msg.ReadInt32();
|
int moneyAmount = msg.ReadInt32();
|
||||||
SetMoney(moneyAmount);
|
SetMoney(moneyAmount);
|
||||||
break;
|
break;
|
||||||
|
case 13: //NetEntityEvent.Type.UpdatePermanentStats:
|
||||||
|
byte savedStatValueCount = msg.ReadByte();
|
||||||
|
StatTypes statType = (StatTypes)msg.ReadByte();
|
||||||
|
info?.ClearSavedStatValues(statType);
|
||||||
|
for (int i = 0; i < savedStatValueCount; i++)
|
||||||
|
{
|
||||||
|
string statIdentifier = msg.ReadString();
|
||||||
|
float statValue = msg.ReadSingle();
|
||||||
|
bool removeOnDeath = msg.ReadBoolean();
|
||||||
|
info?.ChangeSavedStatValue(statType, statValue, statIdentifier, removeOnDeath, setValue: true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
msg.ReadPadBits();
|
msg.ReadPadBits();
|
||||||
|
|||||||
@@ -476,6 +476,7 @@ namespace Barotrauma
|
|||||||
if (Screen.Selected == GameMain.SubEditorScreen)
|
if (Screen.Selected == GameMain.SubEditorScreen)
|
||||||
{
|
{
|
||||||
NewMessage("WARNING: Switching directly from the submarine editor to the game view may cause bugs and crashes. Use with caution.", Color.Orange);
|
NewMessage("WARNING: Switching directly from the submarine editor to the game view may cause bugs and crashes. Use with caution.", Color.Orange);
|
||||||
|
Entity.Spawner ??= new EntitySpawner();
|
||||||
}
|
}
|
||||||
GameMain.GameScreen.Select();
|
GameMain.GameScreen.Select();
|
||||||
}));
|
}));
|
||||||
@@ -488,6 +489,8 @@ namespace Barotrauma
|
|||||||
Submarine.MainSub = Submarine.Load(subInfo, true);
|
Submarine.MainSub = Submarine.Load(subInfo, true);
|
||||||
}
|
}
|
||||||
GameMain.SubEditorScreen.Select(enableAutoSave: Screen.Selected != GameMain.GameScreen);
|
GameMain.SubEditorScreen.Select(enableAutoSave: Screen.Selected != GameMain.GameScreen);
|
||||||
|
Entity.Spawner?.Remove();
|
||||||
|
Entity.Spawner = null;
|
||||||
}, isCheat: true));
|
}, isCheat: true));
|
||||||
|
|
||||||
commands.Add(new Command("editparticles|particleeditor", "editparticles/particleeditor: Switch to the Particle Editor to edit particle effects.", (string[] args) =>
|
commands.Add(new Command("editparticles|particleeditor", "editparticles/particleeditor: Switch to the Particle Editor to edit particle effects.", (string[] args) =>
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ namespace Barotrauma
|
|||||||
GameSession.UpdateTalentNotificationIndicator(talentPointNotification);
|
GameSession.UpdateTalentNotificationIndicator(talentPointNotification);
|
||||||
if (Character.Controlled is { } controlled && talentResetButton != null && talentApplyButton != null)
|
if (Character.Controlled is { } controlled && talentResetButton != null && talentApplyButton != null)
|
||||||
{
|
{
|
||||||
int talentCount = selectedTalents.Count - controlled.Info.UnlockedTalents.Count;
|
int talentCount = selectedTalents.Count - controlled.Info.GetUnlockedTalentsInTree().Count();
|
||||||
talentResetButton.Enabled = talentApplyButton.Enabled = talentCount > 0;
|
talentResetButton.Enabled = talentApplyButton.Enabled = talentCount > 0;
|
||||||
if (talentApplyButton.Enabled && talentApplyButton.FlashTimer <= 0.0f)
|
if (talentApplyButton.Enabled && talentApplyButton.FlashTimer <= 0.0f)
|
||||||
{
|
{
|
||||||
@@ -1254,7 +1254,7 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedTalents = controlledCharacter.Info.UnlockedTalents.ToList();
|
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||||
|
|
||||||
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), talentFrameMain.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), talentFrameMain.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||||
{
|
{
|
||||||
@@ -1541,7 +1541,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
string pointsLeft = controlledCharacter.Info.GetAvailableTalentPoints().ToString();
|
string pointsLeft = controlledCharacter.Info.GetAvailableTalentPoints().ToString();
|
||||||
|
|
||||||
int talentCount = selectedTalents.Count - controlledCharacter.Info.UnlockedTalents.Count;
|
int talentCount = selectedTalents.Count - controlledCharacter.Info.GetUnlockedTalentsInTree().Count();
|
||||||
|
|
||||||
if (talentCount > 0)
|
if (talentCount > 0)
|
||||||
{
|
{
|
||||||
@@ -1612,7 +1612,7 @@ namespace Barotrauma
|
|||||||
private bool ResetTalentSelection(GUIButton guiButton, object userData)
|
private bool ResetTalentSelection(GUIButton guiButton, object userData)
|
||||||
{
|
{
|
||||||
Character controlledCharacter = Character.Controlled;
|
Character controlledCharacter = Character.Controlled;
|
||||||
selectedTalents = controlledCharacter.Info.UnlockedTalents.ToList();
|
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||||
UpdateTalentButtons();
|
UpdateTalentButtons();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -544,7 +544,7 @@ namespace Barotrauma
|
|||||||
if (Character.Controlled.CurrentHull == null) { return; }
|
if (Character.Controlled.CurrentHull == null) { return; }
|
||||||
if (HumanAIController.IsBallastFloraNoticeable(Character.Controlled, Character.Controlled.CurrentHull))
|
if (HumanAIController.IsBallastFloraNoticeable(Character.Controlled, Character.Controlled.CurrentHull))
|
||||||
{
|
{
|
||||||
if (DisplayHint("onballastflorainfected")) { return; }
|
if (IsOnFriendlySub() && DisplayHint("onballastflorainfected")) { return; }
|
||||||
}
|
}
|
||||||
foreach (var gap in Character.Controlled.CurrentHull.ConnectedGaps)
|
foreach (var gap in Character.Controlled.CurrentHull.ConnectedGaps)
|
||||||
{
|
{
|
||||||
@@ -552,7 +552,7 @@ namespace Barotrauma
|
|||||||
if (Vector2.DistanceSquared(Character.Controlled.WorldPosition, gap.ConnectedDoor.Item.WorldPosition) > 400 * 400) { continue; }
|
if (Vector2.DistanceSquared(Character.Controlled.WorldPosition, gap.ConnectedDoor.Item.WorldPosition) > 400 * 400) { continue; }
|
||||||
if (!gap.IsRoomToRoom)
|
if (!gap.IsRoomToRoom)
|
||||||
{
|
{
|
||||||
if (!(Character.Controlled.GetEquippedItem("deepdiving", InvSlotType.OuterClothes) is Item)) { continue; }
|
if (!IsWearingDivingSuit()) { continue; }
|
||||||
if (Character.Controlled.IsProtectedFromPressure()) { continue; }
|
if (Character.Controlled.IsProtectedFromPressure()) { continue; }
|
||||||
if (DisplayHint("divingsuitwarning", extendTextTag: false)) { return; }
|
if (DisplayHint("divingsuitwarning", extendTextTag: false)) { return; }
|
||||||
continue;
|
continue;
|
||||||
@@ -561,10 +561,16 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (me == Character.Controlled.CurrentHull) { continue; }
|
if (me == Character.Controlled.CurrentHull) { continue; }
|
||||||
if (!(me is Hull adjacentHull)) { continue; }
|
if (!(me is Hull adjacentHull)) { continue; }
|
||||||
|
if (!IsOnFriendlySub()) { continue; }
|
||||||
|
if (IsWearingDivingSuit()) { continue; }
|
||||||
if (adjacentHull.LethalPressure > 5.0f && DisplayHint("onadjacenthull.highpressure")) { return; }
|
if (adjacentHull.LethalPressure > 5.0f && DisplayHint("onadjacenthull.highpressure")) { return; }
|
||||||
if (adjacentHull.WaterPercentage > 75 && !BallastHulls.Contains(adjacentHull) && DisplayHint("onadjacenthull.highwaterpercentage")) { return; }
|
if (adjacentHull.WaterPercentage > 75 && !BallastHulls.Contains(adjacentHull) && DisplayHint("onadjacenthull.highwaterpercentage")) { return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsWearingDivingSuit() => Character.Controlled.GetEquippedItem("deepdiving", InvSlotType.OuterClothes) is Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsOnFriendlySub() => Character.Controlled.Submarine is Submarine sub && (sub.TeamID == Character.Controlled.TeamID || sub.TeamID == CharacterTeamType.FriendlyNPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckReminders()
|
private static void CheckReminders()
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
||||||
{
|
{
|
||||||
if (Light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn)
|
if (Light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn && Light.Enabled)
|
||||||
{
|
{
|
||||||
Vector2 origin = Light.LightSprite.Origin;
|
Vector2 origin = Light.LightSprite.Origin;
|
||||||
if ((Light.LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally) { origin.X = Light.LightSprite.SourceRect.Width - origin.X; }
|
if ((Light.LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally) { origin.X = Light.LightSprite.SourceRect.Width - origin.X; }
|
||||||
|
|||||||
@@ -529,21 +529,30 @@ namespace Barotrauma.Items.Components
|
|||||||
};
|
};
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
string name = GetRecipeNameAndAmount(selectedItem);
|
string itemName = GetRecipeNameAndAmount(selectedItem);
|
||||||
|
string name = itemName;
|
||||||
|
|
||||||
float quality = GetFabricatedItemQuality(selectedItem, user);
|
float quality = GetFabricatedItemQuality(selectedItem, user);
|
||||||
if (quality > 0)
|
if (quality > 0)
|
||||||
{
|
{
|
||||||
name = TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", name+'\n', fallBackTag: "itemname.quality3");
|
name = TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", itemName + '\n', fallBackTag: "itemname.quality3");
|
||||||
}
|
}
|
||||||
|
|
||||||
var nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
var nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||||
name, textAlignment: Alignment.CenterLeft, textColor: Color.Aqua, font: GUI.SubHeadingFont, parseRichText: true)
|
name, textAlignment: Alignment.TopLeft, textColor: Color.Aqua, font: GUI.SubHeadingFont, parseRichText: true)
|
||||||
{
|
{
|
||||||
AutoScaleHorizontal = true
|
AutoScaleHorizontal = true
|
||||||
};
|
};
|
||||||
|
nameBlock.Padding = new Vector4(0, nameBlock.Padding.Y, GUI.IntScale(5), nameBlock.Padding.W);
|
||||||
nameBlock.Padding = new Vector4(0, nameBlock.Padding.Y, nameBlock.Padding.Z, nameBlock.Padding.W);
|
if (nameBlock.TextScale < 0.7f)
|
||||||
|
{
|
||||||
|
nameBlock.SetRichText(TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", itemName, fallBackTag: "itemname.quality3"));
|
||||||
|
nameBlock.AutoScaleHorizontal = false;
|
||||||
|
nameBlock.TextScale = 0.7f;
|
||||||
|
nameBlock.Wrap = true;
|
||||||
|
nameBlock.SetTextPos();
|
||||||
|
nameBlock.RectTransform.MinSize = new Point(0, (int)(nameBlock.TextSize.Y * nameBlock.TextScale));
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(selectedItem.TargetItem.Description))
|
if (!string.IsNullOrWhiteSpace(selectedItem.TargetItem.Description))
|
||||||
{
|
{
|
||||||
@@ -555,6 +564,7 @@ namespace Barotrauma.Items.Components
|
|||||||
while (description.Rect.Height + nameBlock.Rect.Height > paddedFrame.Rect.Height)
|
while (description.Rect.Height + nameBlock.Rect.Height > paddedFrame.Rect.Height)
|
||||||
{
|
{
|
||||||
var lines = description.WrappedText.Split('\n');
|
var lines = description.WrappedText.Split('\n');
|
||||||
|
if (lines.Length <= 1) { break; }
|
||||||
var newString = string.Join('\n', lines.Take(lines.Length - 1));
|
var newString = string.Join('\n', lines.Take(lines.Length - 1));
|
||||||
description.Text = newString.Substring(0, newString.Length - 4) + "...";
|
description.Text = newString.Substring(0, newString.Length - 4) + "...";
|
||||||
description.CalculateHeightFromText();
|
description.CalculateHeightFromText();
|
||||||
|
|||||||
@@ -1465,6 +1465,7 @@ namespace Barotrauma.Networking
|
|||||||
bool respawnAllowed = inc.ReadBoolean();
|
bool respawnAllowed = inc.ReadBoolean();
|
||||||
serverSettings.AllowDisguises = inc.ReadBoolean();
|
serverSettings.AllowDisguises = inc.ReadBoolean();
|
||||||
serverSettings.AllowRewiring = inc.ReadBoolean();
|
serverSettings.AllowRewiring = inc.ReadBoolean();
|
||||||
|
serverSettings.AllowFriendlyFire = inc.ReadBoolean();
|
||||||
serverSettings.LockAllDefaultWires = inc.ReadBoolean();
|
serverSettings.LockAllDefaultWires = inc.ReadBoolean();
|
||||||
serverSettings.AllowRagdollButton = inc.ReadBoolean();
|
serverSettings.AllowRagdollButton = inc.ReadBoolean();
|
||||||
GameMain.NetLobbyScreen.UsingShuttle = inc.ReadBoolean();
|
GameMain.NetLobbyScreen.UsingShuttle = inc.ReadBoolean();
|
||||||
|
|||||||
@@ -884,7 +884,7 @@ namespace Barotrauma
|
|||||||
// Switch the type ambience if nothing playing atm or the currently playing clip is not suitable anymore
|
// Switch the type ambience if nothing playing atm or the currently playing clip is not suitable anymore
|
||||||
else if (targetMusic[typeAmbienceTrackIndex] == null || currentMusic[typeAmbienceTrackIndex] == null || !currentMusic[typeAmbienceTrackIndex].IsPlaying() || suitableTypeAmbiences.None(m => m.File == currentMusic[typeAmbienceTrackIndex].Filename))
|
else if (targetMusic[typeAmbienceTrackIndex] == null || currentMusic[typeAmbienceTrackIndex] == null || !currentMusic[typeAmbienceTrackIndex].IsPlaying() || suitableTypeAmbiences.None(m => m.File == currentMusic[typeAmbienceTrackIndex].Filename))
|
||||||
{
|
{
|
||||||
targetMusic[mainTrackIndex] = suitableMusic.GetRandom();
|
targetMusic[typeAmbienceTrackIndex] = suitableTypeAmbiences.GetRandom();
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the appropriate intensity layers for current situation
|
//get the appropriate intensity layers for current situation
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.1500.7.0</Version>
|
<Version>0.1500.8.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.1500.7.0</Version>
|
<Version>0.1500.8.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.1500.7.0</Version>
|
<Version>0.1500.8.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.1500.7.0</Version>
|
<Version>0.1500.8.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.1500.7.0</Version>
|
<Version>0.1500.8.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void OnPermanentStatChanged(StatTypes statType)
|
||||||
|
{
|
||||||
|
if (Character == null || Character.Removed) { return; }
|
||||||
|
GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdatePermanentStats, statType });
|
||||||
|
}
|
||||||
|
|
||||||
public void ServerWrite(IWriteMessage msg)
|
public void ServerWrite(IWriteMessage msg)
|
||||||
{
|
{
|
||||||
msg.Write(ID);
|
msg.Write(ID);
|
||||||
@@ -66,8 +72,8 @@ namespace Barotrauma
|
|||||||
msg.Write((byte)0);
|
msg.Write((byte)0);
|
||||||
}
|
}
|
||||||
// TODO: animations
|
// TODO: animations
|
||||||
msg.Write((byte)savedStatValues.SelectMany(s => s.Value).Count());
|
msg.Write((byte)SavedStatValues.SelectMany(s => s.Value).Count());
|
||||||
foreach (var savedStatValuePair in savedStatValues)
|
foreach (var savedStatValuePair in SavedStatValues)
|
||||||
{
|
{
|
||||||
foreach (var savedStatValue in savedStatValuePair.Value)
|
foreach (var savedStatValue in savedStatValuePair.Value)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (extraData != null)
|
if (extraData != null)
|
||||||
{
|
{
|
||||||
const int min = 0, max = 12;
|
const int min = 0, max = 13;
|
||||||
switch ((NetEntityEvent.Type)extraData[0])
|
switch ((NetEntityEvent.Type)extraData[0])
|
||||||
{
|
{
|
||||||
case NetEntityEvent.Type.InventoryState:
|
case NetEntityEvent.Type.InventoryState:
|
||||||
@@ -438,6 +438,30 @@ namespace Barotrauma
|
|||||||
msg.WriteRangedInteger(12, min, max);
|
msg.WriteRangedInteger(12, min, max);
|
||||||
msg.Write(GameMain.GameSession.Campaign.Money);
|
msg.Write(GameMain.GameSession.Campaign.Money);
|
||||||
break;
|
break;
|
||||||
|
case NetEntityEvent.Type.UpdatePermanentStats:
|
||||||
|
msg.WriteRangedInteger(13, min, max);
|
||||||
|
if (Info == null || extraData.Length < 2 || !(extraData[1] is StatTypes statType))
|
||||||
|
{
|
||||||
|
msg.Write((byte)0);
|
||||||
|
msg.Write((byte)0);
|
||||||
|
}
|
||||||
|
else if (!Info.SavedStatValues.ContainsKey(statType))
|
||||||
|
{
|
||||||
|
msg.Write((byte)0);
|
||||||
|
msg.Write((byte)statType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg.Write((byte)Info.SavedStatValues[statType].Count);
|
||||||
|
msg.Write((byte)statType);
|
||||||
|
foreach (var savedStatValue in Info.SavedStatValues[statType])
|
||||||
|
{
|
||||||
|
msg.Write(savedStatValue.StatIdentifier);
|
||||||
|
msg.Write(savedStatValue.StatValue);
|
||||||
|
msg.Write(savedStatValue.RemoveOnDeath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DebugConsole.ThrowError("Invalid NetworkEvent type for entity " + ToString() + " (" + (NetEntityEvent.Type)extraData[0] + ")");
|
DebugConsole.ThrowError("Invalid NetworkEvent type for entity " + ToString() + " (" + (NetEntityEvent.Type)extraData[0] + ")");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1677,10 +1677,25 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool relativeStrength = false;
|
||||||
|
if (args.Length > 4)
|
||||||
|
{
|
||||||
|
bool.TryParse(args[4], out relativeStrength);
|
||||||
|
}
|
||||||
|
|
||||||
Character targetCharacter = (args.Length <= 2) ? client.Character : FindMatchingCharacter(args.Skip(2).ToArray());
|
Character targetCharacter = (args.Length <= 2) ? client.Character : FindMatchingCharacter(args.Skip(2).ToArray());
|
||||||
if (targetCharacter != null)
|
if (targetCharacter != null)
|
||||||
{
|
{
|
||||||
targetCharacter.CharacterHealth.ApplyAffliction(targetCharacter.AnimController.MainLimb, afflictionPrefab.Instantiate(afflictionStrength));
|
Limb targetLimb = targetCharacter.AnimController.MainLimb;
|
||||||
|
if (args.Length > 3)
|
||||||
|
{
|
||||||
|
targetLimb = targetCharacter.AnimController.Limbs.FirstOrDefault(l => l.type.ToString().Equals(args[3], StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
if (relativeStrength)
|
||||||
|
{
|
||||||
|
afflictionStrength *= targetCharacter.MaxVitality / afflictionPrefab.MaxStrength;
|
||||||
|
}
|
||||||
|
targetCharacter.CharacterHealth.ApplyAffliction(targetLimb ?? targetCharacter.AnimController.MainLimb, afflictionPrefab.Instantiate(afflictionStrength));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -2171,6 +2186,7 @@ namespace Barotrauma
|
|||||||
if (client == null)
|
if (client == null)
|
||||||
{
|
{
|
||||||
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient);
|
GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var character = FindMatchingCharacter(args.Skip(1).ToArray(), false);
|
var character = FindMatchingCharacter(args.Skip(1).ToArray(), false);
|
||||||
|
|||||||
+57
-1
@@ -1,4 +1,6 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -11,11 +13,65 @@ namespace Barotrauma
|
|||||||
get { return itemData != null; }
|
get { return itemData != null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void InitProjSpecific(Client client)
|
public CharacterCampaignData(Client client, bool giveRespawnPenaltyAffliction = false)
|
||||||
{
|
{
|
||||||
|
Name = client.Name;
|
||||||
ClientEndPoint = client.Connection.EndPointString;
|
ClientEndPoint = client.Connection.EndPointString;
|
||||||
SteamID = client.SteamID;
|
SteamID = client.SteamID;
|
||||||
CharacterInfo = client.CharacterInfo;
|
CharacterInfo = client.CharacterInfo;
|
||||||
|
|
||||||
|
healthData = new XElement("health");
|
||||||
|
client.Character?.CharacterHealth?.Save(healthData);
|
||||||
|
if (giveRespawnPenaltyAffliction)
|
||||||
|
{
|
||||||
|
var respawnPenaltyAffliction = RespawnManager.GetRespawnPenaltyAffliction();
|
||||||
|
healthData.Add(new XElement("Affliction",
|
||||||
|
new XAttribute("identifier", respawnPenaltyAffliction.Identifier),
|
||||||
|
new XAttribute("strength", respawnPenaltyAffliction.Strength.ToString("G", CultureInfo.InvariantCulture))));
|
||||||
|
}
|
||||||
|
if (client.Character?.Inventory != null)
|
||||||
|
{
|
||||||
|
itemData = new XElement("inventory");
|
||||||
|
Character.SaveInventory(client.Character.Inventory, itemData);
|
||||||
|
}
|
||||||
|
OrderData = new XElement("orders");
|
||||||
|
if (client.CharacterInfo != null)
|
||||||
|
{
|
||||||
|
CharacterInfo.SaveOrderData(client.CharacterInfo, OrderData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public CharacterCampaignData(XElement element)
|
||||||
|
{
|
||||||
|
Name = element.GetAttributeString("name", "Unnamed");
|
||||||
|
ClientEndPoint = element.GetAttributeString("endpoint", null) ?? element.GetAttributeString("ip", "");
|
||||||
|
string steamID = element.GetAttributeString("steamid", "");
|
||||||
|
if (!string.IsNullOrEmpty(steamID))
|
||||||
|
{
|
||||||
|
ulong.TryParse(steamID, out ulong parsedID);
|
||||||
|
SteamID = parsedID;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (XElement subElement in element.Elements())
|
||||||
|
{
|
||||||
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "character":
|
||||||
|
case "characterinfo":
|
||||||
|
CharacterInfo = new CharacterInfo(subElement);
|
||||||
|
break;
|
||||||
|
case "inventory":
|
||||||
|
itemData = subElement;
|
||||||
|
break;
|
||||||
|
case "health":
|
||||||
|
healthData = subElement;
|
||||||
|
break;
|
||||||
|
case "orders":
|
||||||
|
OrderData = subElement;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MatchesClient(Client client)
|
public bool MatchesClient(Client client)
|
||||||
|
|||||||
+6
-1
@@ -209,6 +209,11 @@ namespace Barotrauma
|
|||||||
//refresh the character data of clients who are still in the server
|
//refresh the character data of clients who are still in the server
|
||||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||||
{
|
{
|
||||||
|
if (c.Character != null && c.Character.Info == null)
|
||||||
|
{
|
||||||
|
c.Character = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (c.HasSpawned && c.CharacterInfo != null && c.CharacterInfo.CauseOfDeath != null && c.CharacterInfo.CauseOfDeath?.Type != CauseOfDeathType.Disconnected)
|
if (c.HasSpawned && c.CharacterInfo != null && c.CharacterInfo.CauseOfDeath != null && c.CharacterInfo.CauseOfDeath?.Type != CauseOfDeathType.Disconnected)
|
||||||
{
|
{
|
||||||
//the client has opted to spawn this round with Reaper's Tax
|
//the client has opted to spawn this round with Reaper's Tax
|
||||||
@@ -228,7 +233,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
c.CharacterInfo = characterInfo;
|
c.CharacterInfo = characterInfo;
|
||||||
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
||||||
characterData.Add(new CharacterCampaignData(c));
|
characterData.Add(new CharacterCampaignData(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
//refresh the character data of clients who aren't in the server anymore
|
//refresh the character data of clients who aren't in the server anymore
|
||||||
|
|||||||
@@ -2470,6 +2470,7 @@ namespace Barotrauma.Networking
|
|||||||
msg.Write(serverSettings.AllowRespawn && missionAllowRespawn);
|
msg.Write(serverSettings.AllowRespawn && missionAllowRespawn);
|
||||||
msg.Write(serverSettings.AllowDisguises);
|
msg.Write(serverSettings.AllowDisguises);
|
||||||
msg.Write(serverSettings.AllowRewiring);
|
msg.Write(serverSettings.AllowRewiring);
|
||||||
|
msg.Write(serverSettings.AllowFriendlyFire);
|
||||||
msg.Write(serverSettings.LockAllDefaultWires);
|
msg.Write(serverSettings.LockAllDefaultWires);
|
||||||
msg.Write(serverSettings.AllowRagdollButton);
|
msg.Write(serverSettings.AllowRagdollButton);
|
||||||
msg.Write(serverSettings.UseRespawnShuttle);
|
msg.Write(serverSettings.UseRespawnShuttle);
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ namespace Barotrauma
|
|||||||
case VoteType.Mode:
|
case VoteType.Mode:
|
||||||
string modeIdentifier = inc.ReadString();
|
string modeIdentifier = inc.ReadString();
|
||||||
GameModePreset mode = GameModePreset.List.Find(gm => gm.Identifier == modeIdentifier);
|
GameModePreset mode = GameModePreset.List.Find(gm => gm.Identifier == modeIdentifier);
|
||||||
if (!mode.Votable) { break; }
|
if (mode == null || !mode.Votable) { break; }
|
||||||
sender.SetVote(voteType, mode);
|
sender.SetVote(voteType, mode);
|
||||||
break;
|
break;
|
||||||
case VoteType.EndRound:
|
case VoteType.EndRound:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.1500.7.0</Version>
|
<Version>0.1500.8.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Extensions;
|
||||||
|
using Barotrauma.Items.Components;
|
||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using FarseerPhysics;
|
using FarseerPhysics;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
@@ -346,7 +347,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region Escape
|
#region Escape
|
||||||
public abstract void Escape(float deltaTime);
|
public abstract bool Escape(float deltaTime);
|
||||||
|
|
||||||
public Gap EscapeTarget { get; private set; }
|
public Gap EscapeTarget { get; private set; }
|
||||||
|
|
||||||
@@ -425,17 +426,38 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (EscapeTarget != null)
|
if (EscapeTarget != null)
|
||||||
{
|
{
|
||||||
SteeringManager.SteeringSeek(EscapeTarget.SimPosition, 10);
|
Vector2 diff = EscapeTarget.WorldPosition - Character.WorldPosition;
|
||||||
float sqrDist = Vector2.DistanceSquared(Character.SimPosition, EscapeTarget.SimPosition);
|
float sqrDist = diff.LengthSquared();
|
||||||
if (sqrDist < 0.5f || Character.CurrentHull == null || HasValidPath(requireNonDirty: true, requireUnfinished: false) && pathSteering.CurrentPath.Finished)
|
if (Character.CurrentHull == null || sqrDist < MathUtils.Pow2(50) || pathSteering == null || IsCurrentPathUnreachable || IsCurrentPathFinished)
|
||||||
{
|
{
|
||||||
// Very close to the target, outside, or at the end of the path -> just steer towards it manually without using the path
|
// Very close to the target, outside, or at the end of the path -> try to steer through the gap
|
||||||
SteeringManager.Reset();
|
SteeringManager.Reset();
|
||||||
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(EscapeTarget.WorldPosition - Character.WorldPosition));
|
pathSteering?.ResetPath();
|
||||||
if (sqrDist < 4)
|
if (sqrDist < MathUtils.Pow2(50))
|
||||||
{
|
{
|
||||||
return true;
|
// Very close -> just keep steering forward
|
||||||
|
var forward = VectorExtensions.Forward(Character.AnimController.Collider.Rotation + MathHelper.PiOver2);
|
||||||
|
SteeringManager.SteeringManual(deltaTime, forward);
|
||||||
}
|
}
|
||||||
|
else if (Character.CurrentHull == null)
|
||||||
|
{
|
||||||
|
// Outside -> steer away from the target
|
||||||
|
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(-diff));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Still inside -> steer towards the target
|
||||||
|
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(diff));
|
||||||
|
}
|
||||||
|
return sqrDist < MathUtils.Pow2(200);
|
||||||
|
}
|
||||||
|
else if (pathSteering != null)
|
||||||
|
{
|
||||||
|
pathSteering.SteeringSeek(EscapeTarget.SimPosition, weight: 1, minGapSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SteeringManager.SteeringSeek(EscapeTarget.SimPosition, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1903,7 +1903,7 @@ namespace Barotrauma
|
|||||||
Character.AnimController.ReleaseStuckLimbs();
|
Character.AnimController.ReleaseStuckLimbs();
|
||||||
LatchOntoAI?.DeattachFromBody(reset: true, cooldown: 1);
|
LatchOntoAI?.DeattachFromBody(reset: true, cooldown: 1);
|
||||||
if (attacker == null || attacker.AiTarget == null || attacker.Removed || attacker.IsDead) { return; }
|
if (attacker == null || attacker.AiTarget == null || attacker.Removed || attacker.IsDead) { return; }
|
||||||
if (Character.Params.CanInteract)
|
if (Character.Params.CanInteract && attackResult.Damage > 10)
|
||||||
{
|
{
|
||||||
ReleaseDragTargets();
|
ReleaseDragTargets();
|
||||||
}
|
}
|
||||||
@@ -3607,12 +3607,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public bool CanPassThroughHole(Structure wall, int sectionIndex) => CanPassThroughHole(wall, sectionIndex, requiredHoleCount);
|
public bool CanPassThroughHole(Structure wall, int sectionIndex) => CanPassThroughHole(wall, sectionIndex, requiredHoleCount);
|
||||||
|
|
||||||
public override void Escape(float deltaTime)
|
public override bool Escape(float deltaTime)
|
||||||
{
|
{
|
||||||
if (SelectedAiTarget != null && (SelectedAiTarget.Entity == null || SelectedAiTarget.Entity.Removed))
|
if (SelectedAiTarget != null && (SelectedAiTarget.Entity == null || SelectedAiTarget.Entity.Removed))
|
||||||
{
|
{
|
||||||
State = AIState.Idle;
|
State = AIState.Idle;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
else if (SelectedTargetMemory is AITargetMemory targetMemory && SelectedAiTarget?.Entity is Character)
|
else if (SelectedTargetMemory is AITargetMemory targetMemory && SelectedAiTarget?.Entity is Character)
|
||||||
{
|
{
|
||||||
@@ -3653,6 +3653,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return isSteeringThroughGap;
|
||||||
|
|
||||||
void SteerAwayFromTheEnemy()
|
void SteerAwayFromTheEnemy()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1364,10 +1364,7 @@ namespace Barotrauma
|
|||||||
ObjectiveManager.WaitTimer = waitDuration;
|
ObjectiveManager.WaitTimer = waitDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Escape(float deltaTime)
|
public override bool Escape(float deltaTime) => UpdateEscape(deltaTime, canAttackDoors: false);
|
||||||
{
|
|
||||||
UpdateEscape(deltaTime, canAttackDoors: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckCrouching(float deltaTime)
|
private void CheckCrouching(float deltaTime)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
var waypoint = CurrentPath.Nodes[i];
|
var waypoint = CurrentPath.Nodes[i];
|
||||||
float directDistance = Vector2.DistanceSquared(character.WorldPosition, waypoint.WorldPosition);
|
float directDistance = Vector2.DistanceSquared(character.WorldPosition, waypoint.WorldPosition);
|
||||||
if (directDistance > (pathDistance * pathDistance) || Submarine.PickBody(host.SimPosition, waypoint.SimPosition, collisionCategory: Physics.CollisionLevel) != null)
|
if (directDistance > (pathDistance * pathDistance) || Submarine.PickBody(host.SimPosition, waypoint.SimPosition, collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) != null)
|
||||||
{
|
{
|
||||||
pathDistance -= CurrentPath.GetLength(startIndex: i - 1, endIndex: i);
|
pathDistance -= CurrentPath.GetLength(startIndex: i - 1, endIndex: i);
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
+16
-7
@@ -9,6 +9,7 @@ namespace Barotrauma
|
|||||||
public override string Identifier { get; set; } = "return";
|
public override string Identifier { get; set; } = "return";
|
||||||
private AIObjectiveGoTo moveInsideObjective, moveInCaveObjective, moveOutsideObjective;
|
private AIObjectiveGoTo moveInsideObjective, moveInCaveObjective, moveOutsideObjective;
|
||||||
private bool usingEscapeBehavior;
|
private bool usingEscapeBehavior;
|
||||||
|
private bool isSteeringThroughGap;
|
||||||
public Submarine ReturnTarget { get; }
|
public Submarine ReturnTarget { get; }
|
||||||
|
|
||||||
public AIObjectiveReturn(Character character, Character orderGiver, AIObjectiveManager objectiveManager, float priorityModifier = 1.0f) : base(character, objectiveManager, priorityModifier)
|
public AIObjectiveReturn(Character character, Character orderGiver, AIObjectiveManager objectiveManager, float priorityModifier = 1.0f) : base(character, objectiveManager, priorityModifier)
|
||||||
@@ -57,7 +58,7 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool shouldUseEscapeBehavior = false;
|
bool shouldUseEscapeBehavior = false;
|
||||||
if (character.CurrentHull != null)
|
if (character.CurrentHull != null || isSteeringThroughGap)
|
||||||
{
|
{
|
||||||
if (character.Submarine == null || !character.Submarine.IsConnectedTo(ReturnTarget))
|
if (character.Submarine == null || !character.Submarine.IsConnectedTo(ReturnTarget))
|
||||||
{
|
{
|
||||||
@@ -67,8 +68,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
HumanAIController.ResetEscape();
|
HumanAIController.ResetEscape();
|
||||||
}
|
}
|
||||||
HumanAIController.Escape(deltaTime);
|
isSteeringThroughGap = HumanAIController.Escape(deltaTime);
|
||||||
if (HumanAIController.EscapeTarget == null || HumanAIController.IsCurrentPathUnreachable)
|
if (!isSteeringThroughGap && (HumanAIController.EscapeTarget == null || HumanAIController.IsCurrentPathUnreachable))
|
||||||
{
|
{
|
||||||
Abandon = true;
|
Abandon = true;
|
||||||
}
|
}
|
||||||
@@ -92,7 +93,10 @@ namespace Barotrauma
|
|||||||
RemoveSubObjective(ref moveInCaveObjective);
|
RemoveSubObjective(ref moveInCaveObjective);
|
||||||
RemoveSubObjective(ref moveOutsideObjective);
|
RemoveSubObjective(ref moveOutsideObjective);
|
||||||
TryAddSubObjective(ref moveInsideObjective,
|
TryAddSubObjective(ref moveInsideObjective,
|
||||||
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager),
|
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager)
|
||||||
|
{
|
||||||
|
AllowGoingOutside = true
|
||||||
|
},
|
||||||
onCompleted: () => RemoveSubObjective(ref moveInsideObjective),
|
onCompleted: () => RemoveSubObjective(ref moveInsideObjective),
|
||||||
onAbandon: () => Abandon = true);
|
onAbandon: () => Abandon = true);
|
||||||
}
|
}
|
||||||
@@ -110,7 +114,7 @@ namespace Barotrauma
|
|||||||
IsCompleted = true;
|
IsCompleted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (moveInCaveObjective == null && moveOutsideObjective == null)
|
else if (!isSteeringThroughGap && moveInCaveObjective == null && moveOutsideObjective == null)
|
||||||
{
|
{
|
||||||
if (HumanAIController.IsInsideCave)
|
if (HumanAIController.IsInsideCave)
|
||||||
{
|
{
|
||||||
@@ -134,7 +138,8 @@ namespace Barotrauma
|
|||||||
TryAddSubObjective(ref moveInCaveObjective,
|
TryAddSubObjective(ref moveInCaveObjective,
|
||||||
constructor: () => new AIObjectiveGoTo(closestOutsideWaypoint, character, objectiveManager)
|
constructor: () => new AIObjectiveGoTo(closestOutsideWaypoint, character, objectiveManager)
|
||||||
{
|
{
|
||||||
endNodeFilter = n => n.Waypoint == closestOutsideWaypoint
|
endNodeFilter = n => n.Waypoint == closestOutsideWaypoint,
|
||||||
|
AllowGoingOutside = true
|
||||||
},
|
},
|
||||||
onCompleted: () => RemoveSubObjective(ref moveInCaveObjective),
|
onCompleted: () => RemoveSubObjective(ref moveInCaveObjective),
|
||||||
onAbandon: () => Abandon = true);
|
onAbandon: () => Abandon = true);
|
||||||
@@ -170,7 +175,10 @@ namespace Barotrauma
|
|||||||
RemoveSubObjective(ref moveInsideObjective);
|
RemoveSubObjective(ref moveInsideObjective);
|
||||||
RemoveSubObjective(ref moveInCaveObjective);
|
RemoveSubObjective(ref moveInCaveObjective);
|
||||||
TryAddSubObjective(ref moveOutsideObjective,
|
TryAddSubObjective(ref moveOutsideObjective,
|
||||||
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager),
|
constructor: () => new AIObjectiveGoTo(targetHull, character, objectiveManager)
|
||||||
|
{
|
||||||
|
AllowGoingOutside = true
|
||||||
|
},
|
||||||
onCompleted: () => RemoveSubObjective(ref moveOutsideObjective),
|
onCompleted: () => RemoveSubObjective(ref moveOutsideObjective),
|
||||||
onAbandon: () => Abandon = true);
|
onAbandon: () => Abandon = true);
|
||||||
}
|
}
|
||||||
@@ -221,6 +229,7 @@ namespace Barotrauma
|
|||||||
moveInCaveObjective = null;
|
moveInCaveObjective = null;
|
||||||
moveOutsideObjective = null;
|
moveOutsideObjective = null;
|
||||||
usingEscapeBehavior = false;
|
usingEscapeBehavior = false;
|
||||||
|
isSteeringThroughGap = false;
|
||||||
HumanAIController.ResetEscape();
|
HumanAIController.ResetEscape();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ namespace Barotrauma
|
|||||||
collisionCategory: Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionStairs);
|
collisionCategory: Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionStairs);
|
||||||
if (body != null)
|
if (body != null)
|
||||||
{
|
{
|
||||||
|
if (body.UserData is Submarine) { return false; }
|
||||||
if (body.UserData is Structure s && !s.IsPlatform) { return false; }
|
if (body.UserData is Structure s && !s.IsPlatform) { return false; }
|
||||||
if (body.UserData is Item && body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall)) { return false; }
|
if (body.UserData is Item && body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall)) { return false; }
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-15
@@ -684,18 +684,15 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (rightHand != null && !rightHand.Disabled)
|
if (rightHand != null && !rightHand.Disabled)
|
||||||
{
|
{
|
||||||
HandIK(rightHand, torso.SimPosition + posAddition +
|
HandIK(rightHand,
|
||||||
new Vector2(
|
torso.SimPosition + posAddition + new Vector2(-handPos.X, (Math.Sign(walkPosX) == Math.Sign(Dir)) ? handPos.Y : lowerY),
|
||||||
-handPos.X,
|
CurrentGroundedParams.ArmMoveStrength, CurrentGroundedParams.HandMoveStrength);
|
||||||
(Math.Sign(walkPosX) == Math.Sign(Dir)) ? handPos.Y : lowerY), CurrentGroundedParams.ArmMoveStrength, CurrentGroundedParams.HandMoveStrength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leftHand != null && !leftHand.Disabled)
|
if (leftHand != null && !leftHand.Disabled)
|
||||||
{
|
{
|
||||||
HandIK(leftHand, torso.SimPosition + posAddition +
|
HandIK(leftHand,
|
||||||
new Vector2(
|
torso.SimPosition + posAddition + new Vector2(handPos.X, (Math.Sign(walkPosX) == Math.Sign(-Dir)) ? handPos.Y : lowerY),
|
||||||
handPos.X,
|
CurrentGroundedParams.ArmMoveStrength, CurrentGroundedParams.HandMoveStrength);
|
||||||
(Math.Sign(walkPosX) == Math.Sign(-Dir)) ? handPos.Y : lowerY), CurrentGroundedParams.ArmMoveStrength, CurrentGroundedParams.HandMoveStrength);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -705,9 +702,7 @@ namespace Barotrauma
|
|||||||
Vector2 footPos = colliderPos;
|
Vector2 footPos = colliderPos;
|
||||||
if (Crouching)
|
if (Crouching)
|
||||||
{
|
{
|
||||||
footPos = new Vector2(
|
footPos = new Vector2(Math.Sign(stepSize.X * i) * Dir * 0.35f, colliderPos.Y);
|
||||||
Math.Sign(stepSize.X * i) * Dir * 0.4f,
|
|
||||||
colliderPos.Y);
|
|
||||||
if (Math.Sign(footPos.X) != Math.Sign(Dir))
|
if (Math.Sign(footPos.X) != Math.Sign(Dir))
|
||||||
{
|
{
|
||||||
//lift the foot at the back up a bit
|
//lift the foot at the back up a bit
|
||||||
@@ -728,9 +723,16 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foot.DebugRefPos = colliderPos;
|
foot.DebugRefPos = colliderPos;
|
||||||
foot.DebugTargetPos = footPos;
|
foot.DebugTargetPos = footPos;
|
||||||
MoveLimb(foot, footPos, CurrentGroundedParams.FootMoveStrength);
|
float footMoveForce = CurrentGroundedParams.FootMoveStrength;
|
||||||
FootIK(foot, footPos,
|
float legBendTorque = CurrentGroundedParams.LegBendTorque;
|
||||||
CurrentGroundedParams.LegBendTorque, CurrentGroundedParams.FootTorque, CurrentGroundedParams.FootAngleInRadians);
|
if (Crouching)
|
||||||
|
{
|
||||||
|
// Keeps the pose
|
||||||
|
legBendTorque = 100;
|
||||||
|
footMoveForce *= 2;
|
||||||
|
}
|
||||||
|
MoveLimb(foot, footPos, footMoveForce);
|
||||||
|
FootIK(foot, footPos, legBendTorque, CurrentGroundedParams.FootTorque, CurrentGroundedParams.FootAngleInRadians);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -760,6 +762,12 @@ namespace Barotrauma
|
|||||||
forearm.body.ApplyTorque(MathHelper.Clamp(-diff, -MathHelper.PiOver2, MathHelper.PiOver2) * forearm.Mass * 100.0f * CurrentGroundedParams.ArmMoveStrength);
|
forearm.body.ApplyTorque(MathHelper.Clamp(-diff, -MathHelper.PiOver2, MathHelper.PiOver2) * forearm.Mass * 100.0f * CurrentGroundedParams.ArmMoveStrength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Try to keep the wrist straight
|
||||||
|
LimbJoint wrist = GetJointBetweenLimbs(foreArmType, hand.type);
|
||||||
|
if (wrist != null)
|
||||||
|
{
|
||||||
|
hand.body.ApplyTorque(MathHelper.Clamp(-wrist.JointAngle, -MathHelper.PiOver2, MathHelper.PiOver2) * hand.Mass * 100f * CurrentGroundedParams.HandMoveStrength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1008,6 +1016,12 @@ namespace Barotrauma
|
|||||||
speedMultiplier = Math.Min(speedMultiplier, 0.1f);
|
speedMultiplier = Math.Min(speedMultiplier, 0.1f);
|
||||||
}
|
}
|
||||||
HandIK(rightHand, handPos + rightHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
|
HandIK(rightHand, handPos + rightHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
|
||||||
|
// Try to keep the wrist straight
|
||||||
|
LimbJoint wrist = GetJointBetweenLimbs(LimbType.RightForearm, LimbType.RightHand);
|
||||||
|
if (wrist != null)
|
||||||
|
{
|
||||||
|
rightHand.body.ApplyTorque(MathHelper.Clamp(-wrist.JointAngle, -MathHelper.PiOver2, MathHelper.PiOver2) * rightHand.Mass * 100f * CurrentSwimParams.HandMoveStrength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leftHand != null && !leftHand.Disabled)
|
if (leftHand != null && !leftHand.Disabled)
|
||||||
@@ -1021,6 +1035,12 @@ namespace Barotrauma
|
|||||||
speedMultiplier = Math.Min(speedMultiplier, 0.1f);
|
speedMultiplier = Math.Min(speedMultiplier, 0.1f);
|
||||||
}
|
}
|
||||||
HandIK(leftHand, handPos + leftHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
|
HandIK(leftHand, handPos + leftHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
|
||||||
|
// Try to keep the wrist straight
|
||||||
|
LimbJoint wrist = GetJointBetweenLimbs(LimbType.LeftForearm, LimbType.LeftHand);
|
||||||
|
if (wrist != null)
|
||||||
|
{
|
||||||
|
leftHand.body.ApplyTorque(MathHelper.Clamp(-wrist.JointAngle, -MathHelper.PiOver2, MathHelper.PiOver2) * leftHand.Mass * 100f * CurrentSwimParams.HandMoveStrength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -665,6 +665,7 @@ namespace Barotrauma
|
|||||||
public float MaxVitality => CharacterHealth.MaxVitality;
|
public float MaxVitality => CharacterHealth.MaxVitality;
|
||||||
public float MaxHealth => MaxVitality;
|
public float MaxHealth => MaxVitality;
|
||||||
public AIState AIState => AIController is EnemyAIController enemyAI ? enemyAI.State : AIState.Idle;
|
public AIState AIState => AIController is EnemyAIController enemyAI ? enemyAI.State : AIState.Idle;
|
||||||
|
public bool IsLatched => AIController is EnemyAIController enemyAI && enemyAI.LatchOntoAI != null && enemyAI.LatchOntoAI.IsAttached;
|
||||||
|
|
||||||
public float Bloodloss
|
public float Bloodloss
|
||||||
{
|
{
|
||||||
@@ -2751,7 +2752,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (this != Controlled)
|
else if (this != Controlled)
|
||||||
{
|
{
|
||||||
IsRagdolled = IsKeyDown(InputType.Ragdoll);
|
wasRagdolled = IsRagdolled;
|
||||||
|
IsRagdolled = selfRagdolled = IsKeyDown(InputType.Ragdoll);
|
||||||
}
|
}
|
||||||
//Keep us ragdolled if we were forced or we're too speedy to unragdoll
|
//Keep us ragdolled if we were forced or we're too speedy to unragdoll
|
||||||
else if (allowRagdoll && (!IsRagdolled || !tooFastToUnragdoll))
|
else if (allowRagdoll && (!IsRagdolled || !tooFastToUnragdoll))
|
||||||
@@ -2765,13 +2767,18 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
wasRagdolled = IsRagdolled;
|
wasRagdolled = IsRagdolled;
|
||||||
IsRagdolled = selfRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves
|
IsRagdolled = selfRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves
|
||||||
if (wasRagdolled != IsRagdolled) { ragdollingLockTimer = 0.25f; }
|
if (wasRagdolled != IsRagdolled) { ragdollingLockTimer = 0.5f; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wasRagdolled && IsRagdolled && selfRagdolled)
|
if (!wasRagdolled && IsRagdolled)
|
||||||
{
|
{
|
||||||
CheckTalents(AbilityEffectType.OnSelfRagdoll);
|
if (selfRagdolled)
|
||||||
|
{
|
||||||
|
CheckTalents(AbilityEffectType.OnSelfRagdoll);
|
||||||
|
}
|
||||||
|
// currently does not work when you are stunned, like it should
|
||||||
|
CheckTalents(AbilityEffectType.OnRagdoll);
|
||||||
}
|
}
|
||||||
|
|
||||||
lowPassMultiplier = MathHelper.Lerp(lowPassMultiplier, 1.0f, 0.1f);
|
lowPassMultiplier = MathHelper.Lerp(lowPassMultiplier, 1.0f, 0.1f);
|
||||||
@@ -3535,11 +3542,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (Removed) { return new AttackResult(); }
|
if (Removed) { return new AttackResult(); }
|
||||||
|
|
||||||
if (attacker != null && attacker != this && GameMain.NetworkMember != null && !GameMain.NetworkMember.ServerSettings.AllowFriendlyFire)
|
|
||||||
{
|
|
||||||
if (attacker.TeamID == TeamID) { return new AttackResult(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
float closestDistance = 0.0f;
|
float closestDistance = 0.0f;
|
||||||
foreach (Limb limb in AnimController.Limbs)
|
foreach (Limb limb in AnimController.Limbs)
|
||||||
{
|
{
|
||||||
@@ -3602,7 +3604,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (attacker != null && attacker != this && GameMain.NetworkMember != null && !GameMain.NetworkMember.ServerSettings.AllowFriendlyFire)
|
if (attacker != null && attacker != this && GameMain.NetworkMember != null && !GameMain.NetworkMember.ServerSettings.AllowFriendlyFire)
|
||||||
{
|
{
|
||||||
if (attacker.TeamID == TeamID) { return new AttackResult(); }
|
if (attacker.TeamID == TeamID)
|
||||||
|
{
|
||||||
|
afflictions = afflictions.Where(a => !a.Prefab.IsBuff);
|
||||||
|
if (!afflictions.Any()) { return new AttackResult(); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
@@ -4385,14 +4391,14 @@ namespace Barotrauma
|
|||||||
info.UnlockedTalents.Add(talentPrefab.Identifier);
|
info.UnlockedTalents.Add(talentPrefab.Identifier);
|
||||||
if (characterTalents.Any(t => t.Prefab == talentPrefab)) { return false; }
|
if (characterTalents.Any(t => t.Prefab == talentPrefab)) { return false; }
|
||||||
|
|
||||||
|
#if SERVER
|
||||||
|
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateTalents });
|
||||||
|
#endif
|
||||||
CharacterTalent characterTalent = new CharacterTalent(talentPrefab, this);
|
CharacterTalent characterTalent = new CharacterTalent(talentPrefab, this);
|
||||||
characterTalent.ActivateTalent(addingFirstTime);
|
characterTalent.ActivateTalent(addingFirstTime);
|
||||||
characterTalents.Add(characterTalent);
|
characterTalents.Add(characterTalent);
|
||||||
characterTalent.AddedThisRound = addingFirstTime;
|
characterTalent.AddedThisRound = addingFirstTime;
|
||||||
|
|
||||||
#if SERVER
|
|
||||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateTalents });
|
|
||||||
#endif
|
|
||||||
if (addingFirstTime)
|
if (addingFirstTime)
|
||||||
{
|
{
|
||||||
OnTalentGiven(talentPrefab.Identifier);
|
OnTalentGiven(talentPrefab.Identifier);
|
||||||
|
|||||||
@@ -216,6 +216,17 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public HashSet<string> UnlockedTalents { get; private set; } = new HashSet<string>();
|
public HashSet<string> UnlockedTalents { get; private set; } = new HashSet<string>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Endocrine boosters can unlock talents outside the user's talent tree. This method is used to cull them from the selection
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<string> GetUnlockedTalentsInTree()
|
||||||
|
{
|
||||||
|
if (!TalentTree.JobTalentTrees.TryGetValue(Job.Prefab.Identifier, out TalentTree talentTree)) { return Enumerable.Empty<string>(); }
|
||||||
|
|
||||||
|
return UnlockedTalents.Where(t => talentTree.TalentIsInTree(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public int AdditionalTalentPoints { get; set; }
|
public int AdditionalTalentPoints { get; set; }
|
||||||
|
|
||||||
private Sprite _headSprite;
|
private Sprite _headSprite;
|
||||||
@@ -1220,7 +1231,7 @@ namespace Barotrauma
|
|||||||
var experienceGainMultiplier = new AbilityValue(1f);
|
var experienceGainMultiplier = new AbilityValue(1f);
|
||||||
if (isMissionExperience)
|
if (isMissionExperience)
|
||||||
{
|
{
|
||||||
Character.CheckTalents(AbilityEffectType.OnGainMissionExperience, experienceGainMultiplier);
|
Character?.CheckTalents(AbilityEffectType.OnGainMissionExperience, experienceGainMultiplier);
|
||||||
}
|
}
|
||||||
experienceGainMultiplier.Value += Character.GetStatValue(StatTypes.ExperienceGainMultiplier);
|
experienceGainMultiplier.Value += Character.GetStatValue(StatTypes.ExperienceGainMultiplier);
|
||||||
|
|
||||||
@@ -1252,7 +1263,7 @@ namespace Barotrauma
|
|||||||
public int GetAvailableTalentPoints()
|
public int GetAvailableTalentPoints()
|
||||||
{
|
{
|
||||||
// hashset always has at least 1
|
// hashset always has at least 1
|
||||||
return Math.Max(GetTotalTalentPoints() - UnlockedTalents.Count, 0);
|
return Math.Max(GetTotalTalentPoints() - GetUnlockedTalentsInTree().Count(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetProgressTowardsNextLevel()
|
public float GetProgressTowardsNextLevel()
|
||||||
@@ -1297,6 +1308,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
partial void OnExperienceChanged(int prevAmount, int newAmount);
|
partial void OnExperienceChanged(int prevAmount, int newAmount);
|
||||||
|
|
||||||
|
partial void OnPermanentStatChanged(StatTypes statType);
|
||||||
|
|
||||||
public void Rename(string newName)
|
public void Rename(string newName)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(newName)) { return; }
|
if (string.IsNullOrEmpty(newName)) { return; }
|
||||||
@@ -1362,7 +1375,7 @@ namespace Barotrauma
|
|||||||
Job.Save(charElement);
|
Job.Save(charElement);
|
||||||
|
|
||||||
XElement savedStatElement = new XElement("savedstatvalues");
|
XElement savedStatElement = new XElement("savedstatvalues");
|
||||||
foreach (var statValuePair in savedStatValues)
|
foreach (var statValuePair in SavedStatValues)
|
||||||
{
|
{
|
||||||
foreach (var savedStat in statValuePair.Value)
|
foreach (var savedStat in statValuePair.Value)
|
||||||
{
|
{
|
||||||
@@ -1708,26 +1721,42 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This could maybe be a LookUp instead?
|
// This could maybe be a LookUp instead?
|
||||||
private readonly Dictionary<StatTypes, List<SavedStatValue>> savedStatValues = new Dictionary<StatTypes, List<SavedStatValue>>();
|
public readonly Dictionary<StatTypes, List<SavedStatValue>> SavedStatValues = new Dictionary<StatTypes, List<SavedStatValue>>();
|
||||||
|
|
||||||
public void ResetSavedStatValues()
|
public void ClearSavedStatValues()
|
||||||
{
|
{
|
||||||
foreach (var savedStatValue in savedStatValues.SelectMany(s => s.Value))
|
foreach (StatTypes statType in SavedStatValues.Keys)
|
||||||
{
|
{
|
||||||
if (savedStatValue.RemoveOnDeath)
|
OnPermanentStatChanged(statType);
|
||||||
{
|
|
||||||
savedStatValue.StatValue = 0f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
SavedStatValues.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ClearSavedStatValues(StatTypes statType)
|
||||||
|
{
|
||||||
|
SavedStatValues.Remove(statType);
|
||||||
|
OnPermanentStatChanged(statType);
|
||||||
|
}
|
||||||
|
|
||||||
public void ResetSavedStatValue(string statIdentifier)
|
public void ResetSavedStatValue(string statIdentifier)
|
||||||
{
|
{
|
||||||
savedStatValues.SelectMany(s => s.Value).Where(s => s.StatIdentifier == statIdentifier).ForEach(v => v.StatValue = 0f);
|
foreach (StatTypes statType in SavedStatValues.Keys)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
foreach (SavedStatValue savedStatValue in SavedStatValues[statType])
|
||||||
|
{
|
||||||
|
if (savedStatValue.StatIdentifier != statIdentifier) { continue; }
|
||||||
|
if (MathUtils.NearlyEqual(savedStatValue.StatValue, 0.0f)) { continue; }
|
||||||
|
savedStatValue.StatValue = 0.0f;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed) { OnPermanentStatChanged(statType); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetSavedStatValue(StatTypes statType)
|
public float GetSavedStatValue(StatTypes statType)
|
||||||
{
|
{
|
||||||
if (savedStatValues.TryGetValue(statType, out var statValues))
|
if (SavedStatValues.TryGetValue(statType, out var statValues))
|
||||||
{
|
{
|
||||||
return statValues.Sum(v => v.StatValue);
|
return statValues.Sum(v => v.StatValue);
|
||||||
}
|
}
|
||||||
@@ -1738,7 +1767,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
public float GetSavedStatValue(StatTypes statType, string statIdentifier)
|
public float GetSavedStatValue(StatTypes statType, string statIdentifier)
|
||||||
{
|
{
|
||||||
if (savedStatValues.TryGetValue(statType, out var statValues))
|
if (SavedStatValues.TryGetValue(statType, out var statValues))
|
||||||
{
|
{
|
||||||
return statValues.Where(s => s.StatIdentifier.Equals(statIdentifier, StringComparison.OrdinalIgnoreCase)).Sum(v => v.StatValue);
|
return statValues.Where(s => s.StatIdentifier.Equals(statIdentifier, StringComparison.OrdinalIgnoreCase)).Sum(v => v.StatValue);
|
||||||
}
|
}
|
||||||
@@ -1750,19 +1779,24 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void ChangeSavedStatValue(StatTypes statType, float value, string statIdentifier, bool removeOnDeath, bool removeAfterRound = false, float maxValue = float.MaxValue, bool setValue = false)
|
public void ChangeSavedStatValue(StatTypes statType, float value, string statIdentifier, bool removeOnDeath, bool removeAfterRound = false, float maxValue = float.MaxValue, bool setValue = false)
|
||||||
{
|
{
|
||||||
if (!savedStatValues.ContainsKey(statType))
|
if (!SavedStatValues.ContainsKey(statType))
|
||||||
{
|
{
|
||||||
savedStatValues.Add(statType, new List<SavedStatValue>());
|
SavedStatValues.Add(statType, new List<SavedStatValue>());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savedStatValues[statType].FirstOrDefault(s => s.StatIdentifier == statIdentifier) is SavedStatValue savedStat)
|
bool changed = false;
|
||||||
|
if (SavedStatValues[statType].FirstOrDefault(s => s.StatIdentifier == statIdentifier) is SavedStatValue savedStat)
|
||||||
{
|
{
|
||||||
|
float prevValue = savedStat.StatValue;
|
||||||
savedStat.StatValue = setValue ? value : MathHelper.Min(savedStat.StatValue + value, maxValue);
|
savedStat.StatValue = setValue ? value : MathHelper.Min(savedStat.StatValue + value, maxValue);
|
||||||
|
changed = !MathUtils.NearlyEqual(savedStat.StatValue, prevValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
savedStatValues[statType].Add(new SavedStatValue(statIdentifier, MathHelper.Min(value, maxValue), removeOnDeath, removeAfterRound));
|
SavedStatValues[statType].Add(new SavedStatValue(statIdentifier, MathHelper.Min(value, maxValue), removeOnDeath, removeAfterRound));
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
|
if (changed) { OnPermanentStatChanged(statType); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-6
@@ -11,6 +11,7 @@ namespace Barotrauma.Abilities
|
|||||||
protected readonly List<StatusEffect> statusEffects;
|
protected readonly List<StatusEffect> statusEffects;
|
||||||
|
|
||||||
private readonly bool nearbyCharactersAppliesToSelf;
|
private readonly bool nearbyCharactersAppliesToSelf;
|
||||||
|
private readonly bool nearbyCharactersAppliesToAllies;
|
||||||
private readonly bool applyToSelected;
|
private readonly bool applyToSelected;
|
||||||
|
|
||||||
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
|
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
|
||||||
@@ -20,6 +21,7 @@ namespace Barotrauma.Abilities
|
|||||||
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
statusEffects = CharacterAbilityGroup.ParseStatusEffects(CharacterTalent, abilityElement.GetChildElement("statuseffects"));
|
||||||
applyToSelected = abilityElement.GetAttributeBool("applytoselected", false);
|
applyToSelected = abilityElement.GetAttributeBool("applytoselected", false);
|
||||||
nearbyCharactersAppliesToSelf = abilityElement.GetAttributeBool("nearbycharactersappliestoself", true);
|
nearbyCharactersAppliesToSelf = abilityElement.GetAttributeBool("nearbycharactersappliestoself", true);
|
||||||
|
nearbyCharactersAppliesToAllies = abilityElement.GetAttributeBool("nearbycharactersappliestoallies", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ApplyEffectSpecific(Character targetCharacter)
|
protected void ApplyEffectSpecific(Character targetCharacter)
|
||||||
@@ -40,6 +42,10 @@ namespace Barotrauma.Abilities
|
|||||||
{
|
{
|
||||||
targets.RemoveAll(c => c == Character);
|
targets.RemoveAll(c => c == Character);
|
||||||
}
|
}
|
||||||
|
if (!nearbyCharactersAppliesToAllies)
|
||||||
|
{
|
||||||
|
targets.RemoveAll(c => c is Character otherCharacter && HumanAIController.IsFriendly(otherCharacter, Character));
|
||||||
|
}
|
||||||
statusEffect.SetUser(Character);
|
statusEffect.SetUser(Character);
|
||||||
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targets);
|
statusEffect.Apply(ActionType.OnAbility, EffectDeltaTime, targetCharacter, targets);
|
||||||
}
|
}
|
||||||
@@ -56,17 +62,20 @@ namespace Barotrauma.Abilities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected override void ApplyEffect()
|
protected override void ApplyEffect()
|
||||||
{
|
|
||||||
ApplyEffectSpecific(Character);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ApplyEffect(AbilityObject abilityObject)
|
|
||||||
{
|
{
|
||||||
if (applyToSelected && Character.SelectedCharacter is Character selectedCharacter)
|
if (applyToSelected && Character.SelectedCharacter is Character selectedCharacter)
|
||||||
{
|
{
|
||||||
ApplyEffectSpecific(selectedCharacter);
|
ApplyEffectSpecific(selectedCharacter);
|
||||||
}
|
}
|
||||||
else if ((abilityObject as IAbilityCharacter)?.Character is Character targetCharacter)
|
else
|
||||||
|
{
|
||||||
|
ApplyEffectSpecific(Character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ApplyEffect(AbilityObject abilityObject)
|
||||||
|
{
|
||||||
|
if ((abilityObject as IAbilityCharacter)?.Character is Character targetCharacter)
|
||||||
{
|
{
|
||||||
ApplyEffectSpecific(targetCharacter);
|
ApplyEffectSpecific(targetCharacter);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ namespace Barotrauma.Abilities
|
|||||||
private readonly bool setValue;
|
private readonly bool setValue;
|
||||||
|
|
||||||
//private readonly float maximumValue;
|
//private readonly float maximumValue;
|
||||||
|
public override bool AllowClientSimulation => true;
|
||||||
public override bool AppliesEffectOnIntervalUpdate => true;
|
public override bool AppliesEffectOnIntervalUpdate => true;
|
||||||
|
|
||||||
public CharacterAbilityGivePermanentStat(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
public CharacterAbilityGivePermanentStat(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||||
|
|||||||
+1
@@ -6,6 +6,7 @@ namespace Barotrauma.Abilities
|
|||||||
{
|
{
|
||||||
private readonly string statIdentifier;
|
private readonly string statIdentifier;
|
||||||
public override bool AppliesEffectOnIntervalUpdate => true;
|
public override bool AppliesEffectOnIntervalUpdate => true;
|
||||||
|
public override bool AllowClientSimulation => true;
|
||||||
|
|
||||||
public CharacterAbilityResetPermanentStat(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
public CharacterAbilityResetPermanentStat(CharacterAbilityGroup characterAbilityGroup, XElement abilityElement) : base(characterAbilityGroup, abilityElement)
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ namespace Barotrauma.Abilities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (closestCharacter.SelectedConstruction == null || !Character.SelectedConstruction.HasTag(tag)) { return; }
|
if (closestCharacter.SelectedConstruction == null || !closestCharacter.SelectedConstruction.HasTag(tag)) { return; }
|
||||||
|
|
||||||
if (closestDistance < squaredMaxDistance)
|
if (closestDistance < squaredMaxDistance)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -66,6 +66,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TalentIsInTree(string talentIdentifier)
|
||||||
|
{
|
||||||
|
return TalentSubTrees.SelectMany(s => s.TalentOptionStages.SelectMany(o => o.Talents.Select(t => t.Identifier))).Any(c => c == talentIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
public static void LoadFromFile(ContentFile file)
|
public static void LoadFromFile(ContentFile file)
|
||||||
{
|
{
|
||||||
DebugConsole.Log("Loading talent tree: " + file.Path);
|
DebugConsole.Log("Loading talent tree: " + file.Path);
|
||||||
|
|||||||
@@ -602,7 +602,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
commands.Add(new Command("giveaffliction", "giveaffliction [affliction name] [affliction strength] [character name] [limb type]: Add an affliction to a character. If the name parameter is omitted, the affliction is added to the controlled character.", (string[] args) =>
|
commands.Add(new Command("giveaffliction", "giveaffliction [affliction name] [affliction strength] [character name] [limb type] [use relative strength]: Add an affliction to a character. If the name parameter is omitted, the affliction is added to the controlled character.", (string[] args) =>
|
||||||
{
|
{
|
||||||
if (args.Length < 2) { return; }
|
if (args.Length < 2) { return; }
|
||||||
|
|
||||||
@@ -622,14 +622,12 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool relativeStrength = false;
|
bool relativeStrength = false;
|
||||||
if (args.Length > 2)
|
if (args.Length > 4)
|
||||||
{
|
{
|
||||||
bool.TryParse(args[2], out relativeStrength);
|
bool.TryParse(args[4], out relativeStrength);
|
||||||
}
|
}
|
||||||
|
|
||||||
Character targetCharacter = (relativeStrength || args.Length <= 2) ? Character.Controlled : FindMatchingCharacter(new string[] { args[2] });
|
Character targetCharacter = args.Length <= 2 ? Character.Controlled : FindMatchingCharacter(new string[] { args[2] });
|
||||||
|
|
||||||
|
|
||||||
if (targetCharacter != null)
|
if (targetCharacter != null)
|
||||||
{
|
{
|
||||||
Limb targetLimb = targetCharacter.AnimController.MainLimb;
|
Limb targetLimb = targetCharacter.AnimController.MainLimb;
|
||||||
@@ -1889,9 +1887,9 @@ namespace Barotrauma
|
|||||||
if (!IsCommandPermitted(splitCommand[0].ToLowerInvariant(), GameMain.Client))
|
if (!IsCommandPermitted(splitCommand[0].ToLowerInvariant(), GameMain.Client))
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
AddWarning("You're not permitted to use the command \"{matchingCommand.Name}\". Executing the command anyway because this is a debug build.");
|
AddWarning($"You're not permitted to use the command \"{splitCommand[0].ToLowerInvariant()}\". Executing the command anyway because this is a debug build.");
|
||||||
#else
|
#else
|
||||||
ThrowError("You're not permitted to use the command \"" + splitCommand[0].ToLowerInvariant() + "\"!");
|
ThrowError($"You're not permitted to use the command \"{splitCommand[0].ToLowerInvariant()}\"!");
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
OnReduceAffliction,
|
OnReduceAffliction,
|
||||||
OnAddDamageAffliction,
|
OnAddDamageAffliction,
|
||||||
OnSelfRagdoll,
|
OnSelfRagdoll,
|
||||||
|
OnRagdoll,
|
||||||
OnRoundEnd,
|
OnRoundEnd,
|
||||||
OnAnyMissionCompleted,
|
OnAnyMissionCompleted,
|
||||||
OnAllMissionsCompleted,
|
OnAllMissionsCompleted,
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ namespace Barotrauma
|
|||||||
if (eventSet == null) { return; }
|
if (eventSet == null) { return; }
|
||||||
if (eventSet.OncePerOutpost)
|
if (eventSet.OncePerOutpost)
|
||||||
{
|
{
|
||||||
foreach (EventPrefab ep in eventSet.EventPrefabs.Select(e => e.prefab))
|
foreach (EventPrefab ep in eventSet.EventPrefabs.SelectMany(e => e.Prefabs))
|
||||||
{
|
{
|
||||||
if (!level.LevelData.NonRepeatableEvents.Contains(ep))
|
if (!level.LevelData.NonRepeatableEvents.Contains(ep))
|
||||||
{
|
{
|
||||||
@@ -434,23 +434,31 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var suitablePrefabs = eventSet.EventPrefabs.FindAll(e =>
|
bool isPrefabSuitable(EventPrefab p)
|
||||||
string.IsNullOrEmpty(e.prefab.BiomeIdentifier) ||
|
=> string.IsNullOrEmpty(p.BiomeIdentifier) ||
|
||||||
e.prefab.BiomeIdentifier.Equals(level.LevelData?.Biome?.Identifier, StringComparison.OrdinalIgnoreCase));
|
p.BiomeIdentifier.Equals(level.LevelData?.Biome?.Identifier, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
var suitablePrefabSubsets = eventSet.EventPrefabs
|
||||||
|
.FindAll(p => p.Prefabs.Any(isPrefabSuitable));
|
||||||
|
|
||||||
for (int i = 0; i < applyCount; i++)
|
for (int i = 0; i < applyCount; i++)
|
||||||
{
|
{
|
||||||
if (eventSet.ChooseRandom)
|
if (eventSet.ChooseRandom)
|
||||||
{
|
{
|
||||||
if (suitablePrefabs.Count > 0)
|
if (suitablePrefabSubsets.Count > 0)
|
||||||
{
|
{
|
||||||
var unusedEvents = new List<(EventPrefab prefab, float commonness, float probability)>(suitablePrefabs);
|
var unusedEvents = suitablePrefabSubsets.ToList();
|
||||||
for (int j = 0; j < eventSet.EventCount; j++)
|
for (int j = 0; j < eventSet.EventCount; j++)
|
||||||
{
|
{
|
||||||
if (unusedEvents.All(e => CalculateCommonness(e.prefab, e.commonness) <= 0.0f)) { break; }
|
if (unusedEvents.All(e => e.Prefabs.All(p => CalculateCommonness(p, e.Commonness) <= 0.0f))) { break; }
|
||||||
(EventPrefab eventPrefab, float commonness, float probability) = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => CalculateCommonness(e.prefab, e.commonness)).ToList(), rand);
|
EventSet.SubEventPrefab subEventPrefab = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => e.Prefabs.Max(p => CalculateCommonness(p, e.Commonness))).ToList(), rand);
|
||||||
if (eventPrefab != null && rand.NextDouble() <= probability)
|
(IEnumerable<EventPrefab> eventPrefabs, float commonness, float probability) = subEventPrefab;
|
||||||
|
if (eventPrefabs != null && rand.NextDouble() <= probability)
|
||||||
{
|
{
|
||||||
|
var finalPrefabs = eventPrefabs.Where(isPrefabSuitable).ToArray();
|
||||||
|
var finalPrefabCommonnesses = finalPrefabs.Select(p => p.Commonness).ToArray();
|
||||||
|
var eventPrefab = ToolBox.SelectWeightedRandom(finalPrefabs, finalPrefabCommonnesses, rand);
|
||||||
|
|
||||||
var newEvent = eventPrefab.CreateInstance();
|
var newEvent = eventPrefab.CreateInstance();
|
||||||
if (newEvent == null) { continue; }
|
if (newEvent == null) { continue; }
|
||||||
newEvent.Init(true);
|
newEvent.Init(true);
|
||||||
@@ -465,7 +473,7 @@ namespace Barotrauma
|
|||||||
selectedEvents.Add(eventSet, new List<Event>());
|
selectedEvents.Add(eventSet, new List<Event>());
|
||||||
}
|
}
|
||||||
selectedEvents[eventSet].Add(newEvent);
|
selectedEvents[eventSet].Add(newEvent);
|
||||||
unusedEvents.Remove((eventPrefab, commonness, probability));
|
unusedEvents.Remove(subEventPrefab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -480,9 +488,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach ((EventPrefab eventPrefab, float commonness, float probability) in suitablePrefabs)
|
foreach ((IEnumerable<EventPrefab> eventPrefabs, float commonness, float probability) in suitablePrefabSubsets)
|
||||||
{
|
{
|
||||||
if (rand.NextDouble() > probability) { continue; }
|
if (rand.NextDouble() > probability) { continue; }
|
||||||
|
|
||||||
|
var finalPrefabs = eventPrefabs.Where(isPrefabSuitable).ToArray();
|
||||||
|
var finalPrefabCommonnesses = finalPrefabs.Select(p => p.Commonness).ToArray();
|
||||||
|
var eventPrefab = ToolBox.SelectWeightedRandom(finalPrefabs, finalPrefabCommonnesses, rand);
|
||||||
var newEvent = eventPrefab.CreateInstance();
|
var newEvent = eventPrefab.CreateInstance();
|
||||||
if (newEvent == null) { continue; }
|
if (newEvent == null) { continue; }
|
||||||
newEvent.Init(true);
|
newEvent.Init(true);
|
||||||
@@ -866,7 +878,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private float CalculateDistanceTraveled()
|
private float CalculateDistanceTraveled()
|
||||||
{
|
{
|
||||||
if (level == null) { return 0.0f; }
|
if (level == null || pathFinder == null) { return 0.0f; }
|
||||||
var refEntity = GetRefEntity();
|
var refEntity = GetRefEntity();
|
||||||
if (refEntity == null) { return 0.0f; }
|
if (refEntity == null) { return 0.0f; }
|
||||||
Vector2 target = ConvertUnits.ToSimUnits(level.EndPosition);
|
Vector2 target = ConvertUnits.ToSimUnits(level.EndPosition);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace Barotrauma
|
|||||||
BiomeIdentifier = ConfigElement.GetAttributeString("biome", string.Empty);
|
BiomeIdentifier = ConfigElement.GetAttributeString("biome", string.Empty);
|
||||||
Commonness = element.GetAttributeFloat("commonness", 1.0f);
|
Commonness = element.GetAttributeFloat("commonness", 1.0f);
|
||||||
Probability = Math.Clamp(element.GetAttributeFloat(1.0f, "probability", "spawnprobability"), 0, 1);
|
Probability = Math.Clamp(element.GetAttributeFloat(1.0f, "probability", "spawnprobability"), 0, 1);
|
||||||
TriggerEventCooldown = element.GetAttributeBool("triggereventcooldown", true);
|
TriggerEventCooldown = element.GetAttributeBool("triggereventcooldown", EventType != typeof(ScriptedEvent));
|
||||||
|
|
||||||
UnlockPathEvent = element.GetAttributeBool("unlockpathevent", false);
|
UnlockPathEvent = element.GetAttributeBool("unlockpathevent", false);
|
||||||
UnlockPathTooltip = element.GetAttributeString("unlockpathtooltip", "lockedpathtooltip");
|
UnlockPathTooltip = element.GetAttributeString("unlockpathtooltip", "lockedpathtooltip");
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Barotrauma.Extensions;
|
using Barotrauma.Extensions;
|
||||||
@@ -48,10 +49,10 @@ namespace Barotrauma
|
|||||||
List<EventPrefab> eventPrefabs = new List<EventPrefab>(PrefabList);
|
List<EventPrefab> eventPrefabs = new List<EventPrefab>(PrefabList);
|
||||||
foreach (var eventSet in List)
|
foreach (var eventSet in List)
|
||||||
{
|
{
|
||||||
eventPrefabs.AddRange(eventSet.EventPrefabs.Select(ep => ep.prefab));
|
eventPrefabs.AddRange(eventSet.EventPrefabs.SelectMany(ep => ep.Prefabs));
|
||||||
foreach (var childSet in eventSet.ChildSets)
|
foreach (var childSet in eventSet.ChildSets)
|
||||||
{
|
{
|
||||||
eventPrefabs.AddRange(childSet.EventPrefabs.Select(ep => ep.prefab));
|
eventPrefabs.AddRange(childSet.EventPrefabs.SelectMany(ep => ep.Prefabs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return eventPrefabs;
|
return eventPrefabs;
|
||||||
@@ -98,7 +99,48 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public readonly Dictionary<string, float> Commonness;
|
public readonly Dictionary<string, float> Commonness;
|
||||||
|
|
||||||
public readonly List<(EventPrefab prefab, float commonness, float probability)> EventPrefabs;
|
public struct SubEventPrefab
|
||||||
|
{
|
||||||
|
public SubEventPrefab(string debugIdentifier, string[] prefabIdentifiers, float? commonness, float? probability)
|
||||||
|
{
|
||||||
|
EventPrefab tryFindPrefab(string id)
|
||||||
|
{
|
||||||
|
var prefab = PrefabList.Find(p => p.Identifier.Equals(id, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (prefab is null)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"Error in event set \"{debugIdentifier}\" - could not find the event prefab \"{id}\".");
|
||||||
|
}
|
||||||
|
return prefab;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Prefabs = prefabIdentifiers
|
||||||
|
.Select(tryFindPrefab)
|
||||||
|
.Where(p => p != null)
|
||||||
|
.ToImmutableArray();
|
||||||
|
this.Commonness = commonness ?? this.Prefabs.Select(p => p.Commonness).Max();
|
||||||
|
this.Probability = probability ?? this.Prefabs.Select(p => p.Probability).Max();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubEventPrefab(EventPrefab prefab, float commonness, float probability)
|
||||||
|
{
|
||||||
|
Prefabs = prefab.ToEnumerable().ToImmutableArray();
|
||||||
|
Commonness = commonness;
|
||||||
|
Probability = probability;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly ImmutableArray<EventPrefab> Prefabs;
|
||||||
|
public readonly float Commonness;
|
||||||
|
public readonly float Probability;
|
||||||
|
|
||||||
|
public void Deconstruct(out IEnumerable<EventPrefab> prefabs, out float commonness, out float probability)
|
||||||
|
{
|
||||||
|
prefabs = Prefabs;
|
||||||
|
commonness = Commonness;
|
||||||
|
probability = Probability;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly List<SubEventPrefab> EventPrefabs;
|
||||||
|
|
||||||
public readonly List<EventSet> ChildSets;
|
public readonly List<EventSet> ChildSets;
|
||||||
|
|
||||||
@@ -112,7 +154,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
DebugIdentifier = element.GetAttributeString("identifier", null) ?? debugIdentifier;
|
DebugIdentifier = element.GetAttributeString("identifier", null) ?? debugIdentifier;
|
||||||
Commonness = new Dictionary<string, float>();
|
Commonness = new Dictionary<string, float>();
|
||||||
EventPrefabs = new List<(EventPrefab prefab, float commonness, float probability)>();
|
EventPrefabs = new List<SubEventPrefab>();
|
||||||
ChildSets = new List<EventSet>();
|
ChildSets = new List<EventSet>();
|
||||||
|
|
||||||
BiomeIdentifier = element.GetAttributeString("biome", string.Empty);
|
BiomeIdentifier = element.GetAttributeString("biome", string.Empty);
|
||||||
@@ -178,23 +220,20 @@ namespace Barotrauma
|
|||||||
//an element with just an identifier = reference to an event prefab
|
//an element with just an identifier = reference to an event prefab
|
||||||
if (!subElement.HasElements && subElement.Attributes().First().Name.ToString().Equals("identifier", StringComparison.OrdinalIgnoreCase))
|
if (!subElement.HasElements && subElement.Attributes().First().Name.ToString().Equals("identifier", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
string identifier = subElement.GetAttributeString("identifier", "");
|
string[] identifiers = subElement.GetAttributeStringArray("identifier", Array.Empty<string>());
|
||||||
var prefab = PrefabList.Find(p => p.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase));
|
|
||||||
if (prefab == null)
|
float commonness = subElement.GetAttributeFloat("commonness", -1f);
|
||||||
{
|
float probability = subElement.GetAttributeFloat("probability", -1f);
|
||||||
DebugConsole.ThrowError($"Error in event set \"{debugIdentifier}\" - could not find the event prefab \"{identifier}\".");
|
EventPrefabs.Add(new SubEventPrefab(
|
||||||
}
|
debugIdentifier,
|
||||||
else
|
identifiers,
|
||||||
{
|
commonness>=0f ? commonness : (float?)null,
|
||||||
float commonness = subElement.GetAttributeFloat("commonness", prefab.Commonness);
|
probability>=0f ? probability : (float?)null));
|
||||||
float probability = subElement.GetAttributeFloat("probability", prefab.Probability);
|
|
||||||
EventPrefabs.Add((prefab, commonness, probability));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var prefab = new EventPrefab(subElement);
|
var prefab = new EventPrefab(subElement);
|
||||||
EventPrefabs.Add((prefab, prefab.Commonness, prefab.Probability));
|
EventPrefabs.Add(new SubEventPrefab(prefab, prefab.Commonness, prefab.Probability));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -346,13 +385,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (thisSet.ChooseRandom)
|
if (thisSet.ChooseRandom)
|
||||||
{
|
{
|
||||||
var unusedEvents = new List<(EventPrefab prefab, float commonness, float probability)>(thisSet.EventPrefabs);
|
var unusedEvents = thisSet.EventPrefabs.ToList();
|
||||||
for (int i = 0; i < thisSet.EventCount; i++)
|
for (int i = 0; i < thisSet.EventCount; i++)
|
||||||
{
|
{
|
||||||
var eventPrefab = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => e.commonness).ToList(), Rand.RandSync.Unsynced);
|
var eventPrefab = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => e.Commonness).ToList(), Rand.RandSync.Unsynced);
|
||||||
if (eventPrefab.prefab != null)
|
if (eventPrefab.Prefabs.Any(p => p != null))
|
||||||
{
|
{
|
||||||
AddEvent(stats, eventPrefab.prefab);
|
AddEvents(stats, eventPrefab.Prefabs);
|
||||||
unusedEvents.Remove(eventPrefab);
|
unusedEvents.Remove(eventPrefab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,7 +400,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (var eventPrefab in thisSet.EventPrefabs)
|
foreach (var eventPrefab in thisSet.EventPrefabs)
|
||||||
{
|
{
|
||||||
AddEvent(stats, eventPrefab.prefab);
|
AddEvents(stats, eventPrefab.Prefabs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var childSet in thisSet.ChildSets)
|
foreach (var childSet in thisSet.ChildSets)
|
||||||
@@ -370,6 +409,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AddEvents(EventDebugStats stats, IEnumerable<EventPrefab> eventPrefabs)
|
||||||
|
=> eventPrefabs.ForEach(p => AddEvent(stats, p));
|
||||||
|
|
||||||
static void AddEvent(EventDebugStats stats, EventPrefab eventPrefab)
|
static void AddEvent(EventDebugStats stats, EventPrefab eventPrefab)
|
||||||
{
|
{
|
||||||
if (eventPrefab.EventType == typeof(MonsterEvent))
|
if (eventPrefab.EventType == typeof(MonsterEvent))
|
||||||
|
|||||||
@@ -363,7 +363,7 @@ namespace Barotrauma
|
|||||||
#if CLIENT
|
#if CLIENT
|
||||||
foreach (Character character in crewCharacters)
|
foreach (Character character in crewCharacters)
|
||||||
{
|
{
|
||||||
character.Info.GiveExperience(experienceGain, isMissionExperience: true);
|
character.Info?.GiveExperience(experienceGain, isMissionExperience: true);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
foreach (Barotrauma.Networking.Client c in GameMain.Server.ConnectedClients)
|
foreach (Barotrauma.Networking.Client c in GameMain.Server.ConnectedClients)
|
||||||
|
|||||||
@@ -218,12 +218,12 @@ namespace Barotrauma
|
|||||||
return validContainers;
|
return validContainers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly float[] qualityCommonnesses = new float[Quality.MaxQuality + 1]
|
private static readonly (int quality, float commonness)[] qualityCommonnesses = new (int quality, float commonness)[Quality.MaxQuality + 1]
|
||||||
{
|
{
|
||||||
0.85f,
|
(0, 0.85f),
|
||||||
0.125f,
|
(1, 0.125f),
|
||||||
0.0225f,
|
(2, 0.0225f),
|
||||||
0.0025f,
|
(3, 0.0025f),
|
||||||
};
|
};
|
||||||
|
|
||||||
private static List<Item> SpawnItem(ItemPrefab itemPrefab, List<ItemContainer> containers, KeyValuePair<ItemContainer, PreferredContainer> validContainer, float difficultyModifier)
|
private static List<Item> SpawnItem(ItemPrefab itemPrefab, List<ItemContainer> containers, KeyValuePair<ItemContainer, PreferredContainer> validContainer, float difficultyModifier)
|
||||||
@@ -243,20 +243,15 @@ namespace Barotrauma
|
|||||||
containers.Remove(validContainer.Key);
|
containers.Remove(validContainer.Key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!validContainer.Key.Inventory.CanBePut(itemPrefab)) { break; }
|
|
||||||
|
|
||||||
int quality = 0;
|
|
||||||
float qualityCommmonnessSum = qualityCommonnesses.Sum();
|
|
||||||
float randomNumber = Rand.Range(0f, qualityCommmonnessSum, Rand.RandSync.Server);
|
|
||||||
for (int k = qualityCommonnesses.Length - 1; k >= 0; k--)
|
|
||||||
{
|
|
||||||
if (randomNumber < qualityCommonnesses[k])
|
|
||||||
{
|
|
||||||
quality = k;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var existingItem = validContainer.Key.Inventory.AllItems.FirstOrDefault(it => it.prefab == itemPrefab);
|
||||||
|
int quality =
|
||||||
|
existingItem?.Quality ??
|
||||||
|
ToolBox.SelectWeightedRandom(
|
||||||
|
qualityCommonnesses.Select(q => q.quality).ToList(),
|
||||||
|
qualityCommonnesses.Select(q => q.commonness).ToList(),
|
||||||
|
Rand.RandSync.Server);
|
||||||
|
if (!validContainer.Key.Inventory.CanBePut(itemPrefab, quality: quality)) { break; }
|
||||||
var item = new Item(itemPrefab, validContainer.Key.Item.Position, validContainer.Key.Item.Submarine)
|
var item = new Item(itemPrefab, validContainer.Key.Item.Position, validContainer.Key.Item.Submarine)
|
||||||
{
|
{
|
||||||
SpawnedInOutpost = validContainer.Key.Item.SpawnedInOutpost,
|
SpawnedInOutpost = validContainer.Key.Item.SpawnedInOutpost,
|
||||||
|
|||||||
+1
-62
@@ -1,6 +1,4 @@
|
|||||||
using Barotrauma.Networking;
|
using System.Xml.Linq;
|
||||||
using System.Globalization;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -29,65 +27,6 @@ namespace Barotrauma
|
|||||||
private XElement healthData;
|
private XElement healthData;
|
||||||
public XElement OrderData { get; private set; }
|
public XElement OrderData { get; private set; }
|
||||||
|
|
||||||
partial void InitProjSpecific(Client client);
|
|
||||||
public CharacterCampaignData(Client client, bool giveRespawnPenaltyAffliction = false)
|
|
||||||
{
|
|
||||||
Name = client.Name;
|
|
||||||
InitProjSpecific(client);
|
|
||||||
|
|
||||||
healthData = new XElement("health");
|
|
||||||
client.Character?.CharacterHealth?.Save(healthData);
|
|
||||||
if (giveRespawnPenaltyAffliction)
|
|
||||||
{
|
|
||||||
var respawnPenaltyAffliction = RespawnManager.GetRespawnPenaltyAffliction();
|
|
||||||
healthData.Add(new XElement("Affliction",
|
|
||||||
new XAttribute("identifier", respawnPenaltyAffliction.Identifier),
|
|
||||||
new XAttribute("strength", respawnPenaltyAffliction.Strength.ToString("G", CultureInfo.InvariantCulture))));
|
|
||||||
}
|
|
||||||
if (client.Character?.Inventory != null)
|
|
||||||
{
|
|
||||||
itemData = new XElement("inventory");
|
|
||||||
Character.SaveInventory(client.Character.Inventory, itemData);
|
|
||||||
}
|
|
||||||
OrderData = new XElement("orders");
|
|
||||||
if (client.Character != null)
|
|
||||||
{
|
|
||||||
CharacterInfo.SaveOrderData(client.Character.Info, OrderData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CharacterCampaignData(XElement element)
|
|
||||||
{
|
|
||||||
Name = element.GetAttributeString("name", "Unnamed");
|
|
||||||
ClientEndPoint = element.GetAttributeString("endpoint", null) ?? element.GetAttributeString("ip", "");
|
|
||||||
string steamID = element.GetAttributeString("steamid", "");
|
|
||||||
if (!string.IsNullOrEmpty(steamID))
|
|
||||||
{
|
|
||||||
ulong.TryParse(steamID, out ulong parsedID);
|
|
||||||
SteamID = parsedID;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (XElement subElement in element.Elements())
|
|
||||||
{
|
|
||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
|
||||||
{
|
|
||||||
case "character":
|
|
||||||
case "characterinfo":
|
|
||||||
CharacterInfo = new CharacterInfo(subElement);
|
|
||||||
break;
|
|
||||||
case "inventory":
|
|
||||||
itemData = subElement;
|
|
||||||
break;
|
|
||||||
case "health":
|
|
||||||
healthData = subElement;
|
|
||||||
break;
|
|
||||||
case "orders":
|
|
||||||
OrderData = subElement;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Refresh(Character character)
|
public void Refresh(Character character)
|
||||||
{
|
{
|
||||||
healthData = new XElement("health");
|
healthData = new XElement("health");
|
||||||
|
|||||||
@@ -141,10 +141,10 @@ namespace Barotrauma
|
|||||||
(SlotTypes[i] == InvSlotType.Any || slots[i].ItemCount < 1);
|
(SlotTypes[i] == InvSlotType.Any || slots[i].ItemCount < 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanBePutInSlot(ItemPrefab itemPrefab, int i, float? condition)
|
public override bool CanBePutInSlot(ItemPrefab itemPrefab, int i, float? condition, int? quality = null)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
base.CanBePutInSlot(itemPrefab, i, condition) &&
|
base.CanBePutInSlot(itemPrefab, i, condition, quality) &&
|
||||||
(SlotTypes[i] == InvSlotType.Any || slots[i].ItemCount < 1);
|
(SlotTypes[i] == InvSlotType.Any || slots[i].ItemCount < 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
string[] allSpecies = SpeciesName.Split(',');
|
string[] allSpecies = SpeciesName.Split(',');
|
||||||
string species = allSpecies.GetRandom().Trim();
|
string species = allSpecies.GetRandom().Trim();
|
||||||
Entity.Spawner.AddToSpawnQueue(species, pos);
|
Entity.Spawner?.AddToSpawnQueue(species, pos);
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrWhiteSpace(ItemIdentifier))
|
else if (!string.IsNullOrWhiteSpace(ItemIdentifier))
|
||||||
{
|
{
|
||||||
@@ -282,7 +282,7 @@ namespace Barotrauma.Items.Components
|
|||||||
pos -= sub.Position;
|
pos -= sub.Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity.Spawner.AddToSpawnQueue(prefab, pos, item.Submarine);
|
Entity.Spawner?.AddToSpawnQueue(prefab, pos, item.Submarine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -642,10 +642,8 @@ namespace Barotrauma.Items.Components
|
|||||||
item.Drop(character);
|
item.Drop(character);
|
||||||
item.SetTransform(ConvertUnits.ToSimUnits(GetAttachPosition(character)), 0.0f, findNewHull: false);
|
item.SetTransform(ConvertUnits.ToSimUnits(GetAttachPosition(character)), 0.0f, findNewHull: false);
|
||||||
}
|
}
|
||||||
|
AttachToWall();
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachToWall();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -291,13 +291,16 @@ namespace Barotrauma.Items.Components
|
|||||||
int index = Inventory.FindIndex(containedItem);
|
int index = Inventory.FindIndex(containedItem);
|
||||||
if (index >= 0 && index < slotRestrictions.Length)
|
if (index >= 0 && index < slotRestrictions.Length)
|
||||||
{
|
{
|
||||||
RelatedItem ri = slotRestrictions[index].ContainableItems?.Find(ci => ci.MatchesItem(containedItem));
|
if (slotRestrictions[index].ContainableItems != null)
|
||||||
if (ri != null)
|
|
||||||
{
|
{
|
||||||
activeContainedItems.RemoveAll(i => i.Item == containedItem);
|
activeContainedItems.RemoveAll(i => i.Item == containedItem);
|
||||||
foreach (StatusEffect effect in ri.statusEffects)
|
foreach (var containableItem in slotRestrictions[index].ContainableItems)
|
||||||
{
|
{
|
||||||
activeContainedItems.Add(new ActiveContainedItem(containedItem, effect, ri.ExcludeBroken));
|
if (!containableItem.MatchesItem(containedItem)) { continue; }
|
||||||
|
foreach (StatusEffect effect in containableItem.statusEffects)
|
||||||
|
{
|
||||||
|
activeContainedItems.Add(new ActiveContainedItem(containedItem, effect, containableItem.ExcludeBroken));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -34,6 +34,8 @@ namespace Barotrauma.Items.Components
|
|||||||
public OxygenGenerator(Item item, XElement element)
|
public OxygenGenerator(Item item, XElement element)
|
||||||
: base(item, element)
|
: base(item, element)
|
||||||
{
|
{
|
||||||
|
//randomize update timer so all oxygen generators don't update at the same time
|
||||||
|
ventUpdateTimer = Rand.Range(0.0f, VentUpdateInterval);
|
||||||
IsActive = true;
|
IsActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +80,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private void GetVents()
|
private void GetVents()
|
||||||
{
|
{
|
||||||
|
totalHullVolume = 0.0f;
|
||||||
ventList ??= new List<(Vent vent, float hullVolume)>();
|
ventList ??= new List<(Vent vent, float hullVolume)>();
|
||||||
ventList.Clear();
|
ventList.Clear();
|
||||||
foreach (MapEntity entity in item.linkedTo)
|
foreach (MapEntity entity in item.linkedTo)
|
||||||
@@ -87,13 +90,14 @@ namespace Barotrauma.Items.Components
|
|||||||
Vent vent = linkedItem.GetComponent<Vent>();
|
Vent vent = linkedItem.GetComponent<Vent>();
|
||||||
if (vent?.Item.CurrentHull == null) { continue; }
|
if (vent?.Item.CurrentHull == null) { continue; }
|
||||||
|
|
||||||
|
totalHullVolume += vent.Item.CurrentHull.Volume;
|
||||||
ventList.Add((vent, vent.Item.CurrentHull.Volume));
|
ventList.Add((vent, vent.Item.CurrentHull.Volume));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ventList.Count; i++)
|
for (int i = 0; i < ventList.Count; i++)
|
||||||
{
|
{
|
||||||
Vent vent = ventList[i].vent;
|
Vent vent = ventList[i].vent;
|
||||||
foreach (Hull connectedHull in vent.Item.CurrentHull.GetConnectedHulls(includingThis: false, searchDepth: 5, ignoreClosedGaps: true))
|
foreach (Hull connectedHull in vent.Item.CurrentHull.GetConnectedHulls(includingThis: false, searchDepth: 3, ignoreClosedGaps: true))
|
||||||
{
|
{
|
||||||
//another vent in the connected hull -> don't add it to this vent's total hull volume
|
//another vent in the connected hull -> don't add it to this vent's total hull volume
|
||||||
if (ventList.Any(v => v.vent != vent && v.vent.Item.CurrentHull == connectedHull)) { continue; }
|
if (ventList.Any(v => v.vent != vent && v.vent.Item.CurrentHull == connectedHull)) { continue; }
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanBePut(ItemPrefab itemPrefab, float? condition = null)
|
public bool CanBePut(ItemPrefab itemPrefab, float? condition = null, int? quality = null)
|
||||||
{
|
{
|
||||||
if (itemPrefab == null) { return false; }
|
if (itemPrefab == null) { return false; }
|
||||||
if (items.Count > 0)
|
if (items.Count > 0)
|
||||||
@@ -82,6 +82,11 @@ namespace Barotrauma
|
|||||||
if (items.Any(it => !it.IsFullCondition)) { return false; }
|
if (items.Any(it => !it.IsFullCondition)) { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (quality.HasValue)
|
||||||
|
{
|
||||||
|
if (items[0].Quality != quality.Value) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
if (items[0].Prefab.Identifier != itemPrefab.Identifier ||
|
if (items[0].Prefab.Identifier != itemPrefab.Identifier ||
|
||||||
items.Count + 1 > itemPrefab.MaxStackSize)
|
items.Count + 1 > itemPrefab.MaxStackSize)
|
||||||
{
|
{
|
||||||
@@ -172,6 +177,11 @@ namespace Barotrauma
|
|||||||
items.Clear();
|
items.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RemoveWhere(Func<Item, bool> predicate)
|
||||||
|
{
|
||||||
|
items.RemoveAll(it => predicate(it));
|
||||||
|
}
|
||||||
|
|
||||||
public bool Any()
|
public bool Any()
|
||||||
{
|
{
|
||||||
return items.Count > 0;
|
return items.Count > 0;
|
||||||
@@ -422,16 +432,16 @@ namespace Barotrauma
|
|||||||
return slots[i].CanBePut(item, ignoreCondition);
|
return slots[i].CanBePut(item, ignoreCondition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanBePut(ItemPrefab itemPrefab, float? condition = null)
|
public bool CanBePut(ItemPrefab itemPrefab, float? condition = null, int? quality = null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < capacity; i++)
|
for (int i = 0; i < capacity; i++)
|
||||||
{
|
{
|
||||||
if (CanBePutInSlot(itemPrefab, i, condition)) { return true; }
|
if (CanBePutInSlot(itemPrefab, i, condition, quality)) { return true; }
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool CanBePutInSlot(ItemPrefab itemPrefab, int i, float? condition = null)
|
public virtual bool CanBePutInSlot(ItemPrefab itemPrefab, int i, float? condition = null, int? quality = null)
|
||||||
{
|
{
|
||||||
if (i < 0 || i >= slots.Length) { return false; }
|
if (i < 0 || i >= slots.Length) { return false; }
|
||||||
return slots[i].CanBePut(itemPrefab, condition);
|
return slots[i].CanBePut(itemPrefab, condition);
|
||||||
@@ -503,7 +513,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
TrySwapping(i, item, user, createNetworkEvent, swapWholeStack: true) ||
|
TrySwapping(i, item, user, createNetworkEvent, swapWholeStack: true) ||
|
||||||
TrySwapping(i, item, user, createNetworkEvent, swapWholeStack: false);
|
TrySwapping(i, item, user, createNetworkEvent, swapWholeStack: false);
|
||||||
}
|
}
|
||||||
@@ -776,11 +786,17 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
for (int j = 0; j < capacity; j++)
|
for (int j = 0; j < capacity; j++)
|
||||||
{
|
{
|
||||||
if (slots[j].Contains(item)) { slots[j].RemoveAllItems(); };
|
if (slots[j].Contains(item))
|
||||||
|
{
|
||||||
|
slots[j].RemoveWhere(it => existingItems.Contains(it) || stackedItems.Contains(it));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (int j = 0; j < otherInventory.capacity; j++)
|
for (int j = 0; j < otherInventory.capacity; j++)
|
||||||
{
|
{
|
||||||
if (otherInventory.slots[j].Contains(existingItems.FirstOrDefault())) { otherInventory.slots[j].RemoveAllItems(); }
|
if (otherInventory.slots[j].Contains(existingItems.FirstOrDefault()))
|
||||||
|
{
|
||||||
|
otherInventory.slots[j].RemoveWhere(it => existingItems.Contains(it) || stackedItems.Contains(it));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,11 +51,11 @@ namespace Barotrauma
|
|||||||
return item != null && slots[i].CanBePut(item, ignoreCondition) && slots[i].ItemCount < container.GetMaxStackSize(i);
|
return item != null && slots[i].CanBePut(item, ignoreCondition) && slots[i].ItemCount < container.GetMaxStackSize(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanBePutInSlot(ItemPrefab itemPrefab, int i, float? condition)
|
public override bool CanBePutInSlot(ItemPrefab itemPrefab, int i, float? condition, int? quality = null)
|
||||||
{
|
{
|
||||||
if (i < 0 || i >= slots.Length) { return false; }
|
if (i < 0 || i >= slots.Length) { return false; }
|
||||||
if (!container.CanBeContained(itemPrefab, i)) { return false; }
|
if (!container.CanBeContained(itemPrefab, i)) { return false; }
|
||||||
return itemPrefab != null && slots[i].CanBePut(itemPrefab, condition) && slots[i].ItemCount < container.GetMaxStackSize(i);
|
return itemPrefab != null && slots[i].CanBePut(itemPrefab, condition, quality) && slots[i].ItemCount < container.GetMaxStackSize(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int HowManyCanBePut(ItemPrefab itemPrefab, int i, float? condition)
|
public override int HowManyCanBePut(ItemPrefab itemPrefab, int i, float? condition)
|
||||||
|
|||||||
@@ -864,6 +864,16 @@ namespace Barotrauma
|
|||||||
foreach (AbyssIsland island in AbyssIslands)
|
foreach (AbyssIsland island in AbyssIslands)
|
||||||
{
|
{
|
||||||
island.Area = new Rectangle(borders.Width - island.Area.Right, island.Area.Y, island.Area.Width, island.Area.Height);
|
island.Area = new Rectangle(borders.Width - island.Area.Right, island.Area.Y, island.Area.Width, island.Area.Height);
|
||||||
|
foreach (var cell in island.Cells)
|
||||||
|
{
|
||||||
|
if (!mirroredSites.Contains(cell.Site))
|
||||||
|
{
|
||||||
|
if (cell.Site.Coord.X % GridCellSize < 1.0f &&
|
||||||
|
cell.Site.Coord.X % GridCellSize >= 0.0f) { cell.Site.Coord.X += 1.0f; }
|
||||||
|
cell.Site.Coord.X = borders.Width - cell.Site.Coord.X;
|
||||||
|
mirroredSites.Add(cell.Site);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ruinPositions.Count; i++)
|
for (int i = 0; i < ruinPositions.Count; i++)
|
||||||
@@ -1972,7 +1982,7 @@ namespace Barotrauma
|
|||||||
ConvertUnits.ToSimUnits(entranceWayPoint.WorldPosition), collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) == null;
|
ConvertUnits.ToSimUnits(entranceWayPoint.WorldPosition), collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) == null;
|
||||||
});
|
});
|
||||||
if (closestWp == null) { continue; }
|
if (closestWp == null) { continue; }
|
||||||
entranceWayPoint.ConnectTo(closestWp);
|
ConnectWaypoints(entranceWayPoint, closestWp, outSideWaypointInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
//create a waypoint path from the ruin to the closest tunnel
|
//create a waypoint path from the ruin to the closest tunnel
|
||||||
|
|||||||
@@ -1023,7 +1023,12 @@ namespace Barotrauma
|
|||||||
#if CLIENT
|
#if CLIENT
|
||||||
if (playSound && damageAmount > 0)
|
if (playSound && damageAmount > 0)
|
||||||
{
|
{
|
||||||
SoundPlayer.PlayDamageSound(attack.StructureSoundType, damageAmount, worldPosition, tags: Tags);
|
string damageSound = Prefab.DamageSound;
|
||||||
|
if (string.IsNullOrWhiteSpace(damageSound))
|
||||||
|
{
|
||||||
|
damageSound = attack.StructureSoundType;
|
||||||
|
}
|
||||||
|
SoundPlayer.PlayDamageSound(damageSound, damageAmount, worldPosition, tags: Tags);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,9 @@ namespace Barotrauma
|
|||||||
private set { size = value; }
|
private set { size = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serialize("", true)]
|
||||||
|
public string DamageSound { get; private set; }
|
||||||
|
|
||||||
public Vector2 ScaledSize => size * Scale;
|
public Vector2 ScaledSize => size * Scale;
|
||||||
|
|
||||||
protected Vector2 textureScale = Vector2.One;
|
protected Vector2 textureScale = Vector2.One;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ namespace Barotrauma.Networking
|
|||||||
UpdateExperience,
|
UpdateExperience,
|
||||||
UpdateTalents,
|
UpdateTalents,
|
||||||
UpdateMoney,
|
UpdateMoney,
|
||||||
|
UpdatePermanentStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly Entity Entity;
|
public readonly Entity Entity;
|
||||||
|
|||||||
@@ -1284,68 +1284,66 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = 0;
|
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
|
||||||
foreach (int giveExperience in giveExperiences)
|
|
||||||
{
|
{
|
||||||
Character targetCharacter = CharacterFromTarget(target);
|
// these effects do not need to be run clientside, as they are replicated from server to clients anyway
|
||||||
if (targetCharacter != null && !targetCharacter.Removed)
|
|
||||||
{
|
|
||||||
targetCharacter?.Info?.GiveExperience(giveExperience);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (giveSkills.Any())
|
foreach (int giveExperience in giveExperiences)
|
||||||
{
|
|
||||||
foreach ((string skillIdentifier, float amount) in giveSkills)
|
|
||||||
{
|
{
|
||||||
Character targetCharacter = CharacterFromTarget(target);
|
Character targetCharacter = CharacterFromTarget(target);
|
||||||
if (targetCharacter != null && !targetCharacter.Removed)
|
if (targetCharacter != null && !targetCharacter.Removed)
|
||||||
{
|
{
|
||||||
if (skillIdentifier?.ToLowerInvariant() == "randomskill")
|
targetCharacter?.Info?.GiveExperience(giveExperience);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (giveSkills.Any())
|
||||||
|
{
|
||||||
|
foreach ((string skillIdentifier, float amount) in giveSkills)
|
||||||
|
{
|
||||||
|
Character targetCharacter = CharacterFromTarget(target);
|
||||||
|
if (targetCharacter != null && !targetCharacter.Removed)
|
||||||
{
|
{
|
||||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
|
if (skillIdentifier?.ToLowerInvariant() == "randomskill")
|
||||||
{
|
{
|
||||||
// don't let clients simulate random skill gain
|
targetCharacter.Info?.IncreaseSkillLevel(GetRandomSkill(), amount);
|
||||||
continue;
|
|
||||||
|
string GetRandomSkill()
|
||||||
|
{
|
||||||
|
return targetCharacter.Info?.Job?.Skills.Select(s => s.Identifier).GetRandom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
targetCharacter.Info?.IncreaseSkillLevel(GetRandomSkill(), amount);
|
else
|
||||||
|
|
||||||
string GetRandomSkill()
|
|
||||||
{
|
{
|
||||||
return targetCharacter.Info?.Job?.Skills.Select(s => s.Identifier).GetRandom();
|
targetCharacter.Info?.IncreaseSkillLevel(skillIdentifier?.ToLowerInvariant(), amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
targetCharacter.Info?.IncreaseSkillLevel(skillIdentifier?.ToLowerInvariant(), amount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (giveTalentInfos.Any() && (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient))
|
|
||||||
{
|
|
||||||
Character targetCharacter = CharacterFromTarget(target);
|
|
||||||
if (targetCharacter?.Info == null) { continue; }
|
|
||||||
if (!TalentTree.JobTalentTrees.TryGetValue(targetCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { continue; }
|
|
||||||
// for the sake of technical simplicity, for now do not allow talents to be given if the character could unlock them in their talent tree as well
|
|
||||||
IEnumerable<string> disallowedTalents = talentTree.TalentSubTrees.SelectMany(s => s.TalentOptionStages.SelectMany(o => o.Talents.Select(t => t.Identifier)));
|
|
||||||
|
|
||||||
foreach (GiveTalentInfo giveTalentInfo in giveTalentInfos)
|
if (giveTalentInfos.Any())
|
||||||
{
|
{
|
||||||
IEnumerable<string> viableTalents = giveTalentInfo.TalentIdentifiers.Where(s => !targetCharacter.Info.UnlockedTalents.Contains(s) && !disallowedTalents.Contains(s));
|
Character targetCharacter = CharacterFromTarget(target);
|
||||||
if (viableTalents.None()) { continue; }
|
if (targetCharacter?.Info == null) { continue; }
|
||||||
|
if (!TalentTree.JobTalentTrees.TryGetValue(targetCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { continue; }
|
||||||
|
// for the sake of technical simplicity, for now do not allow talents to be given if the character could unlock them in their talent tree as well
|
||||||
|
IEnumerable<string> disallowedTalents = talentTree.TalentSubTrees.SelectMany(s => s.TalentOptionStages.SelectMany(o => o.Talents.Select(t => t.Identifier)));
|
||||||
|
|
||||||
if (giveTalentInfo.GiveRandom)
|
foreach (GiveTalentInfo giveTalentInfo in giveTalentInfos)
|
||||||
{
|
{
|
||||||
targetCharacter.GiveTalent(viableTalents.GetRandom(), true);
|
IEnumerable<string> viableTalents = giveTalentInfo.TalentIdentifiers.Where(s => !targetCharacter.Info.UnlockedTalents.Contains(s) && !disallowedTalents.Contains(s));
|
||||||
}
|
if (viableTalents.None()) { continue; }
|
||||||
else
|
|
||||||
{
|
if (giveTalentInfo.GiveRandom)
|
||||||
foreach (string talent in viableTalents)
|
|
||||||
{
|
{
|
||||||
targetCharacter.GiveTalent(talent, true);
|
targetCharacter.GiveTalent(viableTalents.GetRandom(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (string talent in viableTalents)
|
||||||
|
{
|
||||||
|
targetCharacter.GiveTalent(talent, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,38 @@
|
|||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
v0.1500.8.0
|
||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Additions and changes:
|
||||||
|
- More improvements and fixes to the alien ruins and the new fractal guardians.
|
||||||
|
- Improvements to character animations and sprites.
|
||||||
|
- Made ruin scan/clear missions available in outposts.
|
||||||
|
- Talent adjustments and fixes.
|
||||||
|
- Adjustments to outpost distribution: natural formations greatly reduced in the 1st zone, cities slightly reduced in the 1st zone, outposts (including specialized ones) increased in the 3rd and 4th zone.
|
||||||
|
- Made magnesium a little more common in stores and wrecks.
|
||||||
|
- Temporarily disabled magnesium exploding in water to prevent issues with talents related to it.
|
||||||
|
- Added an additonal ambience track for the ruins.
|
||||||
|
- New sounds for alien ruins and the guardians.
|
||||||
|
- Portable pumps turn off automatically when not attached to a wall.
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
- Fixed outpost events always unlocking the same escort mission.
|
||||||
|
- Fixed server occasionally failing to end the round and spamming the clients with XP notifications. Happened when the server was trying to give experience for the completed missions and there were clients in the server whose character had been removed (unstable only).
|
||||||
|
- Fixed shotgun shells not having a fabrication recipe (unstable only).
|
||||||
|
- Fixed thermal goggles being sold in outposts (unstable only).
|
||||||
|
- Fixes to ruin waypoint generation (unstable only).
|
||||||
|
- Fixes to pathfinding outside ruins (unstable only).
|
||||||
|
- Fixed oxygen generator output constantly decreasing due to the changes in the previous build (unstable only).
|
||||||
|
- Fixed long item names being unreadable on the fabricator UI.
|
||||||
|
- The hints about flooded rooms and ballast flora aren't shown in ruins, wrecks or enemy subs.
|
||||||
|
- Fixed "setclientcharacter" command crashing the server if the specified character is not found.
|
||||||
|
- Fixed autofilling subs with supplies sometimes causing high-quality items to appear on the floor near containers (unstable only).
|
||||||
|
- Fixed guardian spears being fabricatable (unstable only).
|
||||||
|
- Fixed "stowaway" event triggering an event cooldown, preventing monsters from spawning at the beginning of the round.
|
||||||
|
- Fixed clients (excluding the host) always considering friendly fire to be disabled, leading to minor cosmetic desyncs when a player applies afflictions on another one (i.e. there was a brief delay before the afflictions update client-side).
|
||||||
|
- Fixed inability to apply buffs on the crew when friendly fire is disabled.
|
||||||
|
- Fixed ItemContainers only applying the StatusEffects from the first matching Containable, even if there's multiple. Prevented the artifact-specific effects of artifact holder from executing.
|
||||||
|
- Fixed "giveaffliction" command's limbtype argument not working in multiplayer.
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------
|
||||||
v0.1500.7.0
|
v0.1500.7.0
|
||||||
---------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------
|
||||||
@@ -7,7 +42,7 @@ Additions and changes:
|
|||||||
- Added a colored border to high-quality items' inventory slots.
|
- Added a colored border to high-quality items' inventory slots.
|
||||||
- Changed the look of the skill/xp notifications to accommodate the larger numbers of notifications you can get from talents and skillbooks.
|
- Changed the look of the skill/xp notifications to accommodate the larger numbers of notifications you can get from talents and skillbooks.
|
||||||
- Added a fabricator and deconstructor to Azimuth and slightly lowered its maximum speed.
|
- Added a fabricator and deconstructor to Azimuth and slightly lowered its maximum speed.
|
||||||
- Increased Azimuth's battery out relay max power-
|
- Increased Azimuth's battery out relay max power.
|
||||||
- Field Medic now only triggers on missions.
|
- Field Medic now only triggers on missions.
|
||||||
- Reduced gravity sphere's force to make it possible to escape it with a diving suit on.
|
- Reduced gravity sphere's force to make it possible to escape it with a diving suit on.
|
||||||
- Diving suit and human ragdoll damagemodifier changes: the suits now offer less protection, but humans have a bit more natural protection towards physical damage types.
|
- Diving suit and human ragdoll damagemodifier changes: the suits now offer less protection, but humans have a bit more natural protection towards physical damage types.
|
||||||
|
|||||||
Reference in New Issue
Block a user