Merge remote-tracking branch 'upstream/master' into develop
This commit is contained in:
@@ -73,7 +73,7 @@ body:
|
|||||||
label: Version
|
label: Version
|
||||||
description: Which version of the game did the bug happen in? You can see the current version number in the bottom left corner of your screen in the main menu.
|
description: Which version of the game did the bug happen in? You can see the current version number in the bottom left corner of your screen in the main menu.
|
||||||
options:
|
options:
|
||||||
- v1.5.8.0 (Summer Update)
|
- v1.5.9.1 (Summer Update Hotfix 2)
|
||||||
- Other
|
- Other
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@@ -525,6 +525,7 @@ namespace Barotrauma
|
|||||||
ushort infoID = inc.ReadUInt16();
|
ushort infoID = inc.ReadUInt16();
|
||||||
string newName = inc.ReadString();
|
string newName = inc.ReadString();
|
||||||
string originalName = inc.ReadString();
|
string originalName = inc.ReadString();
|
||||||
|
bool renamingEnabled = inc.ReadBoolean();
|
||||||
int tagCount = inc.ReadByte();
|
int tagCount = inc.ReadByte();
|
||||||
HashSet<Identifier> tagSet = new HashSet<Identifier>();
|
HashSet<Identifier> tagSet = new HashSet<Identifier>();
|
||||||
for (int i = 0; i < tagCount; i++)
|
for (int i = 0; i < tagCount; i++)
|
||||||
@@ -538,7 +539,8 @@ namespace Barotrauma
|
|||||||
Color skinColor = inc.ReadColorR8G8B8();
|
Color skinColor = inc.ReadColorR8G8B8();
|
||||||
Color hairColor = inc.ReadColorR8G8B8();
|
Color hairColor = inc.ReadColorR8G8B8();
|
||||||
Color facialHairColor = inc.ReadColorR8G8B8();
|
Color facialHairColor = inc.ReadColorR8G8B8();
|
||||||
|
|
||||||
|
|
||||||
Identifier npcId = inc.ReadIdentifier();
|
Identifier npcId = inc.ReadIdentifier();
|
||||||
|
|
||||||
Identifier factionId = inc.ReadIdentifier();
|
Identifier factionId = inc.ReadIdentifier();
|
||||||
@@ -571,7 +573,8 @@ namespace Barotrauma
|
|||||||
CharacterInfo ch = new CharacterInfo(speciesName, newName, originalName, jobPrefab, variant, npcIdentifier: npcId)
|
CharacterInfo ch = new CharacterInfo(speciesName, newName, originalName, jobPrefab, variant, npcIdentifier: npcId)
|
||||||
{
|
{
|
||||||
ID = infoID,
|
ID = infoID,
|
||||||
MinReputationToHire = (factionId, minReputationToHire)
|
MinReputationToHire = (factionId, minReputationToHire),
|
||||||
|
RenamingEnabled = renamingEnabled
|
||||||
};
|
};
|
||||||
ch.RecreateHead(tagSet.ToImmutableHashSet(), hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
ch.RecreateHead(tagSet.ToImmutableHashSet(), hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
||||||
ch.Head.SkinColor = skinColor;
|
ch.Head.SkinColor = skinColor;
|
||||||
|
|||||||
@@ -357,6 +357,7 @@ namespace Barotrauma
|
|||||||
case EventType.Control:
|
case EventType.Control:
|
||||||
bool myCharacter = msg.ReadBoolean();
|
bool myCharacter = msg.ReadBoolean();
|
||||||
byte ownerID = msg.ReadByte();
|
byte ownerID = msg.ReadByte();
|
||||||
|
bool renamingEnabled = msg.ReadBoolean();
|
||||||
ResetNetState();
|
ResetNetState();
|
||||||
if (myCharacter)
|
if (myCharacter)
|
||||||
{
|
{
|
||||||
@@ -385,6 +386,10 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
IsRemotePlayer = ownerID > 0;
|
IsRemotePlayer = ownerID > 0;
|
||||||
}
|
}
|
||||||
|
if (info != null)
|
||||||
|
{
|
||||||
|
info.RenamingEnabled = renamingEnabled;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case EventType.Status:
|
case EventType.Status:
|
||||||
ReadStatus(msg);
|
ReadStatus(msg);
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ internal class DeathPrompt
|
|||||||
var botList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.9f), content.RectTransform));
|
var botList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.9f), content.RectTransform));
|
||||||
foreach (CharacterInfo c in GetAvailableBots())
|
foreach (CharacterInfo c in GetAvailableBots())
|
||||||
{
|
{
|
||||||
var characterFrame = campaign.CampaignUI?.CrewManagement.CreateCharacterFrame(c, botList, hideSalary: true);
|
var characterFrame = campaign.CampaignUI?.HRManagerUI.CreateCharacterFrame(c, botList, hideSalary: true);
|
||||||
if (characterFrame != null)
|
if (characterFrame != null)
|
||||||
{
|
{
|
||||||
characterFrame.UserData = c;
|
characterFrame.UserData = c;
|
||||||
|
|||||||
+53
-27
@@ -8,13 +8,16 @@ using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class CrewManagement
|
/// <summary>
|
||||||
|
/// The "HR manager" UI, which is used to hire/fire characters and rename crewmates.
|
||||||
|
/// </summary>
|
||||||
|
class HRManagerUI
|
||||||
{
|
{
|
||||||
private CampaignMode campaign => campaignUI.Campaign;
|
private CampaignMode campaign => campaignUI.Campaign;
|
||||||
private readonly CampaignUI campaignUI;
|
private readonly CampaignUI campaignUI;
|
||||||
private readonly GUIComponent parentComponent;
|
private readonly GUIComponent parentComponent;
|
||||||
|
|
||||||
private GUILayoutGroup pendingAndCrewGroup;
|
private GUIComponent pendingAndCrewPanel;
|
||||||
private GUIListBox hireableList, pendingList, crewList;
|
private GUIListBox hireableList, pendingList, crewList;
|
||||||
private GUIFrame characterPreviewFrame;
|
private GUIFrame characterPreviewFrame;
|
||||||
private GUIDropDown sortingDropDown;
|
private GUIDropDown sortingDropDown;
|
||||||
@@ -25,14 +28,21 @@ namespace Barotrauma
|
|||||||
private PlayerBalanceElement? playerBalanceElement;
|
private PlayerBalanceElement? playerBalanceElement;
|
||||||
|
|
||||||
private List<CharacterInfo> PendingHires => campaign.Map?.CurrentLocation?.HireManager?.PendingHires;
|
private List<CharacterInfo> PendingHires => campaign.Map?.CurrentLocation?.HireManager?.PendingHires;
|
||||||
|
|
||||||
// Is the player hiring a new character for themselves instead of bots for the crew?
|
|
||||||
// The window can only be used for one of these purposes at the same time.
|
|
||||||
private static bool HiringNewCharacter => GameMain.NetworkMember?.ServerSettings is { RespawnMode: RespawnMode.Permadeath, IronmanMode: false } &&
|
|
||||||
GameMain.Client?.CharacterInfo is { PermanentlyDead: true };
|
|
||||||
|
|
||||||
private static bool HasPermissionToHire => CampaignMode.AllowedToManageCampaign(
|
|
||||||
HiringNewCharacter ? ClientPermissions.ManageMoney : ClientPermissions.ManageHires);
|
private bool wasReplacingPermanentlyDeadCharacter;
|
||||||
|
/// <summary>
|
||||||
|
/// Is the player hiring a new character for themselves instead of bots for the crew?
|
||||||
|
/// The window can only be used for one of these purposes at the same time.
|
||||||
|
/// </summary>
|
||||||
|
private static bool ReplacingPermanentlyDeadCharacter =>
|
||||||
|
GameMain.NetworkMember?.ServerSettings is { RespawnMode: RespawnMode.Permadeath, IronmanMode: false } &&
|
||||||
|
GameMain.Client?.CharacterInfo is { PermanentlyDead: true };
|
||||||
|
|
||||||
|
private bool hadPermissionToHire;
|
||||||
|
private static bool HasPermissionToHire => ReplacingPermanentlyDeadCharacter ?
|
||||||
|
GameMain.NetworkMember?.ServerSettings.ReplaceCostPercentage <= 0 || CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageMoney) || CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageHires) :
|
||||||
|
CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageHires);
|
||||||
|
|
||||||
private Point resolutionWhenCreated;
|
private Point resolutionWhenCreated;
|
||||||
|
|
||||||
@@ -48,7 +58,7 @@ namespace Barotrauma
|
|||||||
SkillDesc
|
SkillDesc
|
||||||
}
|
}
|
||||||
|
|
||||||
public CrewManagement(CampaignUI campaignUI, GUIComponent parentComponent)
|
public HRManagerUI(CampaignUI campaignUI, GUIComponent parentComponent)
|
||||||
{
|
{
|
||||||
this.campaignUI = campaignUI;
|
this.campaignUI = campaignUI;
|
||||||
this.parentComponent = parentComponent;
|
this.parentComponent = parentComponent;
|
||||||
@@ -61,14 +71,19 @@ namespace Barotrauma
|
|||||||
(locationChangeInfo) => UpdateLocationView(locationChangeInfo.NewLocation, true, locationChangeInfo.PrevLocation));
|
(locationChangeInfo) => UpdateLocationView(locationChangeInfo.NewLocation, true, locationChangeInfo.PrevLocation));
|
||||||
Reputation.OnAnyReputationValueChanged.RegisterOverwriteExisting(
|
Reputation.OnAnyReputationValueChanged.RegisterOverwriteExisting(
|
||||||
"CrewManagement.UpdateLocationView".ToIdentifier(), _ => needsHireableRefresh = true);
|
"CrewManagement.UpdateLocationView".ToIdentifier(), _ => needsHireableRefresh = true);
|
||||||
|
|
||||||
|
hadPermissionToHire = HasPermissionToHire;
|
||||||
|
wasReplacingPermanentlyDeadCharacter = ReplacingPermanentlyDeadCharacter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RefreshPermissions()
|
public void RefreshUI()
|
||||||
{
|
{
|
||||||
RefreshCrewFrames(hireableList);
|
RefreshCrewFrames(hireableList);
|
||||||
RefreshCrewFrames(crewList);
|
RefreshCrewFrames(crewList);
|
||||||
RefreshCrewFrames(pendingList);
|
RefreshCrewFrames(pendingList);
|
||||||
if (clearAllButton != null) { clearAllButton.Enabled = HasPermissionToHire; }
|
if (clearAllButton != null) { clearAllButton.Enabled = HasPermissionToHire; }
|
||||||
|
hadPermissionToHire = HasPermissionToHire;
|
||||||
|
wasReplacingPermanentlyDeadCharacter = ReplacingPermanentlyDeadCharacter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshCrewFrames(GUIListBox listBox)
|
private void RefreshCrewFrames(GUIListBox listBox)
|
||||||
@@ -80,8 +95,11 @@ namespace Barotrauma
|
|||||||
if (child.FindChild(c => c is GUIButton && c.UserData is CharacterInfo, true) is GUIButton buyButton)
|
if (child.FindChild(c => c is GUIButton && c.UserData is CharacterInfo, true) is GUIButton buyButton)
|
||||||
{
|
{
|
||||||
CharacterInfo characterInfo = buyButton.UserData as CharacterInfo;
|
CharacterInfo characterInfo = buyButton.UserData as CharacterInfo;
|
||||||
bool enougMoneyToHire = !HiringNewCharacter || campaign.CanAfford(HireManager.GetSalaryFor(characterInfo));
|
buyButton.Enabled =
|
||||||
buyButton.Enabled = HasPermissionToHire && EnoughReputationToHire(characterInfo) && enougMoneyToHire;
|
//"normal buying" is disabled when replacing a dead character
|
||||||
|
!ReplacingPermanentlyDeadCharacter &&
|
||||||
|
HasPermissionToHire &&
|
||||||
|
EnoughReputationToHire(characterInfo) && campaign.CanAffordNewCharacter(characterInfo);
|
||||||
foreach (GUITextBlock text in child.GetAllChildren<GUITextBlock>())
|
foreach (GUITextBlock text in child.GetAllChildren<GUITextBlock>())
|
||||||
{
|
{
|
||||||
text.TextColor = new Color(text.TextColor, buyButton.Enabled ? 1.0f : 0.6f);
|
text.TextColor = new Color(text.TextColor, buyButton.Enabled ? 1.0f : 0.6f);
|
||||||
@@ -182,11 +200,13 @@ namespace Barotrauma
|
|||||||
|
|
||||||
playerBalanceElement = CampaignUI.AddBalanceElement(pendingAndCrewMainGroup, new Vector2(1.0f, 0.75f / 14.0f));
|
playerBalanceElement = CampaignUI.AddBalanceElement(pendingAndCrewMainGroup, new Vector2(1.0f, 0.75f / 14.0f));
|
||||||
|
|
||||||
pendingAndCrewGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
|
pendingAndCrewPanel = new GUIFrame(new RectTransform(new Vector2(1.0f, 13.25f / 14.0f), pendingAndCrewMainGroup.RectTransform)
|
||||||
parent: new GUIFrame(new RectTransform(new Vector2(1.0f, 13.25f / 14.0f), pendingAndCrewMainGroup.RectTransform)
|
{
|
||||||
{
|
MaxSize = new Point(panelMaxWidth, campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Rect.Height)
|
||||||
MaxSize = new Point(panelMaxWidth, campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Rect.Height)
|
});
|
||||||
}).RectTransform));
|
|
||||||
|
var pendingAndCrewGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
|
||||||
|
parent: pendingAndCrewPanel.RectTransform));
|
||||||
|
|
||||||
float height = 0.05f;
|
float height = 0.05f;
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, height), pendingAndCrewGroup.RectTransform), TextManager.Get("campaigncrew.pending"), font: GUIStyle.SubHeadingFont);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, height), pendingAndCrewGroup.RectTransform), TextManager.Get("campaigncrew.pending"), font: GUIStyle.SubHeadingFont);
|
||||||
@@ -456,7 +476,7 @@ namespace Barotrauma
|
|||||||
if (listBox != crewList)
|
if (listBox != crewList)
|
||||||
{
|
{
|
||||||
new GUITextBlock(new RectTransform(new Vector2(width, 1.0f), mainGroup.RectTransform),
|
new GUITextBlock(new RectTransform(new Vector2(width, 1.0f), mainGroup.RectTransform),
|
||||||
TextManager.FormatCurrency(HireManager.GetSalaryFor(characterInfo)),
|
TextManager.FormatCurrency(ReplacingPermanentlyDeadCharacter ? campaign.NewCharacterCost(characterInfo) : HireManager.GetSalaryFor(characterInfo)),
|
||||||
textAlignment: Alignment.Center)
|
textAlignment: Alignment.Center)
|
||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
@@ -476,12 +496,12 @@ namespace Barotrauma
|
|||||||
ToolTip = TextManager.Get("hirebutton"),
|
ToolTip = TextManager.Get("hirebutton"),
|
||||||
ClickSound = GUISoundType.Cart,
|
ClickSound = GUISoundType.Cart,
|
||||||
UserData = characterInfo,
|
UserData = characterInfo,
|
||||||
Enabled = CanHire(characterInfo) && !HiringNewCharacter,
|
Enabled = CanHire(characterInfo) && !ReplacingPermanentlyDeadCharacter,
|
||||||
OnClicked = (b, o) => AddPendingHire(o as CharacterInfo)
|
OnClicked = (b, o) => AddPendingHire(o as CharacterInfo)
|
||||||
};
|
};
|
||||||
hireButton.OnAddedToGUIUpdateList += (GUIComponent btn) =>
|
hireButton.OnAddedToGUIUpdateList += (GUIComponent btn) =>
|
||||||
{
|
{
|
||||||
if (HiringNewCharacter)
|
if (ReplacingPermanentlyDeadCharacter)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -500,9 +520,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (HiringNewCharacter)
|
if (ReplacingPermanentlyDeadCharacter)
|
||||||
{
|
{
|
||||||
bool canHire = CanHire(characterInfo) && campaign.CanAfford(HireManager.GetSalaryFor(characterInfo));
|
bool canHire = CanHire(characterInfo) && campaign.CanAffordNewCharacter(characterInfo);
|
||||||
var takeoverButton = new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementTakeControlButton")
|
var takeoverButton = new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementTakeControlButton")
|
||||||
{
|
{
|
||||||
ToolTip = canHire ? TextManager.Get("hireandtakecontrol") : TextManager.Get("hireandtakecontroldisabled"),
|
ToolTip = canHire ? TextManager.Get("hireandtakecontrol") : TextManager.Get("hireandtakecontroldisabled"),
|
||||||
@@ -516,7 +536,7 @@ namespace Barotrauma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Client client = gameClient.ConnectedClients.FirstOrDefault(c => c.SessionId == gameClient.SessionId);
|
Client client = gameClient.ConnectedClients.FirstOrDefault(c => c.SessionId == gameClient.SessionId);
|
||||||
if (!campaign.TryPurchase(client, HireManager.GetSalaryFor(characterInfo)))
|
if (!campaign.TryPurchase(client, campaign.NewCharacterCost(characterInfo)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -528,7 +548,7 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
takeoverButton.OnAddedToGUIUpdateList += (GUIComponent btn) =>
|
takeoverButton.OnAddedToGUIUpdateList += (GUIComponent btn) =>
|
||||||
{
|
{
|
||||||
bool canHireCurrently = HiringNewCharacter && CanHire(characterInfo) && campaign.CanAfford(HireManager.GetSalaryFor(characterInfo));
|
bool canHireCurrently = ReplacingPermanentlyDeadCharacter && CanHire(characterInfo) && campaign.CanAffordNewCharacter(characterInfo);
|
||||||
btn.ToolTip = TextManager.Get(canHireCurrently ? "hireandtakecontrol" : "hireandtakecontroldisabled");
|
btn.ToolTip = TextManager.Get(canHireCurrently ? "hireandtakecontrol" : "hireandtakecontroldisabled");
|
||||||
btn.Visible = GameMain.GameSession is { AllowHrManagerBotTakeover: true };
|
btn.Visible = GameMain.GameSession is { AllowHrManagerBotTakeover: true };
|
||||||
btn.Enabled = canHireCurrently;
|
btn.Enabled = canHireCurrently;
|
||||||
@@ -931,9 +951,15 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
|
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When showing this window to someone hiring a new character, the right side panels aren't needed
|
// When showing this window to someone hiring a new character, the right side panels aren't needed
|
||||||
pendingAndCrewGroup.Visible = !HiringNewCharacter;
|
pendingAndCrewPanel.Visible = !ReplacingPermanentlyDeadCharacter;
|
||||||
|
|
||||||
|
if (hadPermissionToHire != HasPermissionToHire ||
|
||||||
|
wasReplacingPermanentlyDeadCharacter != ReplacingPermanentlyDeadCharacter)
|
||||||
|
{
|
||||||
|
RefreshUI();
|
||||||
|
}
|
||||||
|
|
||||||
if (needsHireableRefresh)
|
if (needsHireableRefresh)
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -71,7 +71,9 @@ namespace Barotrauma
|
|||||||
private HashSet<Identifier> selectedTalents = new HashSet<Identifier>();
|
private HashSet<Identifier> selectedTalents = new HashSet<Identifier>();
|
||||||
|
|
||||||
private readonly Queue<Identifier> showCaseClosureQueue = new();
|
private readonly Queue<Identifier> showCaseClosureQueue = new();
|
||||||
|
|
||||||
|
private GUITextBlock? nameBlock;
|
||||||
|
private GUIButton? renameButton;
|
||||||
private GUIListBox? skillListBox;
|
private GUIListBox? skillListBox;
|
||||||
private GUITextBlock? talentPointText;
|
private GUITextBlock? talentPointText;
|
||||||
private GUIProgressBar? experienceBar;
|
private GUIProgressBar? experienceBar;
|
||||||
@@ -134,7 +136,6 @@ namespace Barotrauma
|
|||||||
GUILayoutGroup playerFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), containerFrame.RectTransform, Anchor.TopCenter));
|
GUILayoutGroup playerFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), containerFrame.RectTransform, Anchor.TopCenter));
|
||||||
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
|
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
|
||||||
|
|
||||||
// TODO: What is CampaignCharacterDiscarded and can it be relevant in permadeath mode?
|
|
||||||
if (!GameMain.NetLobbyScreen.PermadeathMode)
|
if (!GameMain.NetLobbyScreen.PermadeathMode)
|
||||||
{
|
{
|
||||||
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), skillLayout.RectTransform, Anchor.BottomRight),
|
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), skillLayout.RectTransform, Anchor.BottomRight),
|
||||||
@@ -174,6 +175,25 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
else if (characterInfo != null)
|
||||||
|
{
|
||||||
|
renameButton = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), skillLayout.RectTransform, Anchor.BottomRight),
|
||||||
|
text: TextManager.Get("button.RenameCharacter"), style: "GUIButtonSmall")
|
||||||
|
{
|
||||||
|
Enabled = characterInfo.RenamingEnabled,
|
||||||
|
ToolTip = TextManager.Get("permadeath.rename.description"),
|
||||||
|
IgnoreLayoutGroups = false,
|
||||||
|
TextBlock =
|
||||||
|
{
|
||||||
|
AutoScaleHorizontal = true
|
||||||
|
},
|
||||||
|
OnClicked = (_, _) =>
|
||||||
|
{
|
||||||
|
CreateRenamePopup();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
GUILayoutGroup characterCloseButtonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), characterLayout.RectTransform), childAnchor: Anchor.BottomCenter);
|
GUILayoutGroup characterCloseButtonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), characterLayout.RectTransform), childAnchor: Anchor.BottomCenter);
|
||||||
new GUIButton(new RectTransform(new Vector2(0.4f, 1f), characterCloseButtonLayout.RectTransform), TextManager.Get("ApplySettingsButton")) //TODO: Is this text appropriate for this circumstance for all languages?
|
new GUIButton(new RectTransform(new Vector2(0.4f, 1f), characterCloseButtonLayout.RectTransform), TextManager.Get("ApplySettingsButton")) //TODO: Is this text appropriate for this circumstance for all languages?
|
||||||
@@ -189,6 +209,57 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateRenamePopup()
|
||||||
|
{
|
||||||
|
GUIMessageBox renamePopup = new(
|
||||||
|
TextManager.Get("button.RenameCharacter"), TextManager.Get("permadeath.rename.description"),
|
||||||
|
new LocalizedString[] { TextManager.Get("Confirm"), TextManager.Get("Cancel") }, minSize: new Point(0, GUI.IntScale(230)));
|
||||||
|
GUITextBox newNameBox = new(new(Vector2.One, renamePopup.Content.RectTransform), "")
|
||||||
|
{
|
||||||
|
OnEnterPressed = (textBox, text) =>
|
||||||
|
{
|
||||||
|
textBox.Text = text.Trim();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
renamePopup.Buttons[0].OnClicked += (_, _) =>
|
||||||
|
{
|
||||||
|
if (newNameBox.Text?.Trim() is string newName && newName != "")
|
||||||
|
{
|
||||||
|
if (characterInfo != null)
|
||||||
|
{
|
||||||
|
if (newNameBox.Text == characterInfo.Name)
|
||||||
|
{
|
||||||
|
renamePopup.Close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (GameMain.GameSession?.Campaign?.CampaignUI?.HRManagerUI is { } crewManagement)
|
||||||
|
{
|
||||||
|
crewManagement.RenameCharacter(characterInfo, newName);
|
||||||
|
if (nameBlock != null)
|
||||||
|
{
|
||||||
|
nameBlock.Text = newName;
|
||||||
|
}
|
||||||
|
if (renameButton != null)
|
||||||
|
{
|
||||||
|
renameButton.Enabled = false;
|
||||||
|
}
|
||||||
|
renamePopup.Close();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
DebugConsole.ThrowError("Tried to rename character, but CharacterInfo completely missing!");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newNameBox.Flash();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
renamePopup.Buttons[1].OnClicked += renamePopup.Close;
|
||||||
|
}
|
||||||
|
|
||||||
private void CreateStatPanel(GUIComponent parent, CharacterInfo info)
|
private void CreateStatPanel(GUIComponent parent, CharacterInfo info)
|
||||||
{
|
{
|
||||||
Job job = info.Job;
|
Job job = info.Job;
|
||||||
@@ -206,7 +277,7 @@ namespace Barotrauma
|
|||||||
CanBeFocused = true
|
CanBeFocused = true
|
||||||
};
|
};
|
||||||
|
|
||||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), nameLayout.RectTransform), info.Name, font: GUIStyle.SubHeadingFont);
|
nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), nameLayout.RectTransform), info.Name, font: GUIStyle.SubHeadingFont);
|
||||||
|
|
||||||
if (!info.OmitJobInMenus)
|
if (!info.OmitJobInMenus)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -522,6 +522,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GameMain.GameSession?.Campaign?.CampaignUI?.HRManagerUI is { } crewManagement)
|
||||||
|
{
|
||||||
|
crewManagement.RefreshUI();
|
||||||
|
}
|
||||||
|
|
||||||
return background;
|
return background;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,6 +537,10 @@ namespace Barotrauma
|
|||||||
crewList.RemoveChild(component);
|
crewList.RemoveChild(component);
|
||||||
traitorButtons.RemoveAll(t => t.IsChildOf(component, recursive: true));
|
traitorButtons.RemoveAll(t => t.IsChildOf(component, recursive: true));
|
||||||
}
|
}
|
||||||
|
if (GameMain.GameSession?.Campaign?.CampaignUI?.HRManagerUI is { } crewManagement)
|
||||||
|
{
|
||||||
|
crewManagement.RefreshUI();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetCharacterComponentTooltip(GUIComponent characterComponent)
|
private static void SetCharacterComponentTooltip(GUIComponent characterComponent)
|
||||||
|
|||||||
@@ -344,18 +344,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SubmarineInfo GetPredefinedStartOutpost()
|
|
||||||
{
|
|
||||||
if (Map?.CurrentLocation?.Type?.GetForcedOutpostGenerationParams() is OutpostGenerationParams parameters && !parameters.OutpostFilePath.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return new SubmarineInfo(parameters.OutpostFilePath.Value)
|
|
||||||
{
|
|
||||||
OutpostGenerationParams = parameters
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
partial void NPCInteractProjSpecific(Character npc, Character interactor)
|
partial void NPCInteractProjSpecific(Character npc, Character interactor)
|
||||||
{
|
{
|
||||||
if (npc == null || interactor == null) { return; }
|
if (npc == null || interactor == null) { return; }
|
||||||
@@ -370,7 +358,7 @@ namespace Barotrauma
|
|||||||
UpgradeManager.CreateUpgradeErrorMessage(TextManager.Get("Dialog.CantUpgrade").Value, IsSinglePlayer, npc);
|
UpgradeManager.CreateUpgradeErrorMessage(TextManager.Get("Dialog.CantUpgrade").Value, IsSinglePlayer, npc);
|
||||||
return;
|
return;
|
||||||
case InteractionType.Crew when GameMain.NetworkMember != null:
|
case InteractionType.Crew when GameMain.NetworkMember != null:
|
||||||
CampaignUI.CrewManagement.SendCrewState(false);
|
CampaignUI.HRManagerUI.SendCrewState(false);
|
||||||
goto default;
|
goto default;
|
||||||
case InteractionType.MedicalClinic:
|
case InteractionType.MedicalClinic:
|
||||||
CampaignUI.MedicalClinic.RequestLatestPending();
|
CampaignUI.MedicalClinic.RequestLatestPending();
|
||||||
|
|||||||
+20
-6
@@ -939,7 +939,16 @@ namespace Barotrauma
|
|||||||
UInt16 renamedIdentifier = msg.ReadUInt16();
|
UInt16 renamedIdentifier = msg.ReadUInt16();
|
||||||
string newName = msg.ReadString();
|
string newName = msg.ReadString();
|
||||||
CharacterInfo renamedCharacter = CrewManager.GetCharacterInfos().FirstOrDefault(info => info.ID == renamedIdentifier);
|
CharacterInfo renamedCharacter = CrewManager.GetCharacterInfos().FirstOrDefault(info => info.ID == renamedIdentifier);
|
||||||
if (renamedCharacter != null) { CrewManager.RenameCharacter(renamedCharacter, newName); }
|
if (renamedCharacter != null)
|
||||||
|
{
|
||||||
|
CrewManager.RenameCharacter(renamedCharacter, newName);
|
||||||
|
// Since renaming can only be done once in permadeath, we can safely set this to false to disable the renaming in the UI.
|
||||||
|
renamedCharacter.RenamingEnabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"Could not find a character to rename with the ID {renamedIdentifier}.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fireCharacter = msg.ReadBoolean();
|
bool fireCharacter = msg.ReadBoolean();
|
||||||
@@ -951,15 +960,15 @@ namespace Barotrauma
|
|||||||
if (firedCharacter != null) { CrewManager.FireCharacter(firedCharacter); }
|
if (firedCharacter != null) { CrewManager.FireCharacter(firedCharacter); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map?.CurrentLocation?.HireManager != null && CampaignUI?.CrewManagement != null)
|
if (map?.CurrentLocation?.HireManager != null && CampaignUI?.HRManagerUI != null)
|
||||||
{
|
{
|
||||||
//can't apply until we have the latest save file
|
//can't apply until we have the latest save file
|
||||||
if (!NetIdUtils.IdMoreRecent(pendingSaveID, LastSaveID))
|
if (!NetIdUtils.IdMoreRecent(pendingSaveID, LastSaveID))
|
||||||
{
|
{
|
||||||
CampaignUI.CrewManagement.SetHireables(map.CurrentLocation, availableHires);
|
CampaignUI.HRManagerUI.SetHireables(map.CurrentLocation, availableHires);
|
||||||
if (hiredCharacters.Any()) { CampaignUI.CrewManagement.ValidateHires(hiredCharacters, takeMoney: false, createNotification: createNotification); }
|
if (hiredCharacters.Any()) { CampaignUI.HRManagerUI.ValidateHires(hiredCharacters, takeMoney: false, createNotification: createNotification); }
|
||||||
CampaignUI.CrewManagement.SetPendingHires(pendingHires, map.CurrentLocation);
|
CampaignUI.HRManagerUI.SetPendingHires(pendingHires, map.CurrentLocation);
|
||||||
if (renameCrewMember || fireCharacter) { CampaignUI.CrewManagement.UpdateCrew(); }
|
if (renameCrewMember || fireCharacter) { CampaignUI.HRManagerUI.UpdateCrew(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1007,6 +1016,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public override bool TryPurchase(Client client, int price)
|
public override bool TryPurchase(Client client, int price)
|
||||||
{
|
{
|
||||||
|
if (price == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!AllowedToManageCampaign(ClientPermissions.ManageMoney))
|
if (!AllowedToManageCampaign(ClientPermissions.ManageMoney))
|
||||||
{
|
{
|
||||||
return PersonalWallet.TryDeduct(price);
|
return PersonalWallet.TryDeduct(price);
|
||||||
|
|||||||
@@ -1339,7 +1339,7 @@ namespace Barotrauma.Networking
|
|||||||
if (GameMain.GameSession?.GameMode is CampaignMode campaign)
|
if (GameMain.GameSession?.GameMode is CampaignMode campaign)
|
||||||
{
|
{
|
||||||
campaign.CampaignUI?.UpgradeStore?.RequestRefresh();
|
campaign.CampaignUI?.UpgradeStore?.RequestRefresh();
|
||||||
campaign.CampaignUI?.CrewManagement?.RefreshPermissions();
|
campaign.CampaignUI?.HRManagerUI?.RefreshUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1554,7 +1554,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GameMain.GameSession.StartRound(levelData, mirrorLevel);
|
GameMain.GameSession.StartRound(levelData, mirrorLevel, startOutpost: campaign?.GetPredefinedStartOutpost());
|
||||||
}
|
}
|
||||||
isOutpost = levelData.Type == LevelData.LevelType.Outpost;
|
isOutpost = levelData.Type == LevelData.LevelType.Outpost;
|
||||||
}
|
}
|
||||||
@@ -1959,7 +1959,7 @@ namespace Barotrauma.Networking
|
|||||||
if (GameMain.GameSession?.GameMode is CampaignMode campaign)
|
if (GameMain.GameSession?.GameMode is CampaignMode campaign)
|
||||||
{
|
{
|
||||||
campaign.CampaignUI?.UpgradeStore?.RequestRefresh();
|
campaign.CampaignUI?.UpgradeStore?.RequestRefresh();
|
||||||
campaign.CampaignUI?.CrewManagement?.RefreshPermissions();
|
campaign.CampaignUI?.HRManagerUI?.RefreshUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public CampaignMode Campaign { get; }
|
public CampaignMode Campaign { get; }
|
||||||
|
|
||||||
public CrewManagement CrewManagement { get; set; }
|
public HRManagerUI HRManagerUI { get; set; }
|
||||||
|
|
||||||
public Store Store { get; private set; }
|
public Store Store { get; private set; }
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
var crewTab = new GUIFrame(new RectTransform(Vector2.One, container.RectTransform), color: Color.Black * 0.9f);
|
var crewTab = new GUIFrame(new RectTransform(Vector2.One, container.RectTransform), color: Color.Black * 0.9f);
|
||||||
tabs[(int)CampaignMode.InteractionType.Crew] = crewTab;
|
tabs[(int)CampaignMode.InteractionType.Crew] = crewTab;
|
||||||
CrewManagement = new CrewManagement(this, crewTab);
|
HRManagerUI = new HRManagerUI(this, crewTab);
|
||||||
|
|
||||||
// store tab -------------------------------------------------------------------------
|
// store tab -------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ namespace Barotrauma
|
|||||||
submarineSelection?.Update();
|
submarineSelection?.Update();
|
||||||
break;
|
break;
|
||||||
case CampaignMode.InteractionType.Crew:
|
case CampaignMode.InteractionType.Crew:
|
||||||
CrewManagement?.Update();
|
HRManagerUI?.Update();
|
||||||
break;
|
break;
|
||||||
case CampaignMode.InteractionType.Store:
|
case CampaignMode.InteractionType.Store:
|
||||||
Store?.Update(deltaTime);
|
Store?.Update(deltaTime);
|
||||||
@@ -598,8 +598,8 @@ namespace Barotrauma
|
|||||||
Store.SelectStore(npc);
|
Store.SelectStore(npc);
|
||||||
break;
|
break;
|
||||||
case CampaignMode.InteractionType.Crew:
|
case CampaignMode.InteractionType.Crew:
|
||||||
CrewManagement.UpdateCrew();
|
HRManagerUI.UpdateCrew();
|
||||||
CrewManagement.UpdateHireables();
|
HRManagerUI.UpdateHireables();
|
||||||
break;
|
break;
|
||||||
case CampaignMode.InteractionType.PurchaseSub:
|
case CampaignMode.InteractionType.PurchaseSub:
|
||||||
submarineSelection ??= new SubmarineSelection(false, () => Campaign.ShowCampaignUI = false, tabs[(int)CampaignMode.InteractionType.PurchaseSub].RectTransform);
|
submarineSelection ??= new SubmarineSelection(false, () => Campaign.ShowCampaignUI = false, tabs[(int)CampaignMode.InteractionType.PurchaseSub].RectTransform);
|
||||||
|
|||||||
@@ -1116,6 +1116,36 @@ namespace Barotrauma
|
|||||||
AssignComponentToServerSetting(skillLossImmediateRespawnSlider, nameof(ServerSettings.SkillLossPercentageOnImmediateRespawn));
|
AssignComponentToServerSetting(skillLossImmediateRespawnSlider, nameof(ServerSettings.SkillLossPercentageOnImmediateRespawn));
|
||||||
skillLossImmediateRespawnSlider.OnMoved(skillLossImmediateRespawnSlider, skillLossImmediateRespawnSlider.BarScroll);
|
skillLossImmediateRespawnSlider.OnMoved(skillLossImmediateRespawnSlider, skillLossImmediateRespawnSlider.BarScroll);
|
||||||
|
|
||||||
|
var newCharacterCostSliderElement = CreateLabeledSlider(settingsContent,
|
||||||
|
"ServerSettings.ReplaceCostPercentage", "", "ServerSettings.ReplaceCostPercentage.tooltip",
|
||||||
|
out var newCharacterCostSlider, out var newCharacterCostSliderLabel,
|
||||||
|
range: new Vector2(0, 200), step: 10f);
|
||||||
|
newCharacterCostSlider.StepValue = 10f;
|
||||||
|
newCharacterCostSlider.OnMoved = (GUIScrollBar scrollBar, float _) =>
|
||||||
|
{
|
||||||
|
GUITextBlock textBlock = scrollBar.UserData as GUITextBlock;
|
||||||
|
int currentMultiplier = (int)Math.Round(scrollBar.BarScrollValue);
|
||||||
|
if (currentMultiplier < 1)
|
||||||
|
{
|
||||||
|
textBlock.Text = TextManager.Get("ServerSettings.ReplaceCostPercentage.Free");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textBlock.Text = TextManager.GetWithVariable("percentageformat", "[value]", currentMultiplier.ToString());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
newCharacterCostSlider.OnReleased = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
GameMain.Client?.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Properties);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
clientDisabledElements.AddRange(newCharacterCostSliderElement.GetAllChildren());
|
||||||
|
permadeathEnabledRespawnSettings.AddRange(newCharacterCostSliderElement.GetAllChildren());
|
||||||
|
ironmanDisabledRespawnSettings.AddRange(newCharacterCostSliderElement.GetAllChildren());
|
||||||
|
AssignComponentToServerSetting(newCharacterCostSlider, nameof(ServerSettings.ReplaceCostPercentage));
|
||||||
|
newCharacterCostSlider.OnMoved(newCharacterCostSlider, newCharacterCostSlider.BarScroll); // initialize
|
||||||
|
|
||||||
var allowBotTakeoverTickbox = new GUITickBox(new RectTransform(Vector2.One, settingsContent.RectTransform), TextManager.Get("AllowBotTakeover"))
|
var allowBotTakeoverTickbox = new GUITickBox(new RectTransform(Vector2.One, settingsContent.RectTransform), TextManager.Get("AllowBotTakeover"))
|
||||||
{
|
{
|
||||||
ToolTip = TextManager.Get("AllowBotTakeover.Tooltip"),
|
ToolTip = TextManager.Get("AllowBotTakeover.Tooltip"),
|
||||||
@@ -1834,7 +1864,8 @@ namespace Barotrauma
|
|||||||
OverflowClip = true
|
OverflowClip = true
|
||||||
};
|
};
|
||||||
|
|
||||||
if (PermanentlyDead)
|
if (!allowEditing ||
|
||||||
|
(PermanentlyDead && !characterInfo.RenamingEnabled))
|
||||||
{
|
{
|
||||||
CharacterNameBox.Readonly = true;
|
CharacterNameBox.Readonly = true;
|
||||||
CharacterNameBox.Enabled = false;
|
CharacterNameBox.Enabled = false;
|
||||||
|
|||||||
@@ -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>1.5.8.0</Version>
|
<Version>1.5.9.1</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2024</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2024</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>1.5.8.0</Version>
|
<Version>1.5.9.1</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2024</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2024</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>1.5.8.0</Version>
|
<Version>1.5.9.1</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2024</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2024</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>1.5.8.0</Version>
|
<Version>1.5.9.1</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2023</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2023</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>1.5.8.0</Version>
|
<Version>1.5.9.1</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2023</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2023</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ namespace Barotrauma
|
|||||||
msg.WriteUInt16(ID);
|
msg.WriteUInt16(ID);
|
||||||
msg.WriteString(Name);
|
msg.WriteString(Name);
|
||||||
msg.WriteString(OriginalName);
|
msg.WriteString(OriginalName);
|
||||||
|
msg.WriteBoolean(RenamingEnabled);
|
||||||
msg.WriteByte((byte)Head.Preset.TagSet.Count);
|
msg.WriteByte((byte)Head.Preset.TagSet.Count);
|
||||||
foreach (Identifier tag in Head.Preset.TagSet)
|
foreach (Identifier tag in Head.Preset.TagSet)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -463,6 +463,7 @@ namespace Barotrauma
|
|||||||
Client owner = controlEventData.Owner;
|
Client owner = controlEventData.Owner;
|
||||||
msg.WriteBoolean(owner == c && owner.Character == this);
|
msg.WriteBoolean(owner == c && owner.Character == this);
|
||||||
msg.WriteByte(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.SessionId : (byte)0);
|
msg.WriteByte(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.SessionId : (byte)0);
|
||||||
|
msg.WriteBoolean(info is { RenamingEnabled: true });
|
||||||
break;
|
break;
|
||||||
case CharacterStatusEventData statusEventData:
|
case CharacterStatusEventData statusEventData:
|
||||||
WriteStatus(msg, statusEventData.ForceAfflictionData);
|
WriteStatus(msg, statusEventData.ForceAfflictionData);
|
||||||
|
|||||||
+33
-10
@@ -1231,6 +1231,10 @@ namespace Barotrauma
|
|||||||
renamedIdentifier = msg.ReadUInt16();
|
renamedIdentifier = msg.ReadUInt16();
|
||||||
newName = msg.ReadString();
|
newName = msg.ReadString();
|
||||||
existingCrewMember = msg.ReadBoolean();
|
existingCrewMember = msg.ReadBoolean();
|
||||||
|
if (!GameMain.Server.IsNameValid(sender, newName))
|
||||||
|
{
|
||||||
|
renameCharacter = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fireCharacter = msg.ReadBoolean();
|
bool fireCharacter = msg.ReadBoolean();
|
||||||
@@ -1239,10 +1243,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
Location location = map?.CurrentLocation;
|
Location location = map?.CurrentLocation;
|
||||||
CharacterInfo firedCharacter = null;
|
CharacterInfo firedCharacter = null;
|
||||||
|
(ushort id, string newName) appliedRename = (Entity.NullEntityID, string.Empty);
|
||||||
|
|
||||||
if (location != null && AllowedToManageCampaign(sender, ClientPermissions.ManageHires))
|
if (location != null)
|
||||||
{
|
{
|
||||||
if (fireCharacter)
|
if (fireCharacter && AllowedToManageCampaign(sender, ClientPermissions.ManageHires))
|
||||||
{
|
{
|
||||||
firedCharacter = CrewManager.GetCharacterInfos().FirstOrDefault(info => info.ID == firedIdentifier);
|
firedCharacter = CrewManager.GetCharacterInfos().FirstOrDefault(info => info.ID == firedIdentifier);
|
||||||
if (firedCharacter != null && (firedCharacter.Character?.IsBot ?? true))
|
if (firedCharacter != null && (firedCharacter.Character?.IsBot ?? true))
|
||||||
@@ -1258,29 +1263,45 @@ namespace Barotrauma
|
|||||||
if (renameCharacter)
|
if (renameCharacter)
|
||||||
{
|
{
|
||||||
CharacterInfo characterInfo = null;
|
CharacterInfo characterInfo = null;
|
||||||
if (existingCrewMember && CrewManager != null)
|
if (AllowedToManageCampaign(sender, ClientPermissions.ManageHires))
|
||||||
{
|
{
|
||||||
characterInfo = CrewManager.GetCharacterInfos().FirstOrDefault(info => info.ID == renamedIdentifier);
|
if (existingCrewMember && CrewManager != null)
|
||||||
|
{
|
||||||
|
characterInfo = CrewManager.GetCharacterInfos().FirstOrDefault(info => info.ID == renamedIdentifier);
|
||||||
|
}
|
||||||
|
else if (!existingCrewMember && location.HireManager != null)
|
||||||
|
{
|
||||||
|
characterInfo = location.HireManager.AvailableCharacters.FirstOrDefault(info => info.ID == renamedIdentifier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(!existingCrewMember && location.HireManager != null)
|
if (characterInfo == null && renamedIdentifier == sender.CharacterInfo?.ID)
|
||||||
{
|
{
|
||||||
characterInfo = location.HireManager.AvailableCharacters.FirstOrDefault(info => info.ID == renamedIdentifier);
|
characterInfo = sender.CharacterInfo;
|
||||||
}
|
}
|
||||||
|
if (characterInfo != null &&
|
||||||
if (characterInfo != null && (characterInfo.Character?.IsBot ?? true))
|
(characterInfo.Character == null || characterInfo.Character is { IsBot: true } || (characterInfo.RenamingEnabled && characterInfo == sender.CharacterInfo)))
|
||||||
{
|
{
|
||||||
|
GameServer.Log($"{sender.Name} renamed the character \"{characterInfo.Name}\" as \"{newName}\".", ServerLog.MessageType.ServerMessage);
|
||||||
if (existingCrewMember)
|
if (existingCrewMember)
|
||||||
{
|
{
|
||||||
CrewManager.RenameCharacter(characterInfo, newName);
|
CrewManager.RenameCharacter(characterInfo, newName);
|
||||||
|
if (characterInfo == sender.CharacterInfo)
|
||||||
|
{
|
||||||
|
//renaming is only allowed once
|
||||||
|
characterInfo.RenamingEnabled = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
location.HireManager.RenameCharacter(characterInfo, newName);
|
location.HireManager.RenameCharacter(characterInfo, newName);
|
||||||
}
|
}
|
||||||
|
appliedRename = (characterInfo.ID, newName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Tried to rename an invalid character ({renamedIdentifier})");
|
string errorMsg = $"Tried to rename an invalid character ({renamedIdentifier}, {characterInfo?.Name ?? "null"})";
|
||||||
|
DebugConsole.ThrowError(errorMsg);
|
||||||
|
GameMain.Server?.SendConsoleMessage(errorMsg, sender, Color.Red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1328,7 +1349,7 @@ namespace Barotrauma
|
|||||||
// bounce back
|
// bounce back
|
||||||
if (renameCharacter && existingCrewMember)
|
if (renameCharacter && existingCrewMember)
|
||||||
{
|
{
|
||||||
SendCrewState((renamedIdentifier, newName), firedCharacter);
|
SendCrewState(appliedRename, firedCharacter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1406,6 +1427,8 @@ namespace Barotrauma
|
|||||||
//(can happen e.g. if someone starts a vote to buy something and then disconnects)
|
//(can happen e.g. if someone starts a vote to buy something and then disconnects)
|
||||||
if (client != null && !GameMain.Server.ConnectedClients.Contains(client)) { return false; }
|
if (client != null && !GameMain.Server.ConnectedClients.Contains(client)) { return false; }
|
||||||
|
|
||||||
|
if (price == 0) { return true; }
|
||||||
|
|
||||||
Wallet wallet = GetWallet(client);
|
Wallet wallet = GetWallet(client);
|
||||||
if (!AllowedToManageWallets(client))
|
if (!AllowedToManageWallets(client))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -313,13 +313,22 @@ namespace Barotrauma.Networking
|
|||||||
GameMain.Server.SendConsoleMessage($"Permadeath: Could not take over the target character because it is not a bot.", this, Color.Red);
|
GameMain.Server.SendConsoleMessage($"Permadeath: Could not take over the target character because it is not a bot.", this, Color.Red);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that the old permanently killed character will be replaced, we can fully discard it
|
if (botCharacter.Info != null)
|
||||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign)
|
|
||||||
{
|
{
|
||||||
mpCampaign.DiscardClientCharacterData(this);
|
botCharacter.Info.RenamingEnabled = true; // Grant one opportunity to rename a taken over bot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that the old permanently killed character will be replaced, we can fully discard it
|
||||||
|
var mpCampaign = GameMain.GameSession?.Campaign as MultiPlayerCampaign;
|
||||||
|
mpCampaign?.DiscardClientCharacterData(this);
|
||||||
GameMain.Server.SetClientCharacter(this, botCharacter);
|
GameMain.Server.SetClientCharacter(this, botCharacter);
|
||||||
|
if (mpCampaign?.SetClientCharacterData(this) is CharacterCampaignData characterData)
|
||||||
|
{
|
||||||
|
//the bot has spawned, but the new CharacterCampaignData technically hasn't, because we just created it
|
||||||
|
characterData.HasSpawned = true;
|
||||||
|
}
|
||||||
|
|
||||||
SpectateOnly = false;
|
SpectateOnly = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1406,16 +1406,26 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
if (campaign.CurrentLocation.GetHireableCharacters().FirstOrDefault(c => c.ID == botId) is CharacterInfo hireableCharacter)
|
if (campaign.CurrentLocation.GetHireableCharacters().FirstOrDefault(c => c.ID == botId) is CharacterInfo hireableCharacter)
|
||||||
{
|
{
|
||||||
if (campaign.TryHireCharacter(campaign.CurrentLocation, hireableCharacter, takeMoney: true, sender))
|
if (ServerSettings.ReplaceCostPercentage <= 0 ||
|
||||||
|
CampaignMode.AllowedToManageCampaign(sender, ClientPermissions.ManageMoney) ||
|
||||||
|
CampaignMode.AllowedToManageCampaign(sender, ClientPermissions.ManageHires))
|
||||||
{
|
{
|
||||||
campaign.CurrentLocation.RemoveHireableCharacter(hireableCharacter);
|
if (campaign.TryHireCharacter(campaign.CurrentLocation, hireableCharacter, takeMoney: true, sender, buyingNewCharacter: true))
|
||||||
SpawnAndTakeOverBot(campaign, hireableCharacter, sender);
|
{
|
||||||
campaign.SendCrewState(createNotification: false);
|
campaign.CurrentLocation.RemoveHireableCharacter(hireableCharacter);
|
||||||
|
SpawnAndTakeOverBot(campaign, hireableCharacter, sender);
|
||||||
|
campaign.SendCrewState(createNotification: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SendConsoleMessage($"Could not hire the bot {hireableCharacter.Name}.", sender, Color.Red);
|
||||||
|
DebugConsole.ThrowError($"Client {sender.Name} failed to hire the bot {hireableCharacter.Name}.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SendConsoleMessage($"Could not hire the bot {hireableCharacter.Name}.", sender, Color.Red);
|
SendConsoleMessage($"Could not hire the bot {hireableCharacter.Name}. No permission to manage money or hires.", sender, Color.Red);
|
||||||
DebugConsole.ThrowError($"Client {sender.Name} failed to hire the bot {hireableCharacter.Name}.");
|
DebugConsole.ThrowError($"Client {sender.Name} failed to hire the bot {hireableCharacter.Name}. No permission to manage money or hires.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1460,6 +1470,7 @@ namespace Barotrauma.Networking
|
|||||||
DebugConsole.ThrowError("SpawnAndTakeOverBot: newCharacter is null somehow");
|
DebugConsole.ThrowError("SpawnAndTakeOverBot: newCharacter is null somehow");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// No longer show the hired character in the HR list of current hires
|
||||||
campaign.CrewManager.RemoveCharacterInfo(botInfo);
|
campaign.CrewManager.RemoveCharacterInfo(botInfo);
|
||||||
newCharacter.TeamID = CharacterTeamType.Team1;
|
newCharacter.TeamID = CharacterTeamType.Team1;
|
||||||
campaign.CrewManager.InitializeCharacter(newCharacter, mainSubSpawnpoint, spawnWaypoint);
|
campaign.CrewManager.InitializeCharacter(newCharacter, mainSubSpawnpoint, spawnWaypoint);
|
||||||
@@ -2428,7 +2439,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
|
|
||||||
SendStartMessage(roundStartSeed, campaign.NextLevel.Seed, GameMain.GameSession, connectedClients, includesFinalize: false);
|
SendStartMessage(roundStartSeed, campaign.NextLevel.Seed, GameMain.GameSession, connectedClients, includesFinalize: false);
|
||||||
GameMain.GameSession.StartRound(campaign.NextLevel, mirrorLevel: campaign.MirrorLevel);
|
GameMain.GameSession.StartRound(campaign.NextLevel, startOutpost: campaign.GetPredefinedStartOutpost(), mirrorLevel: campaign.MirrorLevel);
|
||||||
SubmarineSwitchLoad = false;
|
SubmarineSwitchLoad = false;
|
||||||
campaign.AssignClientCharacterInfos(connectedClients);
|
campaign.AssignClientCharacterInfos(connectedClients);
|
||||||
Log("Game mode: " + selectedMode.Name.Value, ServerLog.MessageType.ServerMessage);
|
Log("Game mode: " + selectedMode.Name.Value, ServerLog.MessageType.ServerMessage);
|
||||||
@@ -3042,7 +3053,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsNameValid(Client c, string newName)
|
public bool IsNameValid(Client c, string newName)
|
||||||
{
|
{
|
||||||
newName = Client.SanitizeName(newName);
|
newName = Client.SanitizeName(newName);
|
||||||
|
|
||||||
@@ -3066,13 +3077,20 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Client nameTaken = ConnectedClients.Find(c2 => c != c2 && Homoglyphs.Compare(c2.Name.ToLower(), newName.ToLower()));
|
Client nameTakenByClient = ConnectedClients.Find(c2 => c != c2 && Homoglyphs.Compare(c2.Name.ToLower(), newName.ToLower()));
|
||||||
if (nameTaken != null)
|
if (nameTakenByClient != null)
|
||||||
{
|
{
|
||||||
SendDirectChatMessage($"ServerMessage.NameChangeFailedClientTooSimilar~[newname]={newName}~[takenname]={nameTaken.Name}", c, ChatMessageType.ServerMessageBox);
|
SendDirectChatMessage($"ServerMessage.NameChangeFailedClientTooSimilar~[newname]={newName}~[takenname]={nameTakenByClient.Name}", c, ChatMessageType.ServerMessageBox);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Character nameTakenByCharacter =
|
||||||
|
GameSession.GetSessionCrewCharacters(CharacterType.Both).FirstOrDefault(c2 => c2 != c.Character && Homoglyphs.Compare(c2.Name.ToLower(), newName.ToLower()));
|
||||||
|
if (nameTakenByCharacter != null)
|
||||||
|
{
|
||||||
|
SendDirectChatMessage($"ServerMessage.NameChangeFailedClientTooSimilar~[newname]={newName}~[takenname]={nameTakenByCharacter.Name}", c, ChatMessageType.ServerMessageBox);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3826,6 +3844,7 @@ namespace Barotrauma.Networking
|
|||||||
newCharacter.SetOwnerClient(client);
|
newCharacter.SetOwnerClient(client);
|
||||||
newCharacter.Enabled = true;
|
newCharacter.Enabled = true;
|
||||||
client.Character = newCharacter;
|
client.Character = newCharacter;
|
||||||
|
client.CharacterInfo = newCharacter.Info;
|
||||||
CreateEntityEvent(newCharacter, new Character.ControlEventData(client));
|
CreateEntityEvent(newCharacter, new Character.ControlEventData(client));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>1.5.8.0</Version>
|
<Version>1.5.9.1</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2023</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2023</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
+38
-23
@@ -1,4 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
using FarseerPhysics;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -117,24 +119,52 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (inspectTimer > 0.0f)
|
if (inspectTimer > 0.0f)
|
||||||
{
|
{
|
||||||
character.SelectCharacter(Target);
|
Vector2 diff = Target.WorldPosition - character.WorldPosition;
|
||||||
|
float dist = diff.Length();
|
||||||
|
float maxDist = ConvertUnits.ToDisplayUnits(HumanoidAnimController.BreakFromGrabDistance);
|
||||||
|
if (dist > maxDist)
|
||||||
|
{
|
||||||
|
if (dist > maxDist * 2 || !character.CanSeeTarget(Target, seeThroughWindows: false))
|
||||||
|
{
|
||||||
|
//too far to reach by small manual movement, need to switch back to the earlier state
|
||||||
|
currentState = State.GotoTarget;
|
||||||
|
}
|
||||||
|
//move closer horizontally if the horizontal distance is the issue
|
||||||
|
else if (Math.Abs(diff.X) > Math.Abs(diff.Y) * 2.0f)
|
||||||
|
{
|
||||||
|
character.AIController.SteeringManager.SteeringManual(deltaTime, new Vector2(MathF.Sign(Target.WorldPosition.X - character.WorldPosition.X), 0.0f));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
character.AIController.SteeringManager.Reset();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dist < maxDist * 0.5f) { character.AIController.SteeringManager.Reset(); }
|
||||||
|
character.SelectCharacter(Target);
|
||||||
|
}
|
||||||
|
|
||||||
inspectTimer -= deltaTime;
|
inspectTimer -= deltaTime;
|
||||||
if (inspectTimer < InspectTime - 1)
|
if (inspectTimer < InspectTime - 1)
|
||||||
{
|
{
|
||||||
if (Target.AnimController.IsMovingFast)
|
if (Math.Abs(Target.AnimController.TargetMovement.X) > 1.0f)
|
||||||
{
|
{
|
||||||
ArrestFleeing();
|
// If the target moves, tell to hold still
|
||||||
}
|
|
||||||
else if (Math.Abs(Target.AnimController.TargetMovement.X) > 1.0f)
|
|
||||||
{
|
|
||||||
// If the target moves, reset the inspect timer and tell to hold still
|
|
||||||
character.Speak(TextManager.Get("dialogcheckstolenitems.holdstill").Value, identifier: "holdstill".ToIdentifier(), minDurationBetweenSimilar: 3f);
|
character.Speak(TextManager.Get("dialogcheckstolenitems.holdstill").Value, identifier: "holdstill".ToIdentifier(), minDurationBetweenSimilar: 3f);
|
||||||
inspectTimer = InspectTime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (character.SelectedCharacter != Target)
|
||||||
|
{
|
||||||
|
//target not selected -> must've escaped
|
||||||
|
Abandon = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (stolenItems.Any() &&
|
if (stolenItems.Any() &&
|
||||||
Rand.Range(0.0f, 1.0f, Rand.RandSync.Unsynced) < FindStolenItemsProbability)
|
Rand.Range(0.0f, 1.0f, Rand.RandSync.Unsynced) < FindStolenItemsProbability)
|
||||||
{
|
{
|
||||||
@@ -155,13 +185,6 @@ namespace Barotrauma
|
|||||||
if (warnTimer > 0.0f)
|
if (warnTimer > 0.0f)
|
||||||
{
|
{
|
||||||
warnTimer -= deltaTime;
|
warnTimer -= deltaTime;
|
||||||
if (warnTimer < currentWarnDelay - 1)
|
|
||||||
{
|
|
||||||
if (Target.AnimController.IsMovingFast)
|
|
||||||
{
|
|
||||||
ArrestFleeing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var stolenItemsOnCharacter = stolenItems.Where(it => it.GetRootInventoryOwner() == Target);
|
var stolenItemsOnCharacter = stolenItems.Where(it => it.GetRootInventoryOwner() == Target);
|
||||||
@@ -189,14 +212,6 @@ namespace Barotrauma
|
|||||||
IsCompleted = true;
|
IsCompleted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ArrestFleeing()
|
|
||||||
{
|
|
||||||
character.Speak(TextManager.Get("dialogcheckstolenitems.arrest").Value);
|
|
||||||
currentState = State.Done;
|
|
||||||
IsCompleted = true;
|
|
||||||
Arrest(abortWhenItemsDropped: false, allowHoldFire: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Arrest(bool abortWhenItemsDropped, bool allowHoldFire)
|
private void Arrest(bool abortWhenItemsDropped, bool allowHoldFire)
|
||||||
{
|
{
|
||||||
bool isCriminal = Target.IsCriminal;
|
bool isCriminal = Target.IsCriminal;
|
||||||
|
|||||||
+2
@@ -12,6 +12,8 @@ namespace Barotrauma
|
|||||||
protected override float TargetUpdateTimeMultiplier => 0.2f;
|
protected override float TargetUpdateTimeMultiplier => 0.2f;
|
||||||
public bool TargetCharactersInOtherSubs { get; init; }
|
public bool TargetCharactersInOtherSubs { get; init; }
|
||||||
|
|
||||||
|
protected override bool AllowInAnySub => TargetCharactersInOtherSubs;
|
||||||
|
|
||||||
public AIObjectiveFightIntruders(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1)
|
public AIObjectiveFightIntruders(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1)
|
||||||
: base(character, objectiveManager, priorityModifier) { }
|
: base(character, objectiveManager, priorityModifier) { }
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -21,6 +21,8 @@ namespace Barotrauma
|
|||||||
private const float MaxSpeedOnStairs = 1.7f;
|
private const float MaxSpeedOnStairs = 1.7f;
|
||||||
private const float SteepSlopePushMagnitude = MaxSpeedOnStairs;
|
private const float SteepSlopePushMagnitude = MaxSpeedOnStairs;
|
||||||
|
|
||||||
|
public const float BreakFromGrabDistance = 1.4f;
|
||||||
|
|
||||||
public override RagdollParams RagdollParams
|
public override RagdollParams RagdollParams
|
||||||
{
|
{
|
||||||
get { return HumanRagdollParams; }
|
get { return HumanRagdollParams; }
|
||||||
@@ -1844,7 +1846,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
float dist = ConvertUnits.ToSimUnits(Vector2.Distance(target.WorldPosition, WorldPosition));
|
float dist = ConvertUnits.ToSimUnits(Vector2.Distance(target.WorldPosition, WorldPosition));
|
||||||
//let the target break free if it's moving away and gets far enough
|
//let the target break free if it's moving away and gets far enough
|
||||||
if ((GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) && dist > 1.4f && target.AllowInput &&
|
if ((GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) && dist > BreakFromGrabDistance && target.AllowInput &&
|
||||||
Vector2.Dot(target.WorldPosition - WorldPosition, target.AnimController.TargetMovement) > 0)
|
Vector2.Dot(target.WorldPosition - WorldPosition, target.AnimController.TargetMovement) > 0)
|
||||||
{
|
{
|
||||||
character.DeselectCharacter();
|
character.DeselectCharacter();
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ namespace Barotrauma
|
|||||||
public XElement OrderData;
|
public XElement OrderData;
|
||||||
|
|
||||||
public bool PermanentlyDead;
|
public bool PermanentlyDead;
|
||||||
|
public bool RenamingEnabled = false;
|
||||||
|
|
||||||
private static ushort idCounter = 1;
|
private static ushort idCounter = 1;
|
||||||
private const string disguiseName = "???";
|
private const string disguiseName = "???";
|
||||||
@@ -802,6 +803,7 @@ namespace Barotrauma
|
|||||||
LoadTagsBackwardsCompatibility(infoElement, tags);
|
LoadTagsBackwardsCompatibility(infoElement, tags);
|
||||||
SpeciesName = infoElement.GetAttributeIdentifier("speciesname", "");
|
SpeciesName = infoElement.GetAttributeIdentifier("speciesname", "");
|
||||||
PermanentlyDead = infoElement.GetAttributeBool("permanentlydead", false);
|
PermanentlyDead = infoElement.GetAttributeBool("permanentlydead", false);
|
||||||
|
RenamingEnabled = infoElement.GetAttributeBool("renamingenabled", false);
|
||||||
ContentXElement element;
|
ContentXElement element;
|
||||||
if (!SpeciesName.IsEmpty)
|
if (!SpeciesName.IsEmpty)
|
||||||
{
|
{
|
||||||
@@ -1499,7 +1501,8 @@ namespace Barotrauma
|
|||||||
new XAttribute("startitemsgiven", StartItemsGiven),
|
new XAttribute("startitemsgiven", StartItemsGiven),
|
||||||
new XAttribute("personality", PersonalityTrait?.Identifier ?? Identifier.Empty),
|
new XAttribute("personality", PersonalityTrait?.Identifier ?? Identifier.Empty),
|
||||||
new XAttribute("lastrewarddistribution", LastRewardDistribution.Match(some: value => value, none: () => -1).ToString()),
|
new XAttribute("lastrewarddistribution", LastRewardDistribution.Match(some: value => value, none: () => -1).ToString()),
|
||||||
new XAttribute("permanentlydead", PermanentlyDead)
|
new XAttribute("permanentlydead", PermanentlyDead),
|
||||||
|
new XAttribute("renamingenabled", RenamingEnabled)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (HumanPrefabIds != default)
|
if (HumanPrefabIds != default)
|
||||||
|
|||||||
@@ -7,9 +7,14 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using Barotrauma.Networking;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Responsible for keeping track of the characters in the player crew, saving and loading their orders, managing the crew list UI
|
||||||
|
/// </summary>
|
||||||
partial class CrewManager
|
partial class CrewManager
|
||||||
{
|
{
|
||||||
const float ConversationIntervalMin = 100.0f;
|
const float ConversationIntervalMin = 100.0f;
|
||||||
@@ -27,7 +32,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
return characters;
|
return characters;
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Note: this only returns AI characters' infos in multiplayer. The infos are used to manage hiring/firing/renaming, which only applies to AI characters.
|
||||||
|
/// Use <see cref="GetSessionCrewCharacters"/> to get all the characters regardless if they're player or AI controlled.
|
||||||
|
/// </summary>
|
||||||
public IEnumerable<CharacterInfo> GetCharacterInfos()
|
public IEnumerable<CharacterInfo> GetCharacterInfos()
|
||||||
{
|
{
|
||||||
return characterInfos;
|
return characterInfos;
|
||||||
@@ -387,15 +395,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void RenameCharacter(CharacterInfo characterInfo, string newName)
|
public void RenameCharacter(CharacterInfo characterInfo, string newName)
|
||||||
{
|
{
|
||||||
int identifier = characterInfo.GetIdentifierUsingOriginalName();
|
characterInfo.Rename(newName);
|
||||||
var match = characterInfos.FirstOrDefault(ci => ci.GetIdentifierUsingOriginalName() == identifier);
|
RenameCharacterProjSpecific(characterInfo);
|
||||||
if (match == null)
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError($"Tried to rename an invalid crew member ({identifier})");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
match.Rename(newName);
|
|
||||||
RenameCharacterProjSpecific(match);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void RenameCharacterProjSpecific(CharacterInfo characterInfo);
|
partial void RenameCharacterProjSpecific(CharacterInfo characterInfo);
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public virtual bool TryPurchase(Client client, int price)
|
public virtual bool TryPurchase(Client client, int price)
|
||||||
{
|
{
|
||||||
return GetWallet(client).TryDeduct(price);
|
return price == 0 || GetWallet(client).TryDeduct(price);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual int GetBalance(Client client = null)
|
public virtual int GetBalance(Client client = null)
|
||||||
@@ -250,6 +250,19 @@ namespace Barotrauma
|
|||||||
(sub.AtEndExit != leavingSub.AtEndExit || sub.AtStartExit != leavingSub.AtStartExit));
|
(sub.AtEndExit != leavingSub.AtEndExit || sub.AtStartExit != leavingSub.AtStartExit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SubmarineInfo GetPredefinedStartOutpost()
|
||||||
|
{
|
||||||
|
if (Map?.CurrentLocation?.Type?.GetForcedOutpostGenerationParams() is OutpostGenerationParams parameters &&
|
||||||
|
!parameters.OutpostFilePath.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return new SubmarineInfo(parameters.OutpostFilePath.Value)
|
||||||
|
{
|
||||||
|
OutpostGenerationParams = parameters
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Start()
|
public override void Start()
|
||||||
{
|
{
|
||||||
base.Start();
|
base.Start();
|
||||||
@@ -1044,7 +1057,7 @@ namespace Barotrauma
|
|||||||
return ToolBox.SelectWeightedRandom(factionsList, weights, random);
|
return ToolBox.SelectWeightedRandom(factionsList, weights, random);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryHireCharacter(Location location, CharacterInfo characterInfo, bool takeMoney = true, Client client = null)
|
public bool TryHireCharacter(Location location, CharacterInfo characterInfo, bool takeMoney = true, Client client = null, bool buyingNewCharacter = false)
|
||||||
{
|
{
|
||||||
if (characterInfo == null) { return false; }
|
if (characterInfo == null) { return false; }
|
||||||
if (characterInfo.MinReputationToHire.factionId != Identifier.Empty)
|
if (characterInfo.MinReputationToHire.factionId != Identifier.Empty)
|
||||||
@@ -1054,7 +1067,8 @@ namespace Barotrauma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (takeMoney && !TryPurchase(client, HireManager.GetSalaryFor(characterInfo))) { return false; }
|
var price = buyingNewCharacter ? NewCharacterCost(characterInfo) : HireManager.GetSalaryFor(characterInfo);
|
||||||
|
if (takeMoney && !TryPurchase(client, price)) { return false; }
|
||||||
|
|
||||||
characterInfo.IsNewHire = true;
|
characterInfo.IsNewHire = true;
|
||||||
characterInfo.Title = null;
|
characterInfo.Title = null;
|
||||||
@@ -1063,6 +1077,17 @@ namespace Barotrauma
|
|||||||
GameAnalyticsManager.AddMoneySpentEvent(characterInfo.Salary, GameAnalyticsManager.MoneySink.Crew, characterInfo.Job?.Prefab.Identifier.Value ?? "unknown");
|
GameAnalyticsManager.AddMoneySpentEvent(characterInfo.Salary, GameAnalyticsManager.MoneySink.Crew, characterInfo.Job?.Prefab.Identifier.Value ?? "unknown");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int NewCharacterCost(CharacterInfo characterInfo)
|
||||||
|
{
|
||||||
|
float characterCostPercentage = GameMain.NetworkMember?.ServerSettings.ReplaceCostPercentage ?? 100f;
|
||||||
|
return (int)MathF.Round(HireManager.GetSalaryFor(characterInfo) * (characterCostPercentage/100f));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanAffordNewCharacter(CharacterInfo characterInfo)
|
||||||
|
{
|
||||||
|
return CanAfford(NewCharacterCost(characterInfo));
|
||||||
|
}
|
||||||
|
|
||||||
private void NPCInteract(Character npc, Character interactor)
|
private void NPCInteract(Character npc, Character interactor)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -574,6 +574,12 @@ namespace Barotrauma
|
|||||||
GameAnalyticsManager.AddDesignEvent(eventId + (Level.Loaded?.LevelData?.Biome?.Identifier.Value ?? "none") + "Discovered:Playtime", campaignMode.TotalPlayTime);
|
GameAnalyticsManager.AddDesignEvent(eventId + (Level.Loaded?.LevelData?.Biome?.Identifier.Value ?? "none") + "Discovered:Playtime", campaignMode.TotalPlayTime);
|
||||||
GameAnalyticsManager.AddDesignEvent(eventId + (Level.Loaded?.LevelData?.Biome?.Identifier.Value ?? "none") + "Discovered:PassedLevels", campaignMode.TotalPassedLevels);
|
GameAnalyticsManager.AddDesignEvent(eventId + (Level.Loaded?.LevelData?.Biome?.Identifier.Value ?? "none") + "Discovered:PassedLevels", campaignMode.TotalPassedLevels);
|
||||||
}
|
}
|
||||||
|
if (GameMain.NetworkMember?.ServerSettings is { } serverSettings)
|
||||||
|
{
|
||||||
|
GameAnalyticsManager.AddDesignEvent("ServerSettings:RespawnMode:" + serverSettings.RespawnMode);
|
||||||
|
GameAnalyticsManager.AddDesignEvent("ServerSettings:IronmanMode:" + serverSettings.IronmanMode);
|
||||||
|
GameAnalyticsManager.AddDesignEvent("ServerSettings:AllowBotTakeoverOnPermadeath:" + serverSettings.AllowBotTakeoverOnPermadeath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|||||||
@@ -479,6 +479,16 @@ namespace Barotrauma.Networking
|
|||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serialize(100f, IsPropertySaveable.Yes)]
|
||||||
|
/// <summary>
|
||||||
|
/// Percentage modifier for the cost of hiring a new character to replace a permanently killed one.
|
||||||
|
/// </summary>
|
||||||
|
public float ReplaceCostPercentage
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
[Serialize(true, IsPropertySaveable.Yes)]
|
[Serialize(true, IsPropertySaveable.Yes)]
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -651,6 +661,8 @@ namespace Barotrauma.Networking
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (respawnMode == value) { return; }
|
if (respawnMode == value) { return; }
|
||||||
|
//can't change this when a round is running (but clients can, if the server says so, e.g. when a client joins and needs to know what it's set to despite a round being running)
|
||||||
|
if (GameMain.NetworkMember is { GameStarted: true, IsServer: true }) { return; }
|
||||||
respawnMode = value;
|
respawnMode = value;
|
||||||
ServerDetailsChanged = true;
|
ServerDetailsChanged = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,17 @@
|
|||||||
-------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
v1.5.9.1
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
- Fixed outpost security being way too eager to arrest characters who attempt to escape a security inspection, to the point that getting inspected while running past a guard would immediately make them arrest you.
|
||||||
|
- Fixed some thalamus items being hidden for no reason in some wrecks.
|
||||||
|
- Fixed "assault enemy" order not working in abandoned/enemy outposts.
|
||||||
|
- Added a configurable multiplier for the cost of hiring a new character to replace a permanently killed one. Makes it possible to host permadeath servers without having to assign hiring or money permissions to clients.
|
||||||
|
- Players are allowed to rename the character they take over in the permadeath mode.
|
||||||
|
|
||||||
|
Modding:
|
||||||
|
- Fixed forceOutpostGenerationParamsIdentifier (which can be used to force specific outpost generation params to be used in a location type) only working in single player.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
v1.5.8.0
|
v1.5.8.0
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user