Build 1.1.4.0

This commit is contained in:
Markus Isberg
2023-03-31 18:40:44 +03:00
parent efba17e0ff
commit 9470edead3
483 changed files with 17487 additions and 8548 deletions
@@ -8,7 +8,7 @@ namespace Barotrauma
public override int State
{
get { return base.State; }
protected set
set
{
if (state != value)
{
@@ -45,7 +45,10 @@ namespace Barotrauma
{
requireRescue.Add(character);
#if CLIENT
GameMain.GameSession.CrewManager.AddCharacterToCrewList(character);
if (allowOrderingRescuees)
{
GameMain.GameSession.CrewManager.AddCharacterToCrewList(character);
}
#endif
}
ushort itemCount = msg.ReadUInt16();
@@ -10,8 +10,7 @@ namespace Barotrauma
public override RichString GetMissionRewardText(Submarine sub)
{
LocalizedString rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", GetReward(sub)));
LocalizedString rewardText = GetRewardAmountText(sub);
LocalizedString retVal;
if (rewardPerCrate.HasValue)
{
@@ -0,0 +1,138 @@
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Collections.Immutable;
namespace Barotrauma
{
partial class EndMission : Mission
{
public override bool DisplayAsCompleted => false;
public override bool DisplayAsFailed => false;
partial void OnStateChangedProjSpecific()
{
SoundPlayer.ForceMusicUpdate();
if (Phase == MissionPhase.NoItemsDestroyed)
{
CoroutineManager.Invoke(() =>
{
if (boss != null && !boss.Removed)
{
new CameraTransition(boss, GameMain.GameScreen.Cam, null, Alignment.Center, panDuration: 8, fadeOut: false, startZoom: 1.0f, endZoom: 0.3f * GUI.yScale)
{
RunWhilePaused = false,
EndWaitDuration = 3.0f
};
}
}, delay: 3.0f);
}
else if (Phase == MissionPhase.AllItemsDestroyed)
{
CoroutineManager.StartCoroutine(wakeUpCoroutine(), name: "EndMission.wakeUpCoroutine");
}
else if (Phase == MissionPhase.BossKilled)
{
if (!string.IsNullOrEmpty(endCinematicSound))
{
SoundPlayer.PlaySound(endCinematicSound);
}
CoroutineManager.Invoke(() =>
{
new CameraTransition(boss, GameMain.GameScreen.Cam, null, Alignment.Center, panDuration: 3, fadeOut: false, endZoom: 0.1f * GUI.yScale)
{
RunWhilePaused = false,
EndWaitDuration = float.PositiveInfinity
};
}, delay: 3.0f);
}
IEnumerable<CoroutineStatus> wakeUpCoroutine()
{
yield return new WaitForSeconds(wakeUpCinematicDelay);
if (boss != null && !boss.Removed)
{
new CameraTransition(boss, GameMain.GameScreen.Cam, null, Alignment.Center, panDuration: 5.0f, fadeOut: false, losFadeIn: false, startZoom: 1.0f, endZoom: 0.4f * GUI.yScale)
{
RunWhilePaused = false,
EndWaitDuration = cameraWaitDuration
};
}
yield return new WaitForSeconds(bossWakeUpDelay);
if (boss != null && !boss.Removed)
{
foreach (var limb in boss.AnimController.Limbs)
{
if (!limb.FreezeBlinkState) { continue; }
limb.FreezeBlinkState = false;
if (limb.LightSource is Lights.LightSource light)
{
light.Enabled = true;
}
}
}
}
}
partial void UpdateProjSpecific()
{
if (boss == null || boss.Removed) { return; }
if (Phase is MissionPhase.Initial or MissionPhase.NoItemsDestroyed or MissionPhase.SomeItemsDestroyed)
{
// Put asleep.
// Have to set the light every frame (or at least periodically), because light.Enabled is changed when Character.IsVisible changes (off/on screen). See GameScreen.Draw().
foreach (var limb in boss.AnimController.Limbs)
{
if (limb.Params.BlinkFrequency > 0)
{
limb.FreezeBlinkState = true;
limb.BlinkPhase = -limb.Params.BlinkHoldTime;
if (limb.LightSource is Lights.LightSource light)
{
light.Enabled = false;
}
}
}
}
#if DEBUG
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.O))
{
State = 0;
}
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Y))
{
destructibleItems.ForEach(it => it.Condition = 0.0f);
}
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.U))
{
boss?.SetAllDamage(20000.0f, 0.0f, 0.0f);
}
#endif
}
public override void ClientReadInitial(IReadMessage msg)
{
base.ClientReadInitial(msg);
boss = Character.ReadSpawnData(msg);
byte minionCount = msg.ReadByte();
List<Character> minionList = new List<Character>();
for (int i = 0; i < minionCount; i++)
{
var minion = Character.ReadSpawnData(msg);
if (minion == null)
{
throw new System.Exception($"Error in EndMission.ClientReadInitial: failed to create a minion (mission: {Prefab.Identifier}, index: {i})");
}
minionList.Add(minion);
}
minions = minionList.ToImmutableArray();
if (minions.Length != minionCount)
{
throw new System.Exception("Error in EndMission.ClientReadInitial: minion count does not match the server count (" + minionCount + " != " + minions.Length + "mission: " + Prefab.Identifier + ")");
}
}
}
}
@@ -2,7 +2,7 @@
{
partial class GoToMission : Mission
{
public override bool DisplayAsCompleted => false;
public override bool DisplayAsCompleted => State >= Prefab.MaxProgressState;
public override bool DisplayAsFailed => false;
}
}
@@ -29,7 +29,7 @@ namespace Barotrauma
}
}
for (int i = 0; i < resourceClusters.Count; i++)
for (int i = 0; i < resourceAmounts.Count; i++)
{
var amount = msg.ReadByte();
var rotation = msg.ReadSingle();
@@ -54,7 +54,7 @@ namespace Barotrauma
CalculateMissionClusterPositions();
for(int i = 0; i < resourceClusters.Count; i++)
for(int i = 0; i < resourceAmounts.Count; i++)
{
var identifier = msg.ReadIdentifier();
var count = msg.ReadByte();
@@ -32,44 +32,73 @@ namespace Barotrauma
return ToolBox.GradientLerp(t, GUIStyle.Green, GUIStyle.Orange, GUIStyle.Red);
}
public virtual RichString GetMissionRewardText(Submarine sub)
/// <summary>
/// Returns the amount of marks you get from the reward (e.g. "3,000 mk")
/// </summary>
protected LocalizedString GetRewardAmountText(Submarine sub)
{
LocalizedString rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", GetReward(sub)));
return RichString.Rich(TextManager.GetWithVariable("missionreward", "[reward]", "‖color:gui.orange‖"+rewardText+"‖end‖"));
int baseReward = GetReward(sub);
int finalReward = GetFinalReward(sub);
string rewardAmountText = string.Format(CultureInfo.InvariantCulture, "{0:N0}", baseReward);
if (finalReward > baseReward)
{
rewardAmountText += $" + {string.Format(CultureInfo.InvariantCulture, "{0:N0}", finalReward - baseReward)}";
}
return TextManager.GetWithVariable("currencyformat", "[credits]", rewardAmountText);
}
public RichString GetReputationRewardText(Location currLocation)
/// <summary>
/// Returns the full reward text of the mission (e.g. "Reward: 2,000 mk" or "Reward: 500 mk x 2 (out of max 5) = 1,000 mk")
/// </summary>
public virtual RichString GetMissionRewardText(Submarine sub)
{
LocalizedString rewardText = GetRewardAmountText(sub);
return RichString.Rich(TextManager.GetWithVariable("missionreward", "[reward]", "‖color:gui.orange‖" + rewardText + "‖end‖"));
}
public RichString GetReputationRewardText()
{
List<LocalizedString> reputationRewardTexts = new List<LocalizedString>();
foreach (var reputationReward in ReputationRewards)
{
LocalizedString name = "";
if (reputationReward.Key == "location")
FactionPrefab targetFactionPrefab;
if (reputationReward.Key == "location" )
{
name = $"‖color:gui.orange‖{currLocation.Name}‖end‖";
targetFactionPrefab = OriginLocation.Faction?.Prefab;
}
else
{
var faction = FactionPrefab.Prefabs.Find(f => f.Identifier == reputationReward.Key);
if (faction != null)
{
name = $"‖color:{XMLExtensions.ColorToString(faction.IconColor)}‖{faction.Name}‖end‖";
}
else
{
name = TextManager.Get(reputationReward.Key);
}
FactionPrefab.Prefabs.TryGet(reputationReward.Key, out targetFactionPrefab);
}
if (targetFactionPrefab == null)
{
return string.Empty;
}
float normalizedValue = MathUtils.InverseLerp(-100.0f, 100.0f, reputationReward.Value);
string formattedValue = ((int)reputationReward.Value).ToString("+#;-#;0"); //force plus sign for positive numbers
float totalReputationChange = reputationReward.Value;
if (GameMain.GameSession?.Campaign?.Factions.Find(f => f.Prefab == targetFactionPrefab) is Faction faction)
{
totalReputationChange = reputationReward.Value * faction.Reputation.GetReputationChangeMultiplier(reputationReward.Value);
}
LocalizedString name = $"‖color:{XMLExtensions.ToStringHex(targetFactionPrefab.IconColor)}‖{targetFactionPrefab.Name}‖end‖";
float normalizedValue = MathUtils.InverseLerp(-100.0f, 100.0f, totalReputationChange);
string formattedValue = ((int)Math.Round(totalReputationChange)).ToString("+#;-#;0"); //force plus sign for positive numbers
LocalizedString rewardText = TextManager.GetWithVariables(
"reputationformat",
("[reputationname]", name),
("[reputationvalue]", $"‖color:{XMLExtensions.ColorToString(Reputation.GetReputationColor(normalizedValue))}‖{formattedValue}‖end‖" ));
("[reputationvalue]", $"‖color:{XMLExtensions.ToStringHex(Reputation.GetReputationColor(normalizedValue))}‖{formattedValue}‖end‖" ));
reputationRewardTexts.Add(rewardText.Value);
}
return RichString.Rich(TextManager.AddPunctuation(':', TextManager.Get("reputation"), LocalizedString.Join(", ", reputationRewardTexts)));
if (reputationRewardTexts.Any())
{
return RichString.Rich(TextManager.AddPunctuation(':', TextManager.Get("reputation"), LocalizedString.Join(", ", reputationRewardTexts)));
}
else
{
return string.Empty;
}
}
partial void ShowMessageProjSpecific(int missionState)
@@ -107,6 +136,11 @@ namespace Barotrauma
};
}
public Identifier GetOverrideMusicType()
{
return Prefab.GetOverrideMusicType(State);
}
public virtual void ClientRead(IReadMessage msg)
{
State = msg.ReadInt16();
@@ -8,6 +8,7 @@ namespace Barotrauma
{
foreach (Mission mission in missions)
{
if (!mission.Prefab.ShowStartMessage) { continue; }
new GUIMessageBox(RichString.Rich(mission.Name), RichString.Rich(mission.Description), Array.Empty<LocalizedString>(), type: GUIMessageBox.Type.InGame, icon: mission.Prefab.Icon)
{
IconColor = mission.Prefab.IconColor,
@@ -1,11 +1,16 @@
using Microsoft.Xna.Framework;
using System;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;
namespace Barotrauma
{
partial class MissionPrefab : PrefabWithUintIdentifier
{
private ImmutableArray<Sprite> portraits = new ImmutableArray<Sprite>();
public bool HasPortraits => portraits.Length > 0;
public Sprite Icon
{
get;
@@ -49,24 +54,57 @@ namespace Barotrauma
private Sprite hudIcon;
private Color? hudIconColor;
private ImmutableDictionary<int, Identifier> overrideMusicOnState;
partial void InitProjSpecific(ContentXElement element)
{
DisplayTargetHudIcons = element.GetAttributeBool("displaytargethudicons", false);
HudIconMaxDistance = element.GetAttributeFloat("hudiconmaxdistance", 1000.0f);
Dictionary<int, Identifier> overrideMusic = new Dictionary<int, Identifier>();
List<Sprite> portraits = new List<Sprite>();
foreach (var subElement in element.Elements())
{
string name = subElement.Name.ToString();
if (name.Equals("icon", StringComparison.OrdinalIgnoreCase))
switch (subElement.Name.ToString().ToLowerInvariant())
{
Icon = new Sprite(subElement);
IconColor = subElement.GetAttributeColor("color", Color.White);
}
else if (name.Equals("hudicon", StringComparison.OrdinalIgnoreCase))
{
hudIcon = new Sprite(subElement);
hudIconColor = subElement.GetAttributeColor("color");
case "icon":
Icon = new Sprite(subElement);
IconColor = subElement.GetAttributeColor("color", Color.White);
break;
case "hudicon":
hudIcon = new Sprite(subElement);
hudIconColor = subElement.GetAttributeColor("color");
break;
case "overridemusic":
overrideMusic.Add(
subElement.GetAttributeInt("state", 0),
subElement.GetAttributeIdentifier("type", Identifier.Empty));
break;
case "portrait":
var portrait = new Sprite(subElement, lazyLoad: true);
if (portrait != null)
{
portraits.Add(portrait);
}
break;
}
}
this.portraits = portraits.ToImmutableArray();
overrideMusicOnState = overrideMusic.ToImmutableDictionary();
}
public Identifier GetOverrideMusicType(int state)
{
if (overrideMusicOnState.TryGetValue(state, out Identifier id))
{
return id;
}
return Identifier.Empty;
}
public Sprite GetPortrait(int randomSeed)
{
if (portraits.Length == 0) { return null; }
return portraits[Math.Abs(randomSeed) % portraits.Length];
}
partial void DisposeProjectSpecific()
@@ -13,11 +13,12 @@ namespace Barotrauma
byte monsterCount = msg.ReadByte();
for (int i = 0; i < monsterCount; i++)
{
monsters.Add(Character.ReadSpawnData(msg));
}
if (monsters.Contains(null))
{
throw new System.Exception("Error in MonsterMission.ClientReadInitial: monster list contains null (mission: " + Prefab.Identifier + ")");
var monster = Character.ReadSpawnData(msg);
if (monster == null)
{
throw new System.Exception($"Error in MonsterMission.ClientReadInitial: failed to create a monster (mission: {Prefab.Identifier}, index: {i})");
}
monsters.Add(monster);
}
if (monsters.Count != monsterCount)
{
@@ -11,38 +11,59 @@ namespace Barotrauma
public override void ClientReadInitial(IReadMessage msg)
{
base.ClientReadInitial(msg);
bool usedExistingItem = msg.ReadBoolean();
if (usedExistingItem)
foreach (var target in targets)
{
ushort id = msg.ReadUInt16();
item = Entity.FindEntityByID(id) as Item;
if (item == null)
bool targetFound = msg.ReadBoolean();
if (!targetFound) { continue; }
bool usedExistingItem = msg.ReadBoolean();
if (usedExistingItem)
{
throw new System.Exception("Error in SalvageMission.ClientReadInitial: failed to find item " + id + " (mission: " + Prefab.Identifier + ")");
ushort id = msg.ReadUInt16();
target.Item = Entity.FindEntityByID(id) as Item;
if (target.Item == null)
{
throw new System.Exception("Error in SalvageMission.ClientReadInitial: failed to find item " + id + " (mission: " + Prefab.Identifier + ")");
}
}
else
{
target.Item = Item.ReadSpawnData(msg);
if (target.Item == null)
{
throw new System.Exception("Error in SalvageMission.ClientReadInitial: spawned item was null (mission: " + Prefab.Identifier + ")");
}
}
int executedEffectCount = msg.ReadByte();
for (int i = 0; i < executedEffectCount; i++)
{
int listIndex = msg.ReadByte();
int effectIndex = msg.ReadByte();
var selectedEffect = target.StatusEffects[listIndex][effectIndex];
target.Item.ApplyStatusEffect(selectedEffect, selectedEffect.type, deltaTime: 1.0f, worldPosition: target.Item.Position);
}
if (target.Item.body != null)
{
target.Item.body.FarseerBody.BodyType = BodyType.Kinematic;
}
}
else
}
public override void ClientRead(IReadMessage msg)
{
base.ClientRead(msg);
int targetCount = msg.ReadByte();
for (int i = 0; i < targetCount; i++)
{
item = Item.ReadSpawnData(msg);
if (item == null)
var state = (Target.RetrievalState)msg.ReadByte();
if (i < targets.Count)
{
throw new System.Exception("Error in SalvageMission.ClientReadInitial: spawned item was null (mission: " + Prefab.Identifier + ")");
targets[i].State = state;
}
}
int executedEffectCount = msg.ReadByte();
for (int i = 0; i < executedEffectCount; i++)
{
int index1 = msg.ReadByte();
int index2 = msg.ReadByte();
var selectedEffect = statusEffects[index1][index2];
item.ApplyStatusEffect(selectedEffect, selectedEffect.type, deltaTime: 1.0f, worldPosition: item.Position);
}
if (item.body != null)
{
item.body.FarseerBody.BodyType = BodyType.Kinematic;
}
}
}
}