Unstable 1.8.4.0

This commit is contained in:
Markus Isberg
2025-03-12 12:56:27 +00:00
parent a4c3e868e4
commit a4a3427e4e
627 changed files with 29860 additions and 10018 deletions
@@ -301,6 +301,25 @@ namespace Barotrauma
public bool PermanentlyDead;
public bool RenamingEnabled = false;
private BotStatus botStatus = BotStatus.ActiveService;
public BotStatus BotStatus
{
get => botStatus;
set
{
botStatus = value;
if (botStatus == BotStatus.ActiveService && character == null)
{
//no character yet -> spawn is pending
PendingSpawnToActiveService = true;
}
}
}
public bool IsOnReserveBench => BotStatus == BotStatus.ReserveBench;
public bool PendingSpawnToActiveService;
private static ushort idCounter = 1;
private const string disguiseName = "???";
@@ -312,7 +331,18 @@ namespace Barotrauma
public LocalizedString Title;
public (Identifier NpcSetIdentifier, Identifier NpcIdentifier) HumanPrefabIds;
private HumanPrefab _humanPrefab;
public HumanPrefab HumanPrefab
{
get
{
if (HumanPrefabIds == default) { return null; }
_humanPrefab ??= NPCSet.Get(HumanPrefabIds.NpcSetIdentifier, HumanPrefabIds.NpcIdentifier);
return _humanPrefab;
}
}
public string DisplayName
{
get
@@ -340,19 +370,55 @@ namespace Barotrauma
public Identifier SpeciesName { get; }
private Character character;
/// <summary>
/// Note: Can be null.
/// </summary>
public Character Character;
public Character Character
{
get => character;
set
{
character = value;
if (character != null)
{
//character spawned -> spawn no longer pending
PendingSpawnToActiveService = false;
}
}
}
public Job Job;
public int Salary;
public int ExperiencePoints { get; private set; }
private int talentRefundPoints;
/// <summary>
/// How many times the player is eligible to refund talents
/// </summary>
public int TalentRefundPoints
{
get => talentRefundPoints;
set => talentRefundPoints = MathHelper.Max(value, 0);
}
public HashSet<Identifier> UnlockedTalents { get; private set; } = new HashSet<Identifier>();
private int talentResetCount;
/// <summary>
/// How many times have the characters' talents been reset?
/// </summary>
public int TalentResetCount
{
get => talentResetCount;
set => talentResetCount = MathHelper.Max(value, 0);
}
public (Identifier factionId, float reputation) MinReputationToHire;
/// <summary>
@@ -708,7 +774,9 @@ namespace Barotrauma
SetAttachments(randSync);
SetColors(randSync);
Job = job ?? ((jobPrefab == null) ? Job.Random(Rand.RandSync.Unsynced) : new Job(jobPrefab, randSync, variant));
Job = job ?? ((jobPrefab == null) ?
Job.Random(isPvP: false, Rand.RandSync.Unsynced) :
new Job(jobPrefab, isPvP: false, randSync, variant));
if (!string.IsNullOrEmpty(name))
{
@@ -725,6 +793,8 @@ namespace Barotrauma
}
OriginalName = !string.IsNullOrEmpty(originalName) ? originalName : Name;
TalentRefundPoints = CharacterConfigElement.GetAttributeInt("refundpoints", 0);
int loadedLastRewardDistribution = CharacterConfigElement.GetAttributeInt("lastrewarddistribution", -1);
if (loadedLastRewardDistribution >= 0)
{
@@ -742,6 +812,13 @@ namespace Barotrauma
return name;
}
public void SetNameBasedOnJob()
{
if (Job == null) { return; }
Name = Job.Name.Value;
OriginalName = Name;
}
public static Color SelectRandomColor(in ImmutableArray<(Color Color, float Commonness)> array, Rand.RandSync randSync)
=> ToolBox.SelectWeightedRandom(array, array.Select(p => p.Commonness).ToArray(), randSync)
.Color;
@@ -799,10 +876,12 @@ namespace Barotrauma
Salary = infoElement.GetAttributeInt("salary", 1000);
ExperiencePoints = infoElement.GetAttributeInt("experiencepoints", 0);
AdditionalTalentPoints = infoElement.GetAttributeInt("additionaltalentpoints", 0);
TalentResetCount = infoElement.GetAttributeInt(nameof(talentResetCount), 0);
HashSet<Identifier> tags = infoElement.GetAttributeIdentifierArray("tags", Array.Empty<Identifier>()).ToHashSet();
LoadTagsBackwardsCompatibility(infoElement, tags);
SpeciesName = infoElement.GetAttributeIdentifier("speciesname", "");
PermanentlyDead = infoElement.GetAttributeBool("permanentlydead", false);
BotStatus = infoElement.GetAttributeBool(nameof(IsOnReserveBench), false) ? BotStatus.ReserveBench : BotStatus.ActiveService;
RenamingEnabled = infoElement.GetAttributeBool("renamingenabled", false);
ContentXElement element;
if (!SpeciesName.IsEmpty)
@@ -1047,6 +1126,7 @@ namespace Barotrauma
public string ReplaceVars(string str)
{
if (Head == null) { return str; }
return Prefab.ReplaceVars(str, Head.Preset);
}
@@ -1254,7 +1334,7 @@ namespace Barotrauma
partial void LoadAttachmentSprites();
public int CalculateSalary()
public int CalculateSalary(int baseSalary = 0, float salaryMultiplier = 1.0f)
{
if (Name == null || Job == null) { return 0; }
@@ -1264,25 +1344,25 @@ namespace Barotrauma
salary += (int)(skill.Level * skill.PriceMultiplier);
}
return (int)(salary * Job.Prefab.PriceMultiplier);
return (int)(baseSalary + (salary * Job.Prefab.PriceMultiplier * salaryMultiplier));
}
/// <summary>
/// Increases the characters skill at a rate proportional to their current skill.
/// If you want to increase the skill level by a specific amount instead, use <see cref="IncreaseSkillLevel"/>
/// </summary>
public void ApplySkillGain(Identifier skillIdentifier, float baseGain, bool gainedFromAbility = false, float maxGain = 2f)
public void ApplySkillGain(Identifier skillIdentifier, float baseGain, bool gainedFromAbility = false, float maxGain = 2f, bool forceNotification = false)
{
float skillLevel = Job.GetSkillLevel(skillIdentifier);
// The formula is too generous on low skill levels, hence the minimum divider.
float skillDivider = MathF.Pow(Math.Max(skillLevel, 15f), SkillSettings.Current.SkillIncreaseExponent);
IncreaseSkillLevel(skillIdentifier, Math.Min(baseGain / skillDivider, maxGain), gainedFromAbility);
IncreaseSkillLevel(skillIdentifier, Math.Min(baseGain / skillDivider, maxGain), gainedFromAbility, forceNotification);
}
/// <summary>
/// Increase the skill by a specific amount. Talents may affect the actual, final skill increase.
/// </summary>
public void IncreaseSkillLevel(Identifier skillIdentifier, float increase, bool gainedFromAbility = false)
public void IncreaseSkillLevel(Identifier skillIdentifier, float increase, bool gainedFromAbility = false, bool forceNotification = false)
{
if (Job == null || (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) || Character == null) { return; }
@@ -1312,14 +1392,14 @@ namespace Barotrauma
}
}
OnSkillChanged(skillIdentifier, prevLevel, newLevel);
OnSkillChanged(skillIdentifier, prevLevel, newLevel, forceNotification);
}
private static readonly ImmutableDictionary<Identifier, StatTypes> skillGainStatValues = new Dictionary<Identifier, StatTypes>
{
{ new("helm"), StatTypes.HelmSkillGainSpeed },
{ new("medical"), StatTypes.WeaponsSkillGainSpeed },
{ new("weapons"), StatTypes.MedicalSkillGainSpeed },
{ new("weapons"), StatTypes.WeaponsSkillGainSpeed },
{ new("medical"), StatTypes.MedicalSkillGainSpeed },
{ new("electrical"), StatTypes.ElectricalSkillGainSpeed },
{ new("mechanical"), StatTypes.MechanicalSkillGainSpeed }
}.ToImmutableDictionary();
@@ -1334,7 +1414,7 @@ namespace Barotrauma
return increase;
}
public void SetSkillLevel(Identifier skillIdentifier, float level)
public void SetSkillLevel(Identifier skillIdentifier, float level, bool forceNotification = false)
{
if (Job == null) { return; }
@@ -1342,17 +1422,17 @@ namespace Barotrauma
if (skill == null)
{
Job.IncreaseSkillLevel(skillIdentifier, level, increasePastMax: false);
OnSkillChanged(skillIdentifier, 0.0f, level);
OnSkillChanged(skillIdentifier, 0.0f, level, forceNotification);
}
else
{
float prevLevel = skill.Level;
skill.Level = level;
OnSkillChanged(skillIdentifier, prevLevel, skill.Level);
OnSkillChanged(skillIdentifier, prevLevel, skill.Level, forceNotification);
}
}
partial void OnSkillChanged(Identifier skillIdentifier, float prevLevel, float newLevel);
partial void OnSkillChanged(Identifier skillIdentifier, float prevLevel, float newLevel, bool forceNotification);
public void GiveExperience(int amount)
{
@@ -1437,10 +1517,11 @@ namespace Barotrauma
experienceRequired += ExperienceRequiredPerLevel(level);
level++;
}
return level;
return Math.Max(level, 0);
}
private static int ExperienceRequiredPerLevel(int level)
public static int ExperienceRequiredPerLevel(int level)
{
return BaseExperienceRequired + AddedExperienceRequiredPerLevel * level;
}
@@ -1449,6 +1530,43 @@ namespace Barotrauma
partial void OnPermanentStatChanged(StatTypes statType);
public void RefundTalents()
{
if (TalentRefundPoints <= 0) { return; }
//e.g. talents from endocrine booster or extra talents some special NPC has
var talentsFromOutsideTree = GetUnlockedTalentsOutsideTree().ToList();
UnlockedTalents.Clear();
SavedStatValues.Clear();
Character?.ResetTalents(talentPointReduction: talentResetCount);
TalentRefundPoints--;
talentResetCount++;
//it's simpler to just remove everything first and then reapply the "extra" talents than to
//try determining which talent the resistances, ability flags etc came from and only remove specific ones
if (Character == null)
{
talentsFromOutsideTree.ForEach(talentId => UnlockedTalents.Add(talentId));
}
else
{
talentsFromOutsideTree.ForEach(talentId => Character.GiveTalent(talentId, addingFirstTime: true));
}
GameMain.NetworkMember?.CreateEntityEvent(Character, new Character.ConfirmRefundEventData());
}
public void AddRefundPoints(int newRefundPoints)
{
TalentRefundPoints += newRefundPoints;
#if SERVER
GameMain.NetworkMember?.CreateEntityEvent(Character, new Character.UpdateRefundPointsEventData());
#elif CLIENT
ShowTalentResetPopupOnOpen = true;
#endif
}
public void Rename(string newName)
{
if (string.IsNullOrEmpty(newName)) { return; }
@@ -1491,6 +1609,7 @@ namespace Barotrauma
new XAttribute("salary", Salary),
new XAttribute("experiencepoints", ExperiencePoints),
new XAttribute("additionaltalentpoints", AdditionalTalentPoints),
new XAttribute(nameof(talentResetCount), TalentResetCount),
new XAttribute("hairindex", Head.HairIndex),
new XAttribute("beardindex", Head.BeardIndex),
new XAttribute("moustacheindex", Head.MoustacheIndex),
@@ -1500,8 +1619,10 @@ namespace Barotrauma
new XAttribute("facialhaircolor", XMLExtensions.ColorToString(Head.FacialHairColor)),
new XAttribute("startitemsgiven", StartItemsGiven),
new XAttribute("personality", PersonalityTrait?.Identifier ?? Identifier.Empty),
new XAttribute("refundpoints", TalentRefundPoints),
new XAttribute("lastrewarddistribution", LastRewardDistribution.Match(some: value => value, none: () => -1).ToString()),
new XAttribute("permanentlydead", PermanentlyDead),
new XAttribute(nameof(IsOnReserveBench), IsOnReserveBench),
new XAttribute("renamingenabled", RenamingEnabled)
);
@@ -1601,7 +1722,7 @@ namespace Barotrauma
targetAvailableInNextLevel =
!isOutside &&
GameMain.GameSession?.Campaign is not { SwitchedSubsThisRound: true } &&
(isOnConnectedLinkedSub || entitySub == Submarine.MainSub);
(isOnConnectedLinkedSub || (Submarine.MainSub != null && entitySub == Submarine.MainSub));
if (!targetAvailableInNextLevel)
{
if (!order.Prefab.CanBeGeneralized)
@@ -1636,7 +1757,7 @@ namespace Barotrauma
}
if (order.TargetSpatialEntity?.Submarine is Submarine targetSub)
{
if (targetSub == Submarine.MainSub)
if (Submarine.MainSub != null && targetSub == Submarine.MainSub)
{
orderElement.Add(new XAttribute("onmainsub", true));
}