Build 0.18.0.0
This commit is contained in:
@@ -400,7 +400,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
partial void UpdateControlled(float deltaTime, Camera cam)
|
partial void UpdateControlled(float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
if (controlled != this) return;
|
if (controlled != this) { return; }
|
||||||
|
|
||||||
ControlLocalPlayer(deltaTime, cam);
|
ControlLocalPlayer(deltaTime, cam);
|
||||||
|
|
||||||
|
|||||||
@@ -2008,8 +2008,27 @@ namespace Barotrauma
|
|||||||
DisplayedVitality = Vitality;
|
DisplayedVitality = Vitality;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void UpdateSkinTint()
|
||||||
|
{
|
||||||
|
if (!Character.IsVisible) { return; }
|
||||||
|
FaceTint = DefaultFaceTint;
|
||||||
|
BodyTint = Color.TransparentBlack;
|
||||||
|
|
||||||
|
if (!(Character?.Params?.Health.ApplyAfflictionColors ?? false)) { return; }
|
||||||
|
|
||||||
|
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
||||||
|
{
|
||||||
|
var affliction = kvp.Key;
|
||||||
|
Color faceTint = affliction.GetFaceTint();
|
||||||
|
if (faceTint.A > FaceTint.A) { FaceTint = faceTint; }
|
||||||
|
Color bodyTint = affliction.GetBodyTint();
|
||||||
|
if (bodyTint.A > BodyTint.A) { BodyTint = bodyTint; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
partial void UpdateLimbAfflictionOverlays()
|
partial void UpdateLimbAfflictionOverlays()
|
||||||
{
|
{
|
||||||
|
if (!Character.IsVisible) { return; }
|
||||||
foreach (Limb limb in Character.AnimController.Limbs)
|
foreach (Limb limb in Character.AnimController.Limbs)
|
||||||
{
|
{
|
||||||
if (limb.HealthIndex < 0 || limb.HealthIndex >= limbHealths.Count) { continue; }
|
if (limb.HealthIndex < 0 || limb.HealthIndex >= limbHealths.Count) { continue; }
|
||||||
|
|||||||
@@ -58,21 +58,19 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public class OutfitPreview
|
public class OutfitPreview
|
||||||
{
|
{
|
||||||
/// <summary>
|
public readonly List<(Sprite sprite, Vector2 drawOffset)> Sprites;
|
||||||
/// Pair.First = sprite, Pair.Second = draw offset
|
|
||||||
/// </summary>
|
|
||||||
public readonly List<Pair<Sprite, Vector2>> Sprites;
|
|
||||||
public Vector2 Dimensions;
|
public Vector2 Dimensions;
|
||||||
|
|
||||||
public OutfitPreview()
|
public OutfitPreview()
|
||||||
{
|
{
|
||||||
Sprites = new List<Pair<Sprite, Vector2>>();
|
Sprites = new List<(Sprite sprite, Vector2 drawOffset)>();
|
||||||
Dimensions = Vector2.One;
|
Dimensions = Vector2.One;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSprite(Sprite sprite, Vector2 drawOffset)
|
public void AddSprite(Sprite sprite, Vector2 drawOffset)
|
||||||
{
|
{
|
||||||
Sprites.Add(new Pair<Sprite, Vector2>(sprite, drawOffset));
|
Sprites.Add((sprite, drawOffset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -224,14 +224,14 @@ namespace Barotrauma
|
|||||||
public float DamageOverlayStrength
|
public float DamageOverlayStrength
|
||||||
{
|
{
|
||||||
get { return damageOverlayStrength; }
|
get { return damageOverlayStrength; }
|
||||||
set { damageOverlayStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
set { damageOverlayStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private float burnOverLayStrength;
|
private float burnOverLayStrength;
|
||||||
public float BurnOverlayStrength
|
public float BurnOverlayStrength
|
||||||
{
|
{
|
||||||
get { return burnOverLayStrength; }
|
get { return burnOverLayStrength; }
|
||||||
set { burnOverLayStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
set { burnOverLayStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public string HitSoundTag => Params?.Sound?.Tag;
|
public string HitSoundTag => Params?.Sound?.Tag;
|
||||||
@@ -279,7 +279,7 @@ namespace Barotrauma
|
|||||||
for (int i = 0; i < Params.decorativeSpriteParams.Count; i++)
|
for (int i = 0; i < Params.decorativeSpriteParams.Count; i++)
|
||||||
{
|
{
|
||||||
var param = Params.decorativeSpriteParams[i];
|
var param = Params.decorativeSpriteParams[i];
|
||||||
var decorativeSprite = new DecorativeSprite(param.Element, file: GetSpritePath(param.Element, param));
|
var decorativeSprite = new DecorativeSprite(param.Element, file: GetSpritePath(param.Element, param, ref _texturePath));
|
||||||
DecorativeSprites.Add(decorativeSprite);
|
DecorativeSprites.Add(decorativeSprite);
|
||||||
int groupID = decorativeSprite.RandomGroupID;
|
int groupID = decorativeSprite.RandomGroupID;
|
||||||
if (!DecorativeSpriteGroups.ContainsKey(groupID))
|
if (!DecorativeSpriteGroups.ContainsKey(groupID))
|
||||||
@@ -295,13 +295,13 @@ namespace Barotrauma
|
|||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case "sprite":
|
case "sprite":
|
||||||
Sprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.normalSpriteParams));
|
Sprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.normalSpriteParams, ref _texturePath));
|
||||||
break;
|
break;
|
||||||
case "damagedsprite":
|
case "damagedsprite":
|
||||||
DamagedSprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.damagedSpriteParams));
|
DamagedSprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.damagedSpriteParams, ref _damagedTexturePath));
|
||||||
break;
|
break;
|
||||||
case "conditionalsprite":
|
case "conditionalsprite":
|
||||||
var conditionalSprite = new ConditionalSprite(subElement, GetConditionalTarget(), file: GetSpritePath(subElement, null));
|
var conditionalSprite = new ConditionalSprite(subElement, GetConditionalTarget(), file: GetSpritePath(subElement, null, ref _texturePath));
|
||||||
ConditionalSprites.Add(conditionalSprite);
|
ConditionalSprites.Add(conditionalSprite);
|
||||||
if (conditionalSprite.DeformableSprite != null)
|
if (conditionalSprite.DeformableSprite != null)
|
||||||
{
|
{
|
||||||
@@ -311,7 +311,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "deformablesprite":
|
case "deformablesprite":
|
||||||
_deformSprite = new DeformableSprite(subElement, filePath: GetSpritePath(subElement, Params.deformSpriteParams));
|
_deformSprite = new DeformableSprite(subElement, filePath: GetSpritePath(subElement, Params.deformSpriteParams, ref _texturePath));
|
||||||
var deformations = CreateDeformations(subElement);
|
var deformations = CreateDeformations(subElement);
|
||||||
Deformations.AddRange(deformations);
|
Deformations.AddRange(deformations);
|
||||||
NonConditionalDeformations.AddRange(deformations);
|
NonConditionalDeformations.AddRange(deformations);
|
||||||
@@ -435,33 +435,33 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Sprite.Remove();
|
Sprite.Remove();
|
||||||
var source = Sprite.SourceElement;
|
var source = Sprite.SourceElement;
|
||||||
Sprite = new Sprite(source, file: GetSpritePath(source, Params.normalSpriteParams));
|
Sprite = new Sprite(source, file: GetSpritePath(source, Params.normalSpriteParams, ref _texturePath));
|
||||||
}
|
}
|
||||||
if (_deformSprite != null)
|
if (_deformSprite != null)
|
||||||
{
|
{
|
||||||
_deformSprite.Remove();
|
_deformSprite.Remove();
|
||||||
var source = _deformSprite.Sprite.SourceElement;
|
var source = _deformSprite.Sprite.SourceElement;
|
||||||
_deformSprite = new DeformableSprite(source, filePath: GetSpritePath(source, Params.deformSpriteParams));
|
_deformSprite = new DeformableSprite(source, filePath: GetSpritePath(source, Params.deformSpriteParams, ref _texturePath));
|
||||||
}
|
}
|
||||||
if (DamagedSprite != null)
|
if (DamagedSprite != null)
|
||||||
{
|
{
|
||||||
DamagedSprite.Remove();
|
DamagedSprite.Remove();
|
||||||
var source = DamagedSprite.SourceElement;
|
var source = DamagedSprite.SourceElement;
|
||||||
DamagedSprite = new Sprite(source, file: GetSpritePath(source, Params.damagedSpriteParams));
|
DamagedSprite = new Sprite(source, file: GetSpritePath(source, Params.damagedSpriteParams, ref _damagedTexturePath));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < ConditionalSprites.Count; i++)
|
for (int i = 0; i < ConditionalSprites.Count; i++)
|
||||||
{
|
{
|
||||||
var conditionalSprite = ConditionalSprites[i];
|
var conditionalSprite = ConditionalSprites[i];
|
||||||
var source = conditionalSprite.ActiveSprite.SourceElement;
|
var source = conditionalSprite.ActiveSprite.SourceElement;
|
||||||
conditionalSprite.Remove();
|
conditionalSprite.Remove();
|
||||||
ConditionalSprites[i] = new ConditionalSprite(source, character, file: GetSpritePath(source, null));
|
ConditionalSprites[i] = new ConditionalSprite(source, character, file: GetSpritePath(source, null, ref _texturePath));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < DecorativeSprites.Count; i++)
|
for (int i = 0; i < DecorativeSprites.Count; i++)
|
||||||
{
|
{
|
||||||
var decorativeSprite = DecorativeSprites[i];
|
var decorativeSprite = DecorativeSprites[i];
|
||||||
decorativeSprite.Remove();
|
decorativeSprite.Remove();
|
||||||
var source = decorativeSprite.Sprite.SourceElement;
|
var source = decorativeSprite.Sprite.SourceElement;
|
||||||
DecorativeSprites[i] = new DecorativeSprite(source, file: GetSpritePath(source, Params.decorativeSpriteParams[i]));
|
DecorativeSprites[i] = new DecorativeSprite(source, file: GetSpritePath(source, Params.decorativeSpriteParams[i], ref _texturePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,16 +472,17 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string _texturePath;
|
private string _texturePath;
|
||||||
private string GetSpritePath(ContentXElement element, SpriteParams spriteParams)
|
private string _damagedTexturePath;
|
||||||
|
private string GetSpritePath(ContentXElement element, SpriteParams spriteParams, ref string path)
|
||||||
{
|
{
|
||||||
if (_texturePath == null)
|
if (path == null)
|
||||||
{
|
{
|
||||||
if (spriteParams != null)
|
if (spriteParams != null)
|
||||||
{
|
{
|
||||||
ContentPath texturePath =
|
ContentPath texturePath =
|
||||||
character.Params.VariantFile?.Root?.GetAttributeContentPath("texture", character.Prefab.ContentPackage)
|
character.Params.VariantFile?.Root?.GetAttributeContentPath("texture", character.Prefab.ContentPackage)
|
||||||
?? ContentPath.FromRaw(character.Prefab.ContentPackage, spriteParams.GetTexturePath());
|
?? ContentPath.FromRaw(character.Prefab.ContentPackage, spriteParams.GetTexturePath());
|
||||||
_texturePath = GetSpritePath(texturePath);
|
path = GetSpritePath(texturePath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -489,10 +490,10 @@ namespace Barotrauma
|
|||||||
texturePath = texturePath.IsNullOrWhiteSpace()
|
texturePath = texturePath.IsNullOrWhiteSpace()
|
||||||
? ContentPath.FromRaw(character.Prefab.ContentPackage, ragdoll.RagdollParams.Texture)
|
? ContentPath.FromRaw(character.Prefab.ContentPackage, ragdoll.RagdollParams.Texture)
|
||||||
: texturePath;
|
: texturePath;
|
||||||
_texturePath = GetSpritePath(texturePath);
|
path = GetSpritePath(texturePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _texturePath;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -625,12 +626,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (!body.Enabled) { return; }
|
if (!body.Enabled) { return; }
|
||||||
|
|
||||||
if (!IsDead)
|
if (IsDead)
|
||||||
{
|
|
||||||
DamageOverlayStrength -= deltaTime;
|
|
||||||
BurnOverlayStrength -= deltaTime;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
var spriteParams = Params.GetSprite();
|
var spriteParams = Params.GetSprite();
|
||||||
if (spriteParams != null && spriteParams.DeadColorTime > 0 && deadTimer < spriteParams.DeadColorTime)
|
if (spriteParams != null && spriteParams.DeadColorTime > 0 && deadTimer < spriteParams.DeadColorTime)
|
||||||
@@ -688,7 +684,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null, bool disableDeformations = false)
|
public void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor = null, bool disableDeformations = false)
|
||||||
{
|
{
|
||||||
float brightness = 1.0f - (burnOverLayStrength / 100.0f) * 0.5f;
|
float brightness = Math.Max(1.0f - burnOverLayStrength, 0.2f);
|
||||||
var spriteParams = Params.GetSprite();
|
var spriteParams = Params.GetSprite();
|
||||||
if (spriteParams == null) { return; }
|
if (spriteParams == null) { return; }
|
||||||
|
|
||||||
@@ -831,32 +827,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
|
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
|
||||||
}
|
}
|
||||||
if (damageOverlayStrength > 0.0f && DamagedSprite != null && !hideLimb)
|
|
||||||
{
|
|
||||||
DamagedSprite.Draw(spriteBatch,
|
|
||||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
|
||||||
color * Math.Min(damageOverlayStrength, 1.0f), activeSprite.Origin,
|
|
||||||
-body.DrawRotation,
|
|
||||||
Scale, spriteEffect, activeSprite.Depth - (depthStep * 90));
|
|
||||||
}
|
|
||||||
foreach (var decorativeSprite in DecorativeSprites)
|
|
||||||
{
|
|
||||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
|
||||||
Color c = new Color(decorativeSprite.Color.R / 255f * brightness, decorativeSprite.Color.G / 255f * brightness, decorativeSprite.Color.B / 255f * brightness, decorativeSprite.Color.A / 255f);
|
|
||||||
if (deadTimer > 0)
|
|
||||||
{
|
|
||||||
c = Color.Lerp(c, spriteParams.DeadColor, MathUtils.InverseLerp(0, Params.GetSprite().DeadColorTime, deadTimer));
|
|
||||||
}
|
|
||||||
c = overrideColor ?? c;
|
|
||||||
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
|
|
||||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier) * Scale;
|
|
||||||
var ca = (float)Math.Cos(-body.Rotation);
|
|
||||||
var sa = (float)Math.Sin(-body.Rotation);
|
|
||||||
Vector2 transformedOffset = new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
|
|
||||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X + transformedOffset.X, -(body.DrawPosition.Y + transformedOffset.Y)), c,
|
|
||||||
-body.Rotation + rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, spriteEffect,
|
|
||||||
depth: activeSprite.Depth - (depthStep * 100));
|
|
||||||
}
|
|
||||||
float step = depthStep;
|
float step = depthStep;
|
||||||
WearableSprite onlyDrawable = wearingItems.Find(w => w.HideOtherWearables);
|
WearableSprite onlyDrawable = wearingItems.Find(w => w.HideOtherWearables);
|
||||||
if (Params.MirrorHorizontally)
|
if (Params.MirrorHorizontally)
|
||||||
@@ -925,6 +895,36 @@ namespace Barotrauma
|
|||||||
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
//if there are multiple sprites on this limb, make the successive ones be drawn in front
|
||||||
depthStep += step;
|
depthStep += step;
|
||||||
}
|
}
|
||||||
|
if (!Hide && onlyDrawable == null)
|
||||||
|
{
|
||||||
|
foreach (var decorativeSprite in DecorativeSprites)
|
||||||
|
{
|
||||||
|
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||||
|
Color c = new Color(decorativeSprite.Color.R / 255f * brightness, decorativeSprite.Color.G / 255f * brightness, decorativeSprite.Color.B / 255f * brightness, decorativeSprite.Color.A / 255f);
|
||||||
|
if (deadTimer > 0)
|
||||||
|
{
|
||||||
|
c = Color.Lerp(c, spriteParams.DeadColor, MathUtils.InverseLerp(0, Params.GetSprite().DeadColorTime, deadTimer));
|
||||||
|
}
|
||||||
|
c = overrideColor ?? c;
|
||||||
|
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
|
||||||
|
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier) * Scale;
|
||||||
|
var ca = (float)Math.Cos(-body.Rotation);
|
||||||
|
var sa = (float)Math.Sin(-body.Rotation);
|
||||||
|
Vector2 transformedOffset = new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
|
||||||
|
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X + transformedOffset.X, -(body.DrawPosition.Y + transformedOffset.Y)), c,
|
||||||
|
-body.Rotation + rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale, spriteEffect,
|
||||||
|
depth: activeSprite.Depth - depthStep);
|
||||||
|
depthStep += step;
|
||||||
|
}
|
||||||
|
if (damageOverlayStrength > 0.0f && DamagedSprite != null)
|
||||||
|
{
|
||||||
|
DamagedSprite.Draw(spriteBatch,
|
||||||
|
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||||
|
color * damageOverlayStrength, activeSprite.Origin,
|
||||||
|
-body.DrawRotation,
|
||||||
|
Scale, spriteEffect, activeSprite.Depth - depthStep * Math.Max(1, WearingItems.Count * 2)); // Multiply by 2 to get rid of z-fighting with some clothing combos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (GameMain.DebugDraw)
|
if (GameMain.DebugDraw)
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -359,7 +359,7 @@ namespace Barotrauma.Transition
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//copying a mod: we have a neat method for that!
|
//copying a mod: we have a neat method for that!
|
||||||
await SteamManager.Workshop.CopyDirectory(path, Path.GetFileName(path), path, destPath);
|
await SteamManager.Workshop.CopyDirectory(path, Path.GetFileName(path), path, destPath, SteamManager.Workshop.ShouldCorrectPaths.Yes);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (isOpen)
|
if (isOpen)
|
||||||
{
|
{
|
||||||
frame.AddToGUIUpdateList();
|
frame.AddToGUIUpdateList(order: 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1714,9 +1714,47 @@ namespace Barotrauma
|
|||||||
//check missing mission texts
|
//check missing mission texts
|
||||||
foreach (var missionPrefab in MissionPrefab.Prefabs)
|
foreach (var missionPrefab in MissionPrefab.Prefabs)
|
||||||
{
|
{
|
||||||
Identifier missionId = (missionPrefab.ConfigElement.GetAttribute("textidentifier") == null ? missionPrefab.Identifier : missionPrefab.ConfigElement.GetAttributeIdentifier("textidentifier", Identifier.Empty));
|
Identifier missionId = missionPrefab.ConfigElement.GetAttribute("textidentifier") == null ?
|
||||||
addIfMissing($"missionname.{missionId}".ToIdentifier(), language);
|
missionPrefab.Identifier :
|
||||||
addIfMissing($"missiondescription.{missionId}".ToIdentifier(), language);
|
missionPrefab.ConfigElement.GetAttributeIdentifier("textidentifier", Identifier.Empty);
|
||||||
|
|
||||||
|
if (!tags[language].Contains(missionPrefab.ConfigElement.GetAttributeIdentifier("name", Identifier.Empty)))
|
||||||
|
{
|
||||||
|
addIfMissing($"missionname.{missionId}".ToIdentifier(), language);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missionPrefab.Type == MissionType.Combat)
|
||||||
|
{
|
||||||
|
addIfMissing($"MissionDescriptionNeutral.{missionId}".ToIdentifier(), language);
|
||||||
|
addIfMissing($"MissionDescription1.{missionId}".ToIdentifier(), language);
|
||||||
|
addIfMissing($"MissionDescription2.{missionId}".ToIdentifier(), language);
|
||||||
|
addIfMissing($"MissionTeam1.{missionId}".ToIdentifier(), language);
|
||||||
|
addIfMissing($"MissionTeam2.{missionId}".ToIdentifier(), language);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!tags[language].Contains(missionPrefab.ConfigElement.GetAttributeIdentifier("description", Identifier.Empty)))
|
||||||
|
{
|
||||||
|
addIfMissing($"missiondescription.{missionId}".ToIdentifier(), language);
|
||||||
|
}
|
||||||
|
if (!tags[language].Contains(missionPrefab.ConfigElement.GetAttributeIdentifier("successmessage", Identifier.Empty)))
|
||||||
|
{
|
||||||
|
addIfMissing($"missionsuccess.{missionId}".ToIdentifier(), language);
|
||||||
|
}
|
||||||
|
//only check failure message if there's something defined in the xml (otherwise we just use the generic "missionfailed" text)
|
||||||
|
if (missionPrefab.ConfigElement.GetAttribute("failuremessage") != null &&
|
||||||
|
!tags[language].Contains(missionPrefab.ConfigElement.GetAttributeIdentifier("failuremessage", Identifier.Empty)))
|
||||||
|
{
|
||||||
|
addIfMissing($"missionfailure.{missionId}".ToIdentifier(), language);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i<missionPrefab.Messages.Length; i++)
|
||||||
|
{
|
||||||
|
if (missionPrefab.Messages[i].IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
addIfMissing($"MissionMessage{i}.{missionId}".ToIdentifier(), language);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Type itemComponentType in typeof(ItemComponent).Assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(ItemComponent))))
|
foreach (Type itemComponentType in typeof(ItemComponent).Assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(ItemComponent))))
|
||||||
@@ -2503,7 +2541,7 @@ namespace Barotrauma
|
|||||||
var entity = MapEntity.mapEntityList[i] as ISerializableEntity;
|
var entity = MapEntity.mapEntityList[i] as ISerializableEntity;
|
||||||
if (entity != null)
|
if (entity != null)
|
||||||
{
|
{
|
||||||
List<Pair<object, SerializableProperty>> allProperties = new List<Pair<object, SerializableProperty>>();
|
List<(object obj, SerializableProperty property)> allProperties = new List<(object obj, SerializableProperty property)>();
|
||||||
|
|
||||||
if (entity is Item item)
|
if (entity is Item item)
|
||||||
{
|
{
|
||||||
@@ -2518,14 +2556,14 @@ namespace Barotrauma
|
|||||||
|
|
||||||
for (int k = 0; k < properties.Count; k++)
|
for (int k = 0; k < properties.Count; k++)
|
||||||
{
|
{
|
||||||
allProperties.Add(new Pair<object, SerializableProperty>(entity, properties[k]));
|
allProperties.Add((entity, properties[k]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < allProperties.Count; j++)
|
for (int j = 0; j < allProperties.Count; j++)
|
||||||
{
|
{
|
||||||
var property = allProperties[j].Second;
|
var property = allProperties[j].property;
|
||||||
string propertyName = (allProperties[j].First.GetType().Name + "." + property.PropertyInfo.Name).ToLowerInvariant();
|
string propertyName = (allProperties[j].obj.GetType().Name + "." + property.PropertyInfo.Name).ToLowerInvariant();
|
||||||
LocalizedString displayName = TextManager.Get($"sp.{propertyName}.name");
|
LocalizedString displayName = TextManager.Get($"sp.{propertyName}.name");
|
||||||
if (displayName.IsNullOrEmpty())
|
if (displayName.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ namespace Barotrauma
|
|||||||
public TextGetterHandler TextGetter;
|
public TextGetterHandler TextGetter;
|
||||||
|
|
||||||
public bool Wrap;
|
public bool Wrap;
|
||||||
private bool playerInput;
|
|
||||||
|
|
||||||
public bool RoundToNearestPixel = true;
|
public bool RoundToNearestPixel = true;
|
||||||
|
|
||||||
@@ -287,8 +286,7 @@ namespace Barotrauma
|
|||||||
/// If the rectT height is set 0, the height is calculated from the text.
|
/// If the rectT height is set 0, the height is calculated from the text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GUITextBlock(RectTransform rectT, RichString text, Color? textColor = null, GUIFont font = null,
|
public GUITextBlock(RectTransform rectT, RichString text, Color? textColor = null, GUIFont font = null,
|
||||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null,
|
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null)
|
||||||
bool playerInput = false)
|
|
||||||
: base(style, rectT)
|
: base(style, rectT)
|
||||||
{
|
{
|
||||||
if (color.HasValue)
|
if (color.HasValue)
|
||||||
@@ -307,7 +305,6 @@ namespace Barotrauma
|
|||||||
this.textAlignment = textAlignment;
|
this.textAlignment = textAlignment;
|
||||||
this.Wrap = wrap;
|
this.Wrap = wrap;
|
||||||
this.Text = text ?? "";
|
this.Text = text ?? "";
|
||||||
this.playerInput = playerInput;
|
|
||||||
if (rectT.Rect.Height == 0 && !text.IsNullOrEmpty())
|
if (rectT.Rect.Height == 0 && !text.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
CalculateHeightFromText();
|
CalculateHeightFromText();
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ namespace Barotrauma
|
|||||||
this.color = color ?? Color.White;
|
this.color = color ?? Color.White;
|
||||||
frame = new GUIFrame(new RectTransform(Vector2.One, rectT, Anchor.Center), style, color);
|
frame = new GUIFrame(new RectTransform(Vector2.One, rectT, Anchor.Center), style, color);
|
||||||
GUIStyle.Apply(frame, style == "" ? "GUITextBox" : style);
|
GUIStyle.Apply(frame, style == "" ? "GUITextBox" : style);
|
||||||
textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.CenterLeft), text ?? "", textColor, font, textAlignment, wrap, playerInput: true);
|
textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.CenterLeft), text ?? "", textColor, font, textAlignment, wrap);
|
||||||
GUIStyle.Apply(textBlock, "", this);
|
GUIStyle.Apply(textBlock, "", this);
|
||||||
if (font != null) { textBlock.Font = font; }
|
if (font != null) { textBlock.Font = font; }
|
||||||
CaretEnabled = true;
|
CaretEnabled = true;
|
||||||
|
|||||||
@@ -657,6 +657,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
|
|
||||||
GUILayoutGroup parentLayout = new GUILayoutGroup(new RectTransform(Vector2.One, backgroundFrame.RectTransform), isHorizontal: true) { Stretch = true };
|
GUILayoutGroup parentLayout = new GUILayoutGroup(new RectTransform(Vector2.One, backgroundFrame.RectTransform), isHorizontal: true) { Stretch = true };
|
||||||
|
|
||||||
if (!(affliction.Prefab is { } prefab)) { return; }
|
if (!(affliction.Prefab is { } prefab)) { return; }
|
||||||
@@ -676,7 +677,7 @@ namespace Barotrauma
|
|||||||
GUIFrame textContainer = new GUIFrame(new RectTransform(new Vector2(0.6f, 1f), textLayout.RectTransform), style: null);
|
GUIFrame textContainer = new GUIFrame(new RectTransform(new Vector2(0.6f, 1f), textLayout.RectTransform), style: null);
|
||||||
GUITextBlock afflictionName = new GUITextBlock(new RectTransform(Vector2.One, textContainer.RectTransform), name, font: GUIStyle.SubHeadingFont);
|
GUITextBlock afflictionName = new GUITextBlock(new RectTransform(Vector2.One, textContainer.RectTransform), name, font: GUIStyle.SubHeadingFont);
|
||||||
|
|
||||||
GUITextBlock healCost = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1f), textLayout.RectTransform), TextManager.FormatCurrency(affliction.Price), textAlignment: Alignment.Center, font: GUIStyle.LargeFont)
|
GUITextBlock healCost = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1f), textLayout.RectTransform), TextManager.FormatCurrency(affliction.Price), textAlignment: Alignment.Center, font: GUIStyle.SubHeadingFont)
|
||||||
{
|
{
|
||||||
Padding = Vector4.Zero
|
Padding = Vector4.Zero
|
||||||
};
|
};
|
||||||
@@ -746,12 +747,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
ClosePopup();
|
ClosePopup();
|
||||||
|
|
||||||
GUIFrame mainFrame = new GUIFrame(new RectTransform(new Vector2(0.28f, 0.45f), container.RectTransform)
|
GUIFrame mainFrame = new GUIFrame(new RectTransform(new Vector2(0.28f, 0.5f), container.RectTransform)
|
||||||
{
|
{
|
||||||
ScreenSpaceOffset = location.ToPoint()
|
ScreenSpaceOffset = location.ToPoint()
|
||||||
});
|
});
|
||||||
|
|
||||||
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f), mainFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.01f, Stretch = true };
|
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), mainFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.01f, Stretch = true };
|
||||||
|
|
||||||
if (mainFrame.Rect.Bottom > GameMain.GraphicsHeight)
|
if (mainFrame.Rect.Bottom > GameMain.GraphicsHeight)
|
||||||
{
|
{
|
||||||
@@ -819,7 +820,9 @@ namespace Barotrauma
|
|||||||
if (!(affliction.Prefab is { } prefab)) { return ImmutableArray<GUIComponent>.Empty; }
|
if (!(affliction.Prefab is { } prefab)) { return ImmutableArray<GUIComponent>.Empty; }
|
||||||
|
|
||||||
GUIFrame backgroundFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.33f), parent.RectTransform), style: "ListBoxElement");
|
GUIFrame backgroundFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.33f), parent.RectTransform), style: "ListBoxElement");
|
||||||
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f), backgroundFrame.RectTransform, Anchor.Center))
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), backgroundFrame.RectTransform, Anchor.BottomCenter), style: "HorizontalLine");
|
||||||
|
|
||||||
|
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), backgroundFrame.RectTransform, Anchor.Center))
|
||||||
{
|
{
|
||||||
RelativeSpacing = 0.05f
|
RelativeSpacing = 0.05f
|
||||||
};
|
};
|
||||||
@@ -862,13 +865,27 @@ namespace Barotrauma
|
|||||||
|
|
||||||
GUILayoutGroup bottomLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.66f), mainLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
GUILayoutGroup bottomLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.66f), mainLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||||
|
|
||||||
GUILayoutGroup bottomTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1f), bottomLayout.RectTransform));
|
GUILayoutGroup bottomTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1f), bottomLayout.RectTransform))
|
||||||
GUITextBlock descriptionBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), bottomTextLayout.RectTransform), ToolBox.LimitString(prefab.Description, GUIStyle.Font, GUI.IntScale(64)), wrap: true)
|
{
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
GUITextBlock descriptionBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.6f), bottomTextLayout.RectTransform), prefab.Description, font: GUIStyle.SmallFont, wrap: true)
|
||||||
{
|
{
|
||||||
ToolTip = prefab.Description
|
ToolTip = prefab.Description
|
||||||
};
|
};
|
||||||
|
bool truncated = false;
|
||||||
|
while (descriptionBlock.TextSize.Y > descriptionBlock.Rect.Height && descriptionBlock.WrappedText.Contains('\n'))
|
||||||
|
{
|
||||||
|
var split = descriptionBlock.WrappedText.Value.Split('\n');
|
||||||
|
descriptionBlock.Text = string.Join('\n', split.Take(split.Length - 1));
|
||||||
|
truncated = true;
|
||||||
|
}
|
||||||
|
if (truncated)
|
||||||
|
{
|
||||||
|
descriptionBlock.Text += "...";
|
||||||
|
}
|
||||||
|
|
||||||
GUITextBlock priceBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), bottomTextLayout.RectTransform), TextManager.FormatCurrency(affliction.Price), font: GUIStyle.LargeFont);
|
GUITextBlock priceBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.25f), bottomTextLayout.RectTransform), TextManager.FormatCurrency(affliction.Price), font: GUIStyle.SubHeadingFont);
|
||||||
|
|
||||||
GUIButton buyButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.75f), bottomLayout.RectTransform), style: "CrewManagementAddButton");
|
GUIButton buyButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.75f), bottomLayout.RectTransform), style: "CrewManagementAddButton");
|
||||||
|
|
||||||
@@ -923,6 +940,7 @@ namespace Barotrauma
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#warning TODO: this doesn't seem like the right place for this, and it's not clear from the method signature how this differs from ToolBox.LimitString
|
||||||
public static void EnsureTextDoesntOverflow(string? text, GUITextBlock textBlock, Rectangle bounds, ImmutableArray<GUILayoutGroup>? layoutGroups = null)
|
public static void EnsureTextDoesntOverflow(string? text, GUITextBlock textBlock, Rectangle bounds, ImmutableArray<GUILayoutGroup>? layoutGroups = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(text)) { return; }
|
if (string.IsNullOrWhiteSpace(text)) { return; }
|
||||||
|
|||||||
@@ -46,9 +46,7 @@ namespace Barotrauma
|
|||||||
private int buyTotal, sellTotal, sellFromSubTotal;
|
private int buyTotal, sellTotal, sellFromSubTotal;
|
||||||
|
|
||||||
private GUITextBlock storeNameBlock;
|
private GUITextBlock storeNameBlock;
|
||||||
private GUITextBlock merchantBalanceBlock;
|
private GUITextBlock reputationEffectBlock;
|
||||||
private GUITextBlock currentSellValueBlock, newSellValueBlock;
|
|
||||||
private GUIImage sellValueChangeArrow;
|
|
||||||
private GUIDropDown sortingDropDown;
|
private GUIDropDown sortingDropDown;
|
||||||
private GUITextBox searchBox;
|
private GUITextBox searchBox;
|
||||||
private GUILayoutGroup categoryButtonContainer;
|
private GUILayoutGroup categoryButtonContainer;
|
||||||
@@ -376,41 +374,29 @@ namespace Barotrauma
|
|||||||
AutoScaleVertical = true,
|
AutoScaleVertical = true,
|
||||||
ForceUpperCase = ForceUpperCase.Yes
|
ForceUpperCase = ForceUpperCase.Yes
|
||||||
};
|
};
|
||||||
merchantBalanceBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), merchantBalanceContainer.RectTransform),
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), merchantBalanceContainer.RectTransform), "",
|
||||||
"", font: GUIStyle.SubHeadingFont)
|
color: Color.White, font: GUIStyle.SubHeadingFont)
|
||||||
{
|
{
|
||||||
AutoScaleVertical = true,
|
AutoScaleVertical = true,
|
||||||
TextScale = 1.1f,
|
TextScale = 1.1f,
|
||||||
TextGetter = () =>
|
TextGetter = () => GetMerchantBalanceText()
|
||||||
{
|
|
||||||
merchantBalanceBlock.TextColor = ActiveStore?.BalanceColor ?? Color.Red;
|
|
||||||
return GetMerchantBalanceText();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Item sell value ------------------------------------------------
|
// Item sell value ------------------------------------------------
|
||||||
var sellValueContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), balanceAndValueGroup.RectTransform))
|
var reputationEffectContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), balanceAndValueGroup.RectTransform))
|
||||||
{
|
{
|
||||||
CanBeFocused = true,
|
CanBeFocused = true,
|
||||||
RelativeSpacing = 0.005f
|
RelativeSpacing = 0.005f,
|
||||||
|
ToolTip = TextManager.Get("campaignstore.reputationtooltip")
|
||||||
};
|
};
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), sellValueContainer.RectTransform),
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), reputationEffectContainer.RectTransform),
|
||||||
TextManager.Get("campaignstore.sellvalue"), font: GUIStyle.Font, textAlignment: Alignment.BottomLeft)
|
TextManager.Get("reputation"), font: GUIStyle.Font, textAlignment: Alignment.BottomLeft)
|
||||||
{
|
{
|
||||||
AutoScaleVertical = true,
|
AutoScaleVertical = true,
|
||||||
CanBeFocused = false,
|
CanBeFocused = false,
|
||||||
ForceUpperCase = ForceUpperCase.Yes
|
ForceUpperCase = ForceUpperCase.Yes,
|
||||||
};
|
};
|
||||||
|
reputationEffectBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), reputationEffectContainer.RectTransform), "", font: GUIStyle.SubHeadingFont)
|
||||||
var valueChangeGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), sellValueContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
|
||||||
{
|
|
||||||
CanBeFocused = false,
|
|
||||||
RelativeSpacing = 0.02f
|
|
||||||
};
|
|
||||||
float blockWidth = GUI.IsFourByThree() ? 0.32f : 0.28f;
|
|
||||||
Point blockMaxSize = new Point((int)(GameSettings.CurrentConfig.Graphics.TextScale * 60), valueChangeGroup.Rect.Height);
|
|
||||||
currentSellValueBlock = new GUITextBlock(new RectTransform(new Vector2(blockWidth, 1.0f), valueChangeGroup.RectTransform) { MaxSize = blockMaxSize },
|
|
||||||
"", font: GUIStyle.SubHeadingFont)
|
|
||||||
{
|
{
|
||||||
AutoScaleVertical = true,
|
AutoScaleVertical = true,
|
||||||
CanBeFocused = false,
|
CanBeFocused = false,
|
||||||
@@ -419,64 +405,27 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (CurrentLocation != null)
|
if (CurrentLocation != null)
|
||||||
{
|
{
|
||||||
int balanceAfterTransaction = activeTab switch
|
Color textColor = GUIStyle.ColorReputationNeutral;
|
||||||
|
string sign = "";
|
||||||
|
int reputationModifier = (int)MathF.Round((CurrentLocation.GetStoreReputationModifier(activeTab == StoreTab.Buy) - 1) * 100);
|
||||||
|
if (reputationModifier > 0)
|
||||||
{
|
{
|
||||||
StoreTab.Buy => ActiveStore.Balance + buyTotal,
|
textColor = IsBuying ? GUIStyle.ColorReputationLow : GUIStyle.ColorReputationHigh;
|
||||||
StoreTab.Sell => ActiveStore.Balance - sellTotal,
|
sign = "+";
|
||||||
StoreTab.SellSub => ActiveStore.Balance - sellFromSubTotal,
|
|
||||||
_ => throw new NotImplementedException(),
|
|
||||||
};
|
|
||||||
if (balanceAfterTransaction != ActiveStore.Balance)
|
|
||||||
{
|
|
||||||
var newStatus = CurrentLocation.GetStoreBalanceStatus(balanceAfterTransaction);
|
|
||||||
if (ActiveStore.ActiveBalanceStatus.SellPriceModifier != newStatus.SellPriceModifier)
|
|
||||||
{
|
|
||||||
string tooltipTag = newStatus.SellPriceModifier > ActiveStore.ActiveBalanceStatus.SellPriceModifier ?
|
|
||||||
"campaingstore.valueincreasetooltip" : "campaingstore.valuedecreasetooltip";
|
|
||||||
sellValueContainer.ToolTip = TextManager.Get(tooltipTag);
|
|
||||||
currentSellValueBlock.TextColor = newStatus.Color;
|
|
||||||
sellValueChangeArrow.Color = newStatus.Color;
|
|
||||||
sellValueChangeArrow.Visible = true;
|
|
||||||
newSellValueBlock.TextColor = newStatus.Color;
|
|
||||||
newSellValueBlock.Text = $"{(newStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
|
||||||
return $"{(ActiveStore.ActiveBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sellValueContainer.ToolTip = TextManager.Get("campaignstore.sellvaluetooltip");
|
else if (reputationModifier < 0)
|
||||||
currentSellValueBlock.TextColor = ActiveStore.BalanceColor;
|
{
|
||||||
sellValueChangeArrow.Visible = false;
|
textColor = IsBuying ? GUIStyle.ColorReputationHigh : GUIStyle.ColorReputationLow;
|
||||||
newSellValueBlock.Text = null;
|
}
|
||||||
return $"{(ActiveStore.ActiveBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
reputationEffectBlock.TextColor = textColor;
|
||||||
|
return $"{sign}{reputationModifier}%";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sellValueContainer.ToolTip = null;
|
return "";
|
||||||
sellValueChangeArrow.Visible = false;
|
|
||||||
newSellValueBlock.Text = null;
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Vector4 newPadding = currentSellValueBlock.Padding;
|
|
||||||
newPadding.Z = 0;
|
|
||||||
currentSellValueBlock.Padding = newPadding;
|
|
||||||
float relativeHeight = 0.45f;
|
|
||||||
float relativeWidth = (relativeHeight * valueChangeGroup.Rect.Height) / valueChangeGroup.Rect.Width;
|
|
||||||
sellValueChangeArrow = new GUIImage(new RectTransform(new Vector2(relativeWidth, relativeHeight), valueChangeGroup.RectTransform), "StoreArrow", scaleToFit: true)
|
|
||||||
{
|
|
||||||
CanBeFocused = false,
|
|
||||||
Visible = false
|
|
||||||
};
|
|
||||||
newSellValueBlock = new GUITextBlock(new RectTransform(new Vector2(blockWidth, 1.0f), valueChangeGroup.RectTransform) { MaxSize = blockMaxSize },
|
|
||||||
"", font: GUIStyle.SubHeadingFont)
|
|
||||||
{
|
|
||||||
AutoScaleVertical = true,
|
|
||||||
CanBeFocused = false,
|
|
||||||
TextScale = 1.1f
|
|
||||||
};
|
|
||||||
newPadding = newSellValueBlock.Padding;
|
|
||||||
newPadding.X = 0;
|
|
||||||
newSellValueBlock.Padding = newPadding;
|
|
||||||
|
|
||||||
// Store mode buttons ------------------------------------------------
|
// Store mode buttons ------------------------------------------------
|
||||||
var modeButtonFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.4f / 14.0f), storeContent.RectTransform), style: null);
|
var modeButtonFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.4f / 14.0f), storeContent.RectTransform), style: null);
|
||||||
|
|||||||
@@ -626,7 +626,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (GameMain.Client == null)
|
if (GameMain.Client == null)
|
||||||
{
|
{
|
||||||
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(selectedSubmarine, deliveryFee);
|
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, deliveryFee);
|
||||||
RefreshSubmarineDisplay(true);
|
RefreshSubmarineDisplay(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -664,7 +664,7 @@ namespace Barotrauma
|
|||||||
if (GameMain.Client == null)
|
if (GameMain.Client == null)
|
||||||
{
|
{
|
||||||
GameMain.GameSession.PurchaseSubmarine(selectedSubmarine);
|
GameMain.GameSession.PurchaseSubmarine(selectedSubmarine);
|
||||||
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(selectedSubmarine, 0);
|
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, 0);
|
||||||
RefreshSubmarineDisplay(true);
|
RefreshSubmarineDisplay(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -54,47 +54,65 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private ushort currentPing;
|
private ushort currentPing;
|
||||||
private readonly Character character;
|
private readonly Character character;
|
||||||
private readonly bool hasCharacter;
|
private readonly bool wasCharacterAlive;
|
||||||
private readonly GUITextBlock textBlock;
|
private readonly GUITextBlock textBlock;
|
||||||
private readonly GUIFrame frame;
|
private readonly GUIFrame frame;
|
||||||
|
|
||||||
private readonly GUIImage permissionIcon;
|
private readonly GUIImage permissionIcon;
|
||||||
|
|
||||||
public LinkedGUI(Client client, GUIFrame frame, bool hasCharacter, GUITextBlock textBlock, GUIImage permissionIcon)
|
public LinkedGUI(Client client, GUIFrame frame, GUITextBlock textBlock, GUIImage permissionIcon)
|
||||||
{
|
{
|
||||||
this.Client = client;
|
this.Client = client;
|
||||||
this.textBlock = textBlock;
|
this.textBlock = textBlock;
|
||||||
this.frame = frame;
|
this.frame = frame;
|
||||||
this.hasCharacter = hasCharacter;
|
|
||||||
this.permissionIcon = permissionIcon;
|
this.permissionIcon = permissionIcon;
|
||||||
|
character = client?.Character;
|
||||||
|
wasCharacterAlive = client.Character != null && !client.Character.IsDead;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LinkedGUI(Character character, GUIFrame frame, bool hasCharacter, GUITextBlock textBlock)
|
public LinkedGUI(Character character, GUIFrame frame, GUITextBlock textBlock)
|
||||||
{
|
{
|
||||||
this.character = character;
|
this.character = character;
|
||||||
this.textBlock = textBlock;
|
this.textBlock = textBlock;
|
||||||
this.frame = frame;
|
this.frame = frame;
|
||||||
this.hasCharacter = hasCharacter;
|
wasCharacterAlive = character != null && !character.IsDead;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasMultiplayerCharacterChanged()
|
public bool HasMultiplayerCharacterChanged()
|
||||||
{
|
{
|
||||||
if (Client == null) { return false; }
|
if (Client == null) { return false; }
|
||||||
bool characterState = Client.Character != null;
|
|
||||||
if (characterState && Client.Character.IsDead) characterState = false;
|
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||||
return hasCharacter != characterState;
|
{
|
||||||
|
if (Client.Character != character)
|
||||||
|
{
|
||||||
|
DebugConsole.Log($"Refreshing tab menu crew list (client \"{Client.Name}\"'s character changed from \"{character?.Name ?? "null"}\" to \"{Client.Character?.Name ?? "null"}\")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Client.Character != character;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasMultiplayerCharacterDied()
|
public bool HasCharacterDied()
|
||||||
{
|
|
||||||
if (Client == null || !hasCharacter || Client.Character == null) { return false; }
|
|
||||||
return Client.Character.IsDead;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasAICharacterDied()
|
|
||||||
{
|
{
|
||||||
if (character == null) { return false; }
|
if (character == null) { return false; }
|
||||||
return character.IsDead;
|
bool isAlive = !(character?.IsDead ?? true);
|
||||||
|
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||||
|
{
|
||||||
|
if (wasCharacterAlive && !isAlive)
|
||||||
|
{
|
||||||
|
DebugConsole.Log(Client == null ?
|
||||||
|
$"Refreshing tab menu crew list (character \"{character?.Name ?? "null"}\" died)" :
|
||||||
|
$"Refreshing tab menu crew list (client \"{Client.Name}\"'s character \"{character?.Name ?? "null"}\" died)");
|
||||||
|
}
|
||||||
|
else if (!wasCharacterAlive && isAlive)
|
||||||
|
{
|
||||||
|
DebugConsole.Log(Client == null ?
|
||||||
|
|
||||||
|
$"Refreshing tab menu crew list (character \"{character?.Name ?? "null"}\" came back to life)" :
|
||||||
|
$"Refreshing tab menu crew list (client \"{Client.Name}\"'s character \"{character?.Name ?? "null"}\" came back to life)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isAlive != wasCharacterAlive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TryPingRefresh()
|
public void TryPingRefresh()
|
||||||
@@ -207,7 +225,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
linkedGUIList[i].TryPingRefresh();
|
linkedGUIList[i].TryPingRefresh();
|
||||||
linkedGUIList[i].TryPermissionIconRefresh(GetPermissionIcon(linkedGUIList[i].Client));
|
linkedGUIList[i].TryPermissionIconRefresh(GetPermissionIcon(linkedGUIList[i].Client));
|
||||||
if (linkedGUIList[i].HasMultiplayerCharacterChanged() || linkedGUIList[i].HasMultiplayerCharacterDied() || linkedGUIList[i].HasAICharacterDied())
|
if (linkedGUIList[i].HasMultiplayerCharacterChanged() || linkedGUIList[i].HasCharacterDied())
|
||||||
{
|
{
|
||||||
RemoveCurrentElements();
|
RemoveCurrentElements();
|
||||||
CreateMultiPlayerList(true);
|
CreateMultiPlayerList(true);
|
||||||
@@ -219,10 +237,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < linkedGUIList.Count; i++)
|
for (int i = 0; i < linkedGUIList.Count; i++)
|
||||||
{
|
{
|
||||||
if (linkedGUIList[i].HasAICharacterDied())
|
if (linkedGUIList[i].HasCharacterDied())
|
||||||
{
|
{
|
||||||
RemoveCurrentElements();
|
RemoveCurrentElements();
|
||||||
CreateSinglePlayerList(true);
|
CreateSinglePlayerList(true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,6 +316,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
var balanceFrame = new GUIFrame(new RectTransform(new Point(innerLayoutGroup.Rect.Width, innerLayoutGroup.Rect.Height - infoFrameHolderHeight), parent: innerLayoutGroup.RectTransform), style: "InnerFrame");
|
var balanceFrame = new GUIFrame(new RectTransform(new Point(innerLayoutGroup.Rect.Width, innerLayoutGroup.Rect.Height - infoFrameHolderHeight), parent: innerLayoutGroup.RectTransform), style: "InnerFrame");
|
||||||
GUITextBlock balanceText = new GUITextBlock(new RectTransform(Vector2.One, balanceFrame.RectTransform), string.Empty, textAlignment: Alignment.Right);
|
GUITextBlock balanceText = new GUITextBlock(new RectTransform(Vector2.One, balanceFrame.RectTransform), string.Empty, textAlignment: Alignment.Right);
|
||||||
|
if (GameMain.IsMultiplayer)
|
||||||
|
{
|
||||||
|
balanceText.ToolTip = TextManager.Get("bankdescription");
|
||||||
|
}
|
||||||
GUIFrame bottomDisclaimerFrame = new GUIFrame(new RectTransform(new Vector2(contentFrameSize.X, 0.1f), infoFrame.RectTransform)
|
GUIFrame bottomDisclaimerFrame = new GUIFrame(new RectTransform(new Vector2(contentFrameSize.X, 0.1f), infoFrame.RectTransform)
|
||||||
{
|
{
|
||||||
AbsoluteOffset = new Point(contentFrame.Rect.X, contentFrame.Rect.Bottom + GUI.IntScale(8))
|
AbsoluteOffset = new Point(contentFrame.Rect.X, contentFrame.Rect.Bottom + GUI.IntScale(8))
|
||||||
@@ -337,7 +360,7 @@ namespace Barotrauma
|
|||||||
var talentsButton = createTabButton(InfoFrameTab.Talents, "tabmenu.character");
|
var talentsButton = createTabButton(InfoFrameTab.Talents, "tabmenu.character");
|
||||||
talentsButton.OnAddedToGUIUpdateList += (component) =>
|
talentsButton.OnAddedToGUIUpdateList += (component) =>
|
||||||
{
|
{
|
||||||
talentsButton.Enabled = Character.Controlled?.Info != null;
|
talentsButton.Enabled = Character.Controlled?.Info != null || (GameMain.Client?.CharacterInfo != null && GameMain.GameSession?.GameMode is MultiPlayerCampaign);
|
||||||
if (!talentsButton.Enabled && selectedTab == InfoFrameTab.Talents)
|
if (!talentsButton.Enabled && selectedTab == InfoFrameTab.Talents)
|
||||||
{
|
{
|
||||||
SelectInfoFrameTab(InfoFrameTab.Crew);
|
SelectInfoFrameTab(InfoFrameTab.Crew);
|
||||||
@@ -560,7 +583,7 @@ namespace Barotrauma
|
|||||||
GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
|
GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
|
||||||
ToolBox.LimitString(character.Info.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: character.Info.Job.Prefab.UIColor);
|
ToolBox.LimitString(character.Info.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: character.Info.Job.Prefab.UIColor);
|
||||||
|
|
||||||
linkedGUIList.Add(new LinkedGUI(character, frame, !character.IsDead, textBlock: null));
|
linkedGUIList.Add(new LinkedGUI(character, frame, textBlock: null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateMultiPlayerListContentHolder(GUILayoutGroup headerFrame)
|
private void CreateMultiPlayerListContentHolder(GUILayoutGroup headerFrame)
|
||||||
@@ -657,7 +680,7 @@ namespace Barotrauma
|
|||||||
if (client != null)
|
if (client != null)
|
||||||
{
|
{
|
||||||
CreateNameWithPermissionIcon(client, paddedFrame, out GUIImage permissionIcon);
|
CreateNameWithPermissionIcon(client, paddedFrame, out GUIImage permissionIcon);
|
||||||
linkedGUIList.Add(new LinkedGUI(client, frame, true,
|
linkedGUIList.Add(new LinkedGUI(client, frame,
|
||||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center),
|
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center),
|
||||||
permissionIcon));
|
permissionIcon));
|
||||||
}
|
}
|
||||||
@@ -668,12 +691,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (character is AICharacter)
|
if (character is AICharacter)
|
||||||
{
|
{
|
||||||
linkedGUIList.Add(new LinkedGUI(character, frame, !character.IsDead,
|
linkedGUIList.Add(new LinkedGUI(character, frame,
|
||||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), TextManager.Get("tabmenu.bot"), textAlignment: Alignment.Center) { ForceUpperCase = ForceUpperCase.Yes }));
|
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), TextManager.Get("tabmenu.bot"), textAlignment: Alignment.Center) { ForceUpperCase = ForceUpperCase.Yes }));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
linkedGUIList.Add(new LinkedGUI(client: null, frame, true, textBlock: null, permissionIcon: null));
|
linkedGUIList.Add(new LinkedGUI(client: null, frame, textBlock: null, permissionIcon: null));
|
||||||
|
|
||||||
new GUICustomComponent(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => DrawDisconnectedIcon(sb, component.Rect))
|
new GUICustomComponent(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => DrawDisconnectedIcon(sb, component.Rect))
|
||||||
{
|
{
|
||||||
@@ -718,7 +741,7 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
|
|
||||||
CreateNameWithPermissionIcon(client, paddedFrame, out GUIImage permissionIcon);
|
CreateNameWithPermissionIcon(client, paddedFrame, out GUIImage permissionIcon);
|
||||||
linkedGUIList.Add(new LinkedGUI(client, frame, false,
|
linkedGUIList.Add(new LinkedGUI(client, frame,
|
||||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center),
|
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center),
|
||||||
permissionIcon));
|
permissionIcon));
|
||||||
|
|
||||||
@@ -775,19 +798,27 @@ namespace Barotrauma
|
|||||||
Stretch = true
|
Stretch = true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
new GUIFrame(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform), style: null)
|
||||||
|
{
|
||||||
|
IgnoreLayoutGroups = true,
|
||||||
|
ToolTip = TextManager.Get("walletdescription")
|
||||||
|
};
|
||||||
|
|
||||||
if (character.IsBot) { return; }
|
if (character.IsBot) { return; }
|
||||||
|
|
||||||
Sprite walletSprite = GUIStyle.CrewWalletIconSmall.Value.Sprite;
|
Sprite walletSprite = GUIStyle.CrewWalletIconSmall.Value.Sprite;
|
||||||
|
|
||||||
GUIImage icon = new GUIImage(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform, scaleBasis: ScaleBasis.BothHeight), walletSprite, scaleToFit: true);
|
GUIImage icon = new GUIImage(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform, scaleBasis: ScaleBasis.BothHeight), walletSprite, scaleToFit: true) { CanBeFocused = false };
|
||||||
GUITextBlock walletBlock = new GUITextBlock(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform), string.Empty, textAlignment: Alignment.Right, font: GUIStyle.Font)
|
GUITextBlock walletBlock = new GUITextBlock(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform), string.Empty, textAlignment: Alignment.Right, font: GUIStyle.Font)
|
||||||
{
|
{
|
||||||
AutoScaleHorizontal = true,
|
AutoScaleHorizontal = true,
|
||||||
Padding = Vector4.Zero
|
Padding = Vector4.Zero,
|
||||||
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
|
|
||||||
GUIImage largeIcon = new GUIImage(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform), walletSprite, scaleToFit: true)
|
GUIImage largeIcon = new GUIImage(new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform), walletSprite, scaleToFit: true)
|
||||||
{
|
{
|
||||||
|
CanBeFocused = false,
|
||||||
IgnoreLayoutGroups = true,
|
IgnoreLayoutGroups = true,
|
||||||
Visible = false
|
Visible = false
|
||||||
};
|
};
|
||||||
@@ -971,16 +1002,25 @@ namespace Barotrauma
|
|||||||
float relativeX = icon.RectTransform.NonScaledSize.X / (float)icon.Parent.RectTransform.NonScaledSize.X;
|
float relativeX = icon.RectTransform.NonScaledSize.X / (float)icon.Parent.RectTransform.NonScaledSize.X;
|
||||||
GUILayoutGroup headerTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - relativeX, 1f), headerLayout.RectTransform), isHorizontal: true) { Stretch = true };
|
GUILayoutGroup headerTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - relativeX, 1f), headerLayout.RectTransform), isHorizontal: true) { Stretch = true };
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.Get("crewwallet.wallet"), font: GUIStyle.LargeFont);
|
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.Get("crewwallet.wallet"), font: GUIStyle.LargeFont);
|
||||||
|
GUIFrame walletTooltipFrame = new GUIFrame(new RectTransform(Vector2.One, headerLayout.RectTransform), style: null)
|
||||||
|
{
|
||||||
|
IgnoreLayoutGroups = true,
|
||||||
|
ToolTip = TextManager.Get("walletdescription")
|
||||||
|
};
|
||||||
GUITextBlock moneyBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.FormatCurrency(targetWallet.Balance), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right);
|
GUITextBlock moneyBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.FormatCurrency(targetWallet.Balance), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right);
|
||||||
|
|
||||||
GUILayoutGroup middleLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.66f), walletLayout.RectTransform));
|
GUILayoutGroup middleLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.66f), walletLayout.RectTransform));
|
||||||
GUILayoutGroup salaryTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true);
|
GUILayoutGroup salaryTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true);
|
||||||
GUITextBlock salaryTitle = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.Get("crewwallet.salary"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft);
|
GUITextBlock salaryTitle = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.Get("crewwallet.salary"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft);
|
||||||
GUITextBlock rewardBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), string.Empty, textAlignment: Alignment.BottomRight);
|
GUITextBlock rewardBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), string.Empty, textAlignment: Alignment.BottomRight);
|
||||||
|
GUIFrame salaryTooltipFrame = new GUIFrame(new RectTransform(Vector2.One, middleLayout.RectTransform), style: null)
|
||||||
|
{
|
||||||
|
IgnoreLayoutGroups = true,
|
||||||
|
ToolTip = TextManager.Get("crewwallet.salary.tooltip")
|
||||||
|
};
|
||||||
GUILayoutGroup sliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.Center);
|
GUILayoutGroup sliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.Center);
|
||||||
GUIScrollBar salarySlider = new GUIScrollBar(new RectTransform(new Vector2(0.9f, 1f), sliderLayout.RectTransform), style: "GUISlider", barSize: 0.03f)
|
GUIScrollBar salarySlider = new GUIScrollBar(new RectTransform(new Vector2(0.9f, 1f), sliderLayout.RectTransform), style: "GUISlider", barSize: 0.03f)
|
||||||
{
|
{
|
||||||
ToolTip = TextManager.Get("crewwallet.salary.tooltip"),
|
|
||||||
Range = new Vector2(0, 1),
|
Range = new Vector2(0, 1),
|
||||||
BarScrollValue = targetWallet.RewardDistribution / 100f,
|
BarScrollValue = targetWallet.RewardDistribution / 100f,
|
||||||
Step = 0.01f,
|
Step = 0.01f,
|
||||||
@@ -1050,149 +1090,195 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Identifier eventIdentifier = nameof(CreateWalletFrame).ToIdentifier();
|
||||||
|
|
||||||
ToggleTransferMenuIcon(transferMenuButton, open: isTransferMenuOpen);
|
ToggleTransferMenuIcon(transferMenuButton, open: isTransferMenuOpen);
|
||||||
ToggleCenterButton(centerButton, isSending);
|
ToggleCenterButton(centerButton, isSending);
|
||||||
|
|
||||||
|
|
||||||
if (!(Character.Controlled is { } myCharacter))
|
|
||||||
{
|
|
||||||
salarySlider.Enabled = false;
|
|
||||||
transferAmountInput.Enabled = false;
|
|
||||||
centerButton.Enabled = false;
|
|
||||||
confirmButton.Enabled = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasMoneyPermissions = CampaignMode.AllowedToManageWallets();
|
|
||||||
salarySlider.Enabled = hasMoneyPermissions;
|
|
||||||
Wallet otherWallet;
|
Wallet otherWallet;
|
||||||
|
GameMain.Client?.OnPermissionChanged.RegisterOverwriteExisting(eventIdentifier, e => UpdateWalletInterface(registerEvents: false));
|
||||||
|
UpdateWalletInterface(registerEvents: true);
|
||||||
|
|
||||||
switch (hasMoneyPermissions)
|
void UpdateWalletInterface(bool registerEvents)
|
||||||
{
|
{
|
||||||
case true:
|
if (!(Character.Controlled is { } myCharacter))
|
||||||
rightName.Text = TextManager.Get("crewwallet.bank");
|
|
||||||
otherWallet = campaign.Bank;
|
|
||||||
break;
|
|
||||||
case false when character == myCharacter:
|
|
||||||
rightName.Text = TextManager.Get("crewwallet.bank");
|
|
||||||
otherWallet = campaign.Bank;
|
|
||||||
isSending = true;
|
|
||||||
ToggleCenterButton(centerButton, isSending);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rightName.Text = myCharacter.Name;
|
|
||||||
otherWallet = campaign.PersonalWallet;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
MedicalClinicUI.EnsureTextDoesntOverflow(rightName.Text.ToString(), rightName, rightLayout.Rect, layoutGroups);
|
|
||||||
updateButtonText();
|
|
||||||
if (!hasMoneyPermissions)
|
|
||||||
{
|
|
||||||
if (character != Character.Controlled)
|
|
||||||
{
|
{
|
||||||
centerButton.Enabled = centerButton.CanBeFocused = false;
|
salarySlider.Enabled = false;
|
||||||
|
transferAmountInput.Enabled = false;
|
||||||
|
centerButton.Enabled = false;
|
||||||
|
confirmButton.Enabled = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
salarySlider.Enabled = salarySlider.CanBeFocused = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
leftBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
|
bool hasMoneyPermissions = CampaignMode.AllowedToManageWallets();
|
||||||
|
salarySlider.Enabled = hasMoneyPermissions;
|
||||||
|
|
||||||
UpdateAllInputs();
|
switch (hasMoneyPermissions)
|
||||||
|
{
|
||||||
|
case true:
|
||||||
|
rightName.Text = TextManager.Get("crewwallet.bank");
|
||||||
|
otherWallet = campaign.Bank;
|
||||||
|
break;
|
||||||
|
case false when character == myCharacter:
|
||||||
|
rightName.Text = TextManager.Get("crewwallet.bank");
|
||||||
|
otherWallet = campaign.Bank;
|
||||||
|
isSending = true;
|
||||||
|
ToggleCenterButton(centerButton, isSending);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rightName.Text = myCharacter.Name;
|
||||||
|
otherWallet = campaign.PersonalWallet;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
MedicalClinicUI.EnsureTextDoesntOverflow(rightName.Text.ToString(), rightName, rightLayout.Rect, layoutGroups);
|
||||||
|
|
||||||
|
UpdatedConfirmButtonText();
|
||||||
|
|
||||||
|
if (!hasMoneyPermissions)
|
||||||
|
{
|
||||||
|
if (character != Character.Controlled)
|
||||||
|
{
|
||||||
|
centerButton.Enabled = centerButton.CanBeFocused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
salarySlider.Enabled = salarySlider.CanBeFocused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
leftBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
|
||||||
|
|
||||||
centerButton.OnClicked = (btn, o) =>
|
|
||||||
{
|
|
||||||
isSending = !isSending;
|
|
||||||
updateButtonText();
|
|
||||||
ToggleCenterButton(btn, isSending);
|
|
||||||
UpdateAllInputs();
|
UpdateAllInputs();
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
void updateButtonText()
|
if (!registerEvents) { return; }
|
||||||
{
|
|
||||||
confirmButton.Text = TextManager.Get(hasMoneyPermissions || isSending ? "confirm" : "crewwallet.requestmoney");
|
|
||||||
}
|
|
||||||
|
|
||||||
transferAmountInput.OnValueChanged = input =>
|
centerButton.OnClicked = (btn, o) =>
|
||||||
{
|
|
||||||
UpdateInputs();
|
|
||||||
};
|
|
||||||
|
|
||||||
transferAmountInput.OnValueEntered = input =>
|
|
||||||
{
|
|
||||||
UpdateAllInputs();
|
|
||||||
};
|
|
||||||
|
|
||||||
Identifier eventIdentifier = nameof(CreateWalletFrame).ToIdentifier();
|
|
||||||
campaign.OnMoneyChanged.RegisterOverwriteExisting(eventIdentifier, e =>
|
|
||||||
{
|
|
||||||
if (e.Wallet == targetWallet)
|
|
||||||
{
|
{
|
||||||
moneyBlock.Text = TextManager.FormatCurrency(e.Info.Balance);
|
isSending = !isSending;
|
||||||
salarySlider.BarScrollValue = e.Info.RewardDistribution / 100f;
|
UpdatedConfirmButtonText();
|
||||||
|
ToggleCenterButton(btn, isSending);
|
||||||
|
UpdateAllInputs();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
transferAmountInput.OnValueChanged = input =>
|
||||||
|
{
|
||||||
|
UpdateInputs();
|
||||||
|
};
|
||||||
|
|
||||||
|
transferAmountInput.OnValueEntered = input =>
|
||||||
|
{
|
||||||
|
UpdateAllInputs();
|
||||||
|
};
|
||||||
|
|
||||||
|
resetButton.OnClicked = (button, o) =>
|
||||||
|
{
|
||||||
|
transferAmountInput.IntValue = 0;
|
||||||
|
UpdateAllInputs();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
confirmButton.OnClicked = (button, o) =>
|
||||||
|
{
|
||||||
|
int amount = transferAmountInput.IntValue;
|
||||||
|
if (amount == 0) { return false; }
|
||||||
|
|
||||||
|
Option<Character> target1 = Option<Character>.Some(character),
|
||||||
|
target2 = otherWallet == campaign.Bank ? Option<Character>.None() : Option<Character>.Some(myCharacter);
|
||||||
|
if (isSending) { (target1, target2) = (target2, target1); }
|
||||||
|
|
||||||
|
SendTransaction(target1, target2, amount);
|
||||||
|
isTransferMenuOpen = false;
|
||||||
|
ToggleTransferMenuIcon(transferMenuButton, isTransferMenuOpen);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
campaign.OnMoneyChanged.RegisterOverwriteExisting(eventIdentifier, e =>
|
||||||
|
{
|
||||||
|
if (e.Wallet == targetWallet)
|
||||||
|
{
|
||||||
|
moneyBlock.Text = TextManager.FormatCurrency(e.Info.Balance);
|
||||||
|
salarySlider.BarScrollValue = e.Info.RewardDistribution / 100f;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAllInputs();
|
||||||
|
});
|
||||||
|
|
||||||
|
registeredEvents.Add(eventIdentifier);
|
||||||
|
|
||||||
|
void UpdatedConfirmButtonText()
|
||||||
|
{
|
||||||
|
confirmButton.Text = TextManager.Get(hasMoneyPermissions || isSending ? "confirm" : "crewwallet.requestmoney");
|
||||||
}
|
}
|
||||||
UpdateAllInputs();
|
|
||||||
});
|
|
||||||
registeredEvents.Add(eventIdentifier);
|
|
||||||
|
|
||||||
resetButton.OnClicked = (button, o) =>
|
void UpdateAllInputs()
|
||||||
{
|
|
||||||
transferAmountInput.IntValue = 0;
|
|
||||||
UpdateAllInputs();
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
confirmButton.OnClicked = (button, o) =>
|
|
||||||
{
|
|
||||||
int amount = transferAmountInput.IntValue;
|
|
||||||
if (amount == 0) { return false; }
|
|
||||||
|
|
||||||
Option<Character> target1 = Option<Character>.Some(character),
|
|
||||||
target2 = otherWallet == campaign.Bank ? Option<Character>.None() : Option<Character>.Some(myCharacter);
|
|
||||||
if (isSending) { (target1, target2) = (target2, target1); }
|
|
||||||
|
|
||||||
SendTransaction(target1, target2, amount);
|
|
||||||
isTransferMenuOpen = false;
|
|
||||||
ToggleTransferMenuIcon(transferMenuButton, isTransferMenuOpen);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
void UpdateAllInputs()
|
|
||||||
{
|
|
||||||
UpdateInputs();
|
|
||||||
UpdateMaxInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateInputs()
|
|
||||||
{
|
|
||||||
confirmButton.Enabled = resetButton.Enabled = transferAmountInput.IntValue > 0;
|
|
||||||
if (transferAmountInput.IntValue == 0)
|
|
||||||
{
|
{
|
||||||
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
|
UpdateInputs();
|
||||||
rightBalance.TextColor = GUIStyle.TextColorNormal;
|
UpdateMaxInput();
|
||||||
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance);
|
|
||||||
leftBalance.TextColor = GUIStyle.TextColorNormal;
|
|
||||||
}
|
}
|
||||||
else if (isSending)
|
|
||||||
|
void UpdateInputs()
|
||||||
{
|
{
|
||||||
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance + transferAmountInput.IntValue);
|
confirmButton.Enabled = resetButton.Enabled = transferAmountInput.IntValue > 0;
|
||||||
rightBalance.TextColor = GUIStyle.Blue;
|
if (transferAmountInput.IntValue == 0)
|
||||||
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance - transferAmountInput.IntValue);
|
{
|
||||||
leftBalance.TextColor = GUIStyle.Red;
|
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
|
||||||
|
rightBalance.TextColor = GUIStyle.TextColorNormal;
|
||||||
|
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance);
|
||||||
|
leftBalance.TextColor = GUIStyle.TextColorNormal;
|
||||||
|
}
|
||||||
|
else if (isSending)
|
||||||
|
{
|
||||||
|
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance + transferAmountInput.IntValue);
|
||||||
|
rightBalance.TextColor = GUIStyle.Blue;
|
||||||
|
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance - transferAmountInput.IntValue);
|
||||||
|
leftBalance.TextColor = GUIStyle.Red;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance - transferAmountInput.IntValue);
|
||||||
|
rightBalance.TextColor = GUIStyle.Red;
|
||||||
|
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance + transferAmountInput.IntValue);
|
||||||
|
leftBalance.TextColor = GUIStyle.Blue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
void UpdateMaxInput()
|
||||||
{
|
{
|
||||||
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance - transferAmountInput.IntValue);
|
int maxValue = isSending ? targetWallet.Balance : otherWallet.Balance;
|
||||||
rightBalance.TextColor = GUIStyle.Red;
|
transferAmountInput.MaxValueInt = maxValue;
|
||||||
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance + transferAmountInput.IntValue);
|
|
||||||
leftBalance.TextColor = GUIStyle.Blue;
|
transferAmountInput.Enabled = true;
|
||||||
|
transferAmountInput.ToolTip = string.Empty;
|
||||||
|
|
||||||
|
if (!hasMoneyPermissions && GameMain.Client?.ServerSettings is { } serverSettings)
|
||||||
|
{
|
||||||
|
transferAmountInput.MaxValueInt = Math.Min(maxValue, serverSettings.MaximumTransferRequest);
|
||||||
|
if (serverSettings.MaximumTransferRequest <= 0)
|
||||||
|
{
|
||||||
|
transferAmountInput.Enabled = false;
|
||||||
|
transferAmountInput.ToolTip = TextManager.Get("wallettransferrequestdisabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateMaxInput()
|
void SetRewardText(int value, GUITextBlock block)
|
||||||
{
|
{
|
||||||
transferAmountInput.MaxValueInt = isSending ? targetWallet.Balance : otherWallet.Balance;
|
var (_, percentage, sum) = Mission.GetRewardShare(value, salaryCrew, Option<int>.None());
|
||||||
|
LocalizedString tooltip = string.Empty;
|
||||||
|
block.TextColor = GUIStyle.TextColorNormal;
|
||||||
|
|
||||||
|
if (sum > 100)
|
||||||
|
{
|
||||||
|
tooltip = TextManager.GetWithVariables("crewwallet.salary.over100toolitp", ("[sum]", $"{(int)sum}"), ("[newvalue]", $"{percentage}"));
|
||||||
|
block.TextColor = GUIStyle.Orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalizedString text = TextManager.GetWithVariable("percentageformat", "[value]", $"{value}");
|
||||||
|
|
||||||
|
block.Text = text;
|
||||||
|
block.ToolTip = RichString.Rich(tooltip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ToggleTransferMenuIcon(GUIButton btn, bool open)
|
static void ToggleTransferMenuIcon(GUIButton btn, bool open)
|
||||||
@@ -1235,24 +1321,6 @@ namespace Barotrauma
|
|||||||
transfer.Write(msg);
|
transfer.Write(msg);
|
||||||
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRewardText(int value, GUITextBlock block)
|
|
||||||
{
|
|
||||||
var (_, percentage, sum) = Mission.GetRewardShare(value, salaryCrew, Option<int>.None());
|
|
||||||
LocalizedString tooltip = string.Empty;
|
|
||||||
block.TextColor = GUIStyle.TextColorNormal;
|
|
||||||
|
|
||||||
if (sum > 100)
|
|
||||||
{
|
|
||||||
tooltip = TextManager.GetWithVariables("crewwallet.salary.over100toolitp", ("[sum]", $"{(int)sum}"), ("[newvalue]", $"{percentage}"));
|
|
||||||
block.TextColor = GUIStyle.Orange;
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalizedString text = TextManager.GetWithVariable("percentageformat", "[value]", $"{value}");
|
|
||||||
|
|
||||||
block.Text = text;
|
|
||||||
block.ToolTip = RichString.Rich(tooltip);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private GUIComponent CreateClientInfoFrame(GUIFrame frame, Client client, Sprite permissionIcon = null)
|
private GUIComponent CreateClientInfoFrame(GUIFrame frame, Client client, Sprite permissionIcon = null)
|
||||||
@@ -1740,9 +1808,6 @@ namespace Barotrauma
|
|||||||
talentButtons.Clear();
|
talentButtons.Clear();
|
||||||
talentCornerIcons.Clear();
|
talentCornerIcons.Clear();
|
||||||
|
|
||||||
Character controlledCharacter = Character.Controlled;
|
|
||||||
if (controlledCharacter == null) { return; }
|
|
||||||
|
|
||||||
GUIFrame talentFrameBackground = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
GUIFrame talentFrameBackground = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||||
int padding = GUI.IntScale(15);
|
int padding = GUI.IntScale(15);
|
||||||
GUIFrame talentFrameContent = new GUIFrame(new RectTransform(new Point(talentFrameBackground.Rect.Width - padding, talentFrameBackground.Rect.Height - padding), infoFrame.RectTransform, Anchor.Center), style: null);
|
GUIFrame talentFrameContent = new GUIFrame(new RectTransform(new Point(talentFrameBackground.Rect.Width - padding, talentFrameBackground.Rect.Height - padding), infoFrame.RectTransform, Anchor.Center), style: null);
|
||||||
@@ -1762,13 +1827,20 @@ namespace Barotrauma
|
|||||||
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
|
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*Character controlledCharacter = Character.Controlled;
|
||||||
|
if (controlledCharacter == null) { return; }
|
||||||
|
|
||||||
if (controlledCharacter.Info is null)
|
if (controlledCharacter.Info is null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("No character info found for talent UI");
|
DebugConsole.ThrowError("No character info found for talent UI");
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
Character controlledCharacter = Character.Controlled;
|
||||||
|
CharacterInfo info = controlledCharacter?.Info ?? GameMain.Client?.CharacterInfo;
|
||||||
|
if (info == null) { return; }
|
||||||
|
|
||||||
|
Job job = info.Job;
|
||||||
|
|
||||||
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), talentFrameMain.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), talentFrameMain.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||||
{
|
{
|
||||||
@@ -1777,8 +1849,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
GUILayoutGroup talentInfoLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), talentFrameLayoutGroup.RectTransform, Anchor.Center), isHorizontal: true);
|
GUILayoutGroup talentInfoLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), talentFrameLayoutGroup.RectTransform, Anchor.Center), isHorizontal: true);
|
||||||
|
|
||||||
CharacterInfo info = controlledCharacter.Info;
|
|
||||||
Job job = info.Job;
|
|
||||||
|
|
||||||
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), talentInfoLayoutGroup.RectTransform), onDraw: (batch, component) =>
|
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), talentInfoLayoutGroup.RectTransform), onDraw: (batch, component) =>
|
||||||
{
|
{
|
||||||
@@ -1801,11 +1871,11 @@ namespace Barotrauma
|
|||||||
GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUIStyle.SmallFont);
|
GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUIStyle.SmallFont);
|
||||||
traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint();
|
traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint();
|
||||||
|
|
||||||
GUIFrame endocrineFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.35f), nameLayout.RectTransform, Anchor.BottomCenter), style: null);
|
GUIFrame talentsOutsideTreeFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.35f), nameLayout.RectTransform, Anchor.BottomCenter), style: null);
|
||||||
|
|
||||||
if (!(GameMain.NetworkMember is null))
|
if (!(GameMain.NetworkMember is null))
|
||||||
{
|
{
|
||||||
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.675f, 1f), endocrineFrame.RectTransform, Anchor.TopLeft), text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"))
|
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.675f, 1f), talentsOutsideTreeFrame.RectTransform, Anchor.TopLeft), text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"))
|
||||||
{
|
{
|
||||||
IgnoreLayoutGroups = true
|
IgnoreLayoutGroups = true
|
||||||
};
|
};
|
||||||
@@ -1852,13 +1922,14 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<TalentPrefab> endocrineTalents = info.GetEndocrineTalents().Select(e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier == e));
|
IEnumerable<TalentPrefab> talentsOutsideTree = info.GetUnlockedTalentsOutsideTree().Select(e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier == e));
|
||||||
|
|
||||||
if (endocrineTalents.Count() > 0)
|
if (talentsOutsideTree.Count() > 0)
|
||||||
{
|
{
|
||||||
GUIImage endocrineIcon = new GUIImage(new RectTransform(new Vector2(0.275f, 1f), endocrineFrame.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.Normal), style: "EndocrineReminderIcon")
|
//TODO: replace with something more generic
|
||||||
|
GUIImage endocrineIcon = new GUIImage(new RectTransform(new Vector2(0.275f, 1f), talentsOutsideTreeFrame.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.Normal), style: "EndocrineReminderIcon")
|
||||||
{
|
{
|
||||||
ToolTip = $"{TextManager.Get("afflictionname.endocrineboost")}\n\n{string.Join(", ", endocrineTalents.Select(e => e.DisplayName))}"
|
ToolTip = $"{TextManager.Get("afflictionname.endocrineboost")}\n\n{string.Join(", ", talentsOutsideTree.Select(e => e.DisplayName))}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1870,49 +1941,55 @@ namespace Barotrauma
|
|||||||
skillBlock.RectTransform.NonScaledSize = skillSize.Pad(skillBlock.Padding).ToPoint();
|
skillBlock.RectTransform.NonScaledSize = skillSize.Pad(skillBlock.Padding).ToPoint();
|
||||||
|
|
||||||
skillListBox = new GUIListBox(new RectTransform(new Vector2(1f, 1f - skillBlock.RectTransform.RelativeSize.Y), skillLayout.RectTransform), style: null);
|
skillListBox = new GUIListBox(new RectTransform(new Vector2(1f, 1f - skillBlock.RectTransform.RelativeSize.Y), skillLayout.RectTransform), style: null);
|
||||||
CreateTalentSkillList(controlledCharacter, skillListBox);
|
CreateTalentSkillList(controlledCharacter, info, skillListBox);
|
||||||
|
|
||||||
if (!TalentTree.JobTalentTrees.TryGet(controlledCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
if (controlledCharacter != null)
|
||||||
|
|
||||||
new GUIFrame(new RectTransform(new Vector2(1f, 1f), talentFrameLayoutGroup.RectTransform), style: "HorizontalLine");
|
|
||||||
|
|
||||||
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.7f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
|
||||||
|
|
||||||
List<GUITextBlock> subTreeNames = new List<GUITextBlock>();
|
|
||||||
foreach (var subTree in talentTree.TalentSubTrees)
|
|
||||||
{
|
{
|
||||||
GUIFrame subTreeFrame = new GUIFrame(new RectTransform(new Vector2(0.333f, 1f), talentTreeListBox.Content.RectTransform, anchor: Anchor.TopLeft), style: null);
|
if (!TalentTree.JobTalentTrees.TryGet(info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
||||||
GUILayoutGroup subTreeLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), subTreeFrame.RectTransform, Anchor.Center), false, childAnchor: Anchor.TopCenter);
|
|
||||||
|
|
||||||
GUIFrame subtreeTitleFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.111f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
new GUIFrame(new RectTransform(new Vector2(1f, 1f), talentFrameLayoutGroup.RectTransform), style: "HorizontalLine");
|
||||||
int elementPadding = GUI.IntScale(8);
|
|
||||||
Point headerSize = subtreeTitleFrame.RectTransform.NonScaledSize;
|
|
||||||
GUIFrame subTreeTitleBackground = new GUIFrame(new RectTransform(new Point(headerSize.X - elementPadding, headerSize.Y), subtreeTitleFrame.RectTransform, anchor: Anchor.Center), style: "SubtreeHeader");
|
|
||||||
subTreeNames.Add(new GUITextBlock(new RectTransform(Vector2.One, subTreeTitleBackground.RectTransform, anchor: Anchor.TopCenter), subTree.DisplayName, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center));
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.7f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
||||||
|
|
||||||
|
selectedTalents = info.GetUnlockedTalentsInTree().ToList();
|
||||||
|
|
||||||
|
List<GUITextBlock> subTreeNames = new List<GUITextBlock>();
|
||||||
|
foreach (var subTree in talentTree.TalentSubTrees)
|
||||||
{
|
{
|
||||||
GUIFrame talentOptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.222f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
GUIFrame subTreeFrame = new GUIFrame(new RectTransform(new Vector2(0.333f, 1f), talentTreeListBox.Content.RectTransform, anchor: Anchor.TopLeft), style: null);
|
||||||
|
GUILayoutGroup subTreeLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), subTreeFrame.RectTransform, Anchor.Center), false, childAnchor: Anchor.TopCenter);
|
||||||
|
|
||||||
Point talentFrameSize = talentOptionFrame.RectTransform.NonScaledSize;
|
GUIFrame subtreeTitleFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.111f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||||
|
int elementPadding = GUI.IntScale(8);
|
||||||
|
Point headerSize = subtreeTitleFrame.RectTransform.NonScaledSize;
|
||||||
|
GUIFrame subTreeTitleBackground = new GUIFrame(new RectTransform(new Point(headerSize.X - elementPadding, headerSize.Y), subtreeTitleFrame.RectTransform, anchor: Anchor.Center), style: "SubtreeHeader");
|
||||||
|
subTreeNames.Add(new GUITextBlock(new RectTransform(Vector2.One, subTreeTitleBackground.RectTransform, anchor: Anchor.TopCenter), subTree.DisplayName, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center));
|
||||||
|
|
||||||
GUIFrame talentBackground = new GUIFrame(new RectTransform(new Point(talentFrameSize.X - elementPadding, talentFrameSize.Y - elementPadding), talentOptionFrame.RectTransform, anchor: Anchor.Center), style: "TalentBackground");
|
for (int i = 0; i < 4; i++)
|
||||||
GUIFrame talentBackgroundHighlight = new GUIFrame(new RectTransform(Vector2.One, talentBackground.RectTransform, anchor: Anchor.Center), style: "TalentBackgroundGlow") { Visible = false };
|
|
||||||
|
|
||||||
GUIImage cornerIcon = new GUIImage(new RectTransform(new Vector2(0.2f), talentOptionFrame.RectTransform, anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight) { MaxSize = new Point(16) }, style: null)
|
|
||||||
{
|
{
|
||||||
CanBeFocused = false
|
GUIFrame talentOptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.222f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||||
};
|
|
||||||
|
|
||||||
Point iconSize = cornerIcon.RectTransform.NonScaledSize;
|
Point talentFrameSize = talentOptionFrame.RectTransform.NonScaledSize;
|
||||||
cornerIcon.RectTransform.AbsoluteOffset = new Point(iconSize.X / 2, iconSize.Y / 2);
|
|
||||||
|
GUIFrame talentBackground = new GUIFrame(new RectTransform(new Point(talentFrameSize.X - elementPadding, talentFrameSize.Y - elementPadding), talentOptionFrame.RectTransform, anchor: Anchor.Center), style: "TalentBackground")
|
||||||
|
{
|
||||||
|
Color = talentStageBackgroundColors[TalentTree.TalentTreeStageState.Locked]
|
||||||
|
};
|
||||||
|
GUIFrame talentBackgroundHighlight = new GUIFrame(new RectTransform(Vector2.One, talentBackground.RectTransform, anchor: Anchor.Center), style: "TalentBackgroundGlow") { Visible = false };
|
||||||
|
|
||||||
|
GUIImage cornerIcon = new GUIImage(new RectTransform(new Vector2(0.2f), talentOptionFrame.RectTransform, anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight) { MaxSize = new Point(16) }, style: null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false,
|
||||||
|
Color = talentStageBackgroundColors[TalentTree.TalentTreeStageState.Locked]
|
||||||
|
};
|
||||||
|
|
||||||
|
Point iconSize = cornerIcon.RectTransform.NonScaledSize;
|
||||||
|
cornerIcon.RectTransform.AbsoluteOffset = new Point(iconSize.X / 2, iconSize.Y / 2);
|
||||||
|
|
||||||
|
if (subTree.TalentOptionStages.Count <= i) { continue; }
|
||||||
|
|
||||||
if (subTree.TalentOptionStages.Count > i)
|
|
||||||
{
|
|
||||||
TalentOption talentOption = subTree.TalentOptionStages[i];
|
TalentOption talentOption = subTree.TalentOptionStages[i];
|
||||||
|
|
||||||
GUILayoutGroup talentOptionCenterGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 0.7f), talentOptionFrame.RectTransform, Anchor.Center), childAnchor: Anchor.CenterLeft);
|
GUILayoutGroup talentOptionCenterGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 0.7f), talentOptionFrame.RectTransform, Anchor.Center), childAnchor: Anchor.CenterLeft);
|
||||||
|
|
||||||
GUILayoutGroup talentOptionLayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, talentOptionCenterGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
GUILayoutGroup talentOptionLayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, talentOptionCenterGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||||
|
|
||||||
foreach (TalentPrefab talent in talentOption.Talents.OrderBy(t => t.Identifier))
|
foreach (TalentPrefab talent in talentOption.Talents.OrderBy(t => t.Identifier))
|
||||||
@@ -1929,6 +2006,7 @@ namespace Barotrauma
|
|||||||
ToolTip = RichString.Rich(talent.DisplayName + "\n\n" + talent.Description),
|
ToolTip = RichString.Rich(talent.DisplayName + "\n\n" + talent.Description),
|
||||||
UserData = talent.Identifier,
|
UserData = talent.Identifier,
|
||||||
PressedColor = pressedColor,
|
PressedColor = pressedColor,
|
||||||
|
Enabled = controlledCharacter != null,
|
||||||
OnClicked = (button, userData) =>
|
OnClicked = (button, userData) =>
|
||||||
{
|
{
|
||||||
// deselect other buttons in tier by removing their selected talents from pool
|
// deselect other buttons in tier by removing their selected talents from pool
|
||||||
@@ -1961,7 +2039,7 @@ namespace Barotrauma
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
talentButton.Color = talentButton.HoverColor = talentButton.PressedColor = talentButton.SelectedColor = Color.Transparent;
|
talentButton.Color = talentButton.HoverColor = talentButton.PressedColor = talentButton.SelectedColor = talentButton.DisabledColor = Color.Transparent;
|
||||||
|
|
||||||
GUIComponent iconImage;
|
GUIComponent iconImage;
|
||||||
if (talent.Icon is null)
|
if (talent.Icon is null)
|
||||||
@@ -1971,6 +2049,7 @@ namespace Barotrauma
|
|||||||
OutlineColor = GUIStyle.Red,
|
OutlineColor = GUIStyle.Red,
|
||||||
TextColor = GUIStyle.Red,
|
TextColor = GUIStyle.Red,
|
||||||
PressedColor = unselectableColor,
|
PressedColor = unselectableColor,
|
||||||
|
DisabledColor = unselectableColor,
|
||||||
CanBeFocused = false,
|
CanBeFocused = false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1979,63 +2058,63 @@ namespace Barotrauma
|
|||||||
iconImage = new GUIImage(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), sprite: talent.Icon, scaleToFit: true)
|
iconImage = new GUIImage(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), sprite: talent.Icon, scaleToFit: true)
|
||||||
{
|
{
|
||||||
PressedColor = unselectableColor,
|
PressedColor = unselectableColor,
|
||||||
|
DisabledColor = unselectableColor * 0.5f,
|
||||||
CanBeFocused = false,
|
CanBeFocused = false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
iconImage.Enabled = talentButton.Enabled;
|
||||||
talentButtons.Add((talentButton, iconImage));
|
talentButtons.Add((talentButton, iconImage));
|
||||||
}
|
}
|
||||||
|
|
||||||
talentCornerIcons.Add((subTree.Identifier, i, cornerIcon, talentBackground, talentBackgroundHighlight));
|
talentCornerIcons.Add((subTree.Identifier, i, cornerIcon, talentBackground, talentBackgroundHighlight));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GUITextBlock.AutoScaleAndNormalize(subTreeNames);
|
||||||
|
|
||||||
|
GUILayoutGroup talentBottomFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true) { RelativeSpacing = 0.01f };
|
||||||
|
|
||||||
|
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.59f, 1f), talentBottomFrame.RectTransform));
|
||||||
|
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), experienceLayout.RectTransform), style: null);
|
||||||
|
|
||||||
|
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
||||||
|
barSize: info.GetProgressTowardsNextLevel(), color: GUIStyle.Green)
|
||||||
|
{
|
||||||
|
IsHorizontal = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.Font, textAlignment: Alignment.CenterRight)
|
||||||
|
{
|
||||||
|
Shadow = true,
|
||||||
|
ToolTip = TextManager.Get("experiencetooltip")
|
||||||
|
};
|
||||||
|
|
||||||
|
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight) { AutoScaleVertical = true };
|
||||||
|
|
||||||
|
talentResetButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("reset"), style: "GUIButtonFreeScale")
|
||||||
|
{
|
||||||
|
OnClicked = ResetTalentSelection
|
||||||
|
};
|
||||||
|
talentApplyButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUIButtonFreeScale")
|
||||||
|
{
|
||||||
|
OnClicked = ApplyTalentSelection,
|
||||||
|
};
|
||||||
|
GUITextBlock.AutoScaleAndNormalize(talentResetButton.TextBlock, talentApplyButton.TextBlock);
|
||||||
}
|
}
|
||||||
GUITextBlock.AutoScaleAndNormalize(subTreeNames);
|
|
||||||
|
|
||||||
GUILayoutGroup talentBottomFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true) { RelativeSpacing = 0.01f };
|
|
||||||
|
|
||||||
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.59f, 1f), talentBottomFrame.RectTransform));
|
|
||||||
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), experienceLayout.RectTransform), style: null);
|
|
||||||
|
|
||||||
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
|
||||||
barSize: controlledCharacter.Info.GetProgressTowardsNextLevel(), color: GUIStyle.Green)
|
|
||||||
{
|
|
||||||
IsHorizontal = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.Font, textAlignment: Alignment.CenterRight)
|
|
||||||
{
|
|
||||||
Shadow = true,
|
|
||||||
ToolTip = TextManager.Get("experiencetooltip")
|
|
||||||
};
|
|
||||||
|
|
||||||
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight) { AutoScaleVertical = true };
|
|
||||||
|
|
||||||
talentResetButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("reset"), style: "GUIButtonFreeScale")
|
|
||||||
{
|
|
||||||
OnClicked = ResetTalentSelection
|
|
||||||
};
|
|
||||||
talentApplyButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), talentBottomFrame.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUIButtonFreeScale")
|
|
||||||
{
|
|
||||||
OnClicked = ApplyTalentSelection,
|
|
||||||
};
|
|
||||||
GUITextBlock.AutoScaleAndNormalize(talentResetButton.TextBlock, talentApplyButton.TextBlock);
|
|
||||||
|
|
||||||
UpdateTalentInfo();
|
UpdateTalentInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateTalentSkillList(Character character, GUIListBox parent)
|
private void CreateTalentSkillList(Character character, CharacterInfo info, GUIListBox parent)
|
||||||
{
|
{
|
||||||
parent.Content.ClearChildren();
|
parent.Content.ClearChildren();
|
||||||
List<GUITextBlock> skillNames = new List<GUITextBlock>();
|
List<GUITextBlock> skillNames = new List<GUITextBlock>();
|
||||||
foreach (Skill skill in character.Info.Job.GetSkills())
|
foreach (Skill skill in info.Job.GetSkills())
|
||||||
{
|
{
|
||||||
GUILayoutGroup skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), parent.Content.RectTransform), isHorizontal: true) { CanBeFocused = false };
|
GUILayoutGroup skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), parent.Content.RectTransform), isHorizontal: true) { CanBeFocused = false };
|
||||||
|
|
||||||
skillNames.Add(new GUITextBlock(new RectTransform(new Vector2(0.7f, 1f), skillContainer.RectTransform), TextManager.Get($"skillname.{skill.Identifier}").Fallback(skill.Identifier.Value)));
|
skillNames.Add(new GUITextBlock(new RectTransform(new Vector2(0.7f, 1f), skillContainer.RectTransform), TextManager.Get($"skillname.{skill.Identifier}").Fallback(skill.Identifier.Value)));
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), Math.Floor(skill.Level).ToString("F0"), textAlignment: Alignment.CenterRight) { Padding = new Vector4(0, 0, 4, 0) };
|
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), Math.Floor(skill.Level).ToString("F0"), textAlignment: Alignment.CenterRight) { Padding = new Vector4(0, 0, 4, 0) };
|
||||||
|
|
||||||
float modifiedSkillLevel = character.GetSkillLevel(skill.Identifier);
|
float modifiedSkillLevel = character?.GetSkillLevel(skill.Identifier) ?? skill.Level;
|
||||||
if (!MathUtils.NearlyEqual(MathF.Floor(modifiedSkillLevel), MathF.Floor(skill.Level)))
|
if (!MathUtils.NearlyEqual(MathF.Floor(modifiedSkillLevel), MathF.Floor(skill.Level)))
|
||||||
{
|
{
|
||||||
int skillChange = (int)MathF.Floor(modifiedSkillLevel - skill.Level);
|
int skillChange = (int)MathF.Floor(modifiedSkillLevel - skill.Level);
|
||||||
@@ -2129,7 +2208,7 @@ namespace Barotrauma
|
|||||||
talentButton.icon.HoverColor = hoverColor;
|
talentButton.icon.HoverColor = hoverColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateTalentSkillList(controlledCharacter, skillListBox);
|
CreateTalentSkillList(controlledCharacter, controlledCharacter.Info, skillListBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyTalents(Character controlledCharacter)
|
private void ApplyTalents(Character controlledCharacter)
|
||||||
@@ -2157,6 +2236,7 @@ namespace Barotrauma
|
|||||||
private bool ResetTalentSelection(GUIButton guiButton, object userData)
|
private bool ResetTalentSelection(GUIButton guiButton, object userData)
|
||||||
{
|
{
|
||||||
Character controlledCharacter = Character.Controlled;
|
Character controlledCharacter = Character.Controlled;
|
||||||
|
if (controlledCharacter?.Info == null) { return false; }
|
||||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||||
UpdateTalentInfo();
|
UpdateTalentInfo();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -546,6 +546,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
LevelGenerationParams.CheckValidity();
|
||||||
|
#endif
|
||||||
|
|
||||||
MainMenuScreen.Select();
|
MainMenuScreen.Select();
|
||||||
|
|
||||||
foreach (Identifier steamError in SteamManager.InitializationErrors)
|
foreach (Identifier steamError in SteamManager.InitializationErrors)
|
||||||
@@ -1033,11 +1037,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
GUI.SetSavingIndicatorState(true);
|
GUI.SetSavingIndicatorState(true);
|
||||||
|
|
||||||
if (GameSession.Submarine != null && !GameSession.Submarine.Removed)
|
|
||||||
{
|
|
||||||
GameSession.SubmarineInfo = new SubmarineInfo(GameSession.Submarine);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update store stock when saving and quitting in an outpost (normally updated when CampaignMode.End() is called)
|
// Update store stock when saving and quitting in an outpost (normally updated when CampaignMode.End() is called)
|
||||||
if (GameSession?.Campaign is SinglePlayerCampaign spCampaign && Level.IsLoadedOutpost && spCampaign.Map?.CurrentLocation != null && spCampaign.CargoManager != null)
|
if (GameSession?.Campaign is SinglePlayerCampaign spCampaign && Level.IsLoadedOutpost && spCampaign.Map?.CurrentLocation != null && spCampaign.CargoManager != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ namespace Barotrauma
|
|||||||
: this(isSinglePlayer)
|
: this(isSinglePlayer)
|
||||||
{
|
{
|
||||||
AddCharacterElements(element);
|
AddCharacterElements(element);
|
||||||
ActiveOrdersElement = element.GetChildElement("activeorders");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void InitProjectSpecific()
|
partial void InitProjectSpecific()
|
||||||
@@ -3661,9 +3660,9 @@ namespace Barotrauma
|
|||||||
crewList.ClearChildren();
|
crewList.ClearChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(XElement parentElement)
|
public XElement Save(XElement parentElement)
|
||||||
{
|
{
|
||||||
XElement element = new XElement("crew");
|
var element = new XElement("crew");
|
||||||
for (int i = 0; i < characterInfos.Count; i++)
|
for (int i = 0; i < characterInfos.Count; i++)
|
||||||
{
|
{
|
||||||
var ci = characterInfos[i];
|
var ci = characterInfos[i];
|
||||||
@@ -3674,8 +3673,8 @@ namespace Barotrauma
|
|||||||
infoElement.Add(new XAttribute("crewlistindex", ci.CrewListIndex));
|
infoElement.Add(new XAttribute("crewlistindex", ci.CrewListIndex));
|
||||||
if (ci.LastControlled) { infoElement.Add(new XAttribute("lastcontrolled", true)); }
|
if (ci.LastControlled) { infoElement.Add(new XAttribute("lastcontrolled", true)); }
|
||||||
}
|
}
|
||||||
SaveActiveOrders(element);
|
parentElement?.Add(element);
|
||||||
parentElement.Add(element);
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ClientReadActiveOrders(IReadMessage inc)
|
public static void ClientReadActiveOrders(IReadMessage inc)
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
partial void SettingsChanged(Option<int> balanceChanged, Option<int> rewardChanged)
|
partial void SettingsChanged(Option<int> balanceChanged, Option<int> rewardChanged)
|
||||||
{
|
{
|
||||||
|
if (Owner is Some<Character> { Value: var character })
|
||||||
|
{
|
||||||
|
if (!character.IsPlayer) { return; }
|
||||||
|
}
|
||||||
|
|
||||||
CampaignMode campaign = GameMain.GameSession?.Campaign;
|
CampaignMode campaign = GameMain.GameSession?.Campaign;
|
||||||
WalletChangedData data = new WalletChangedData
|
WalletChangedData data = new WalletChangedData
|
||||||
{
|
{
|
||||||
|
|||||||
+8
-43
@@ -92,6 +92,7 @@ namespace Barotrauma
|
|||||||
break;
|
break;
|
||||||
case "crew":
|
case "crew":
|
||||||
GameMain.GameSession.CrewManager = new CrewManager(subElement, true);
|
GameMain.GameSession.CrewManager = new CrewManager(subElement, true);
|
||||||
|
ActiveOrdersElement = element.GetChildElement("activeorders");
|
||||||
break;
|
break;
|
||||||
case "map":
|
case "map":
|
||||||
map = Map.Load(this, subElement, Settings);
|
map = Map.Load(this, subElement, Settings);
|
||||||
@@ -242,11 +243,10 @@ namespace Barotrauma
|
|||||||
crewDead = false;
|
crewDead = false;
|
||||||
endTimer = 5.0f;
|
endTimer = 5.0f;
|
||||||
CrewManager.InitSinglePlayerRound();
|
CrewManager.InitSinglePlayerRound();
|
||||||
if (petsElement != null)
|
LoadPets();
|
||||||
{
|
LoadActiveOrders();
|
||||||
PetBehavior.LoadPets(petsElement);
|
|
||||||
}
|
CargoManager.InitPurchasedIDCards();
|
||||||
CrewManager.LoadActiveOrders();
|
|
||||||
|
|
||||||
GUI.DisableSavingIndicatorDelayed();
|
GUI.DisableSavingIndicatorDelayed();
|
||||||
}
|
}
|
||||||
@@ -461,41 +461,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
if (leavingSub != Submarine.MainSub && !leavingSub.DockedTo.Contains(Submarine.MainSub))
|
|
||||||
{
|
|
||||||
Submarine.MainSub = leavingSub;
|
|
||||||
GameMain.GameSession.Submarine = leavingSub;
|
|
||||||
GameMain.GameSession.SubmarineInfo = leavingSub.Info;
|
|
||||||
leavingSub.Info.FilePath = System.IO.Path.Combine(SaveUtil.TempPath, leavingSub.Info.Name + ".sub");
|
|
||||||
var subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
|
||||||
GameMain.GameSession.OwnedSubmarines.Add(leavingSub.Info);
|
|
||||||
foreach (Submarine sub in subsToLeaveBehind)
|
|
||||||
{
|
|
||||||
GameMain.GameSession.OwnedSubmarines.RemoveAll(s => s != leavingSub.Info && s.Name == sub.Info.Name);
|
|
||||||
MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine);
|
|
||||||
LinkedSubmarine.CreateDummy(leavingSub, sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
|
||||||
|
|
||||||
if (PendingSubmarineSwitch != null)
|
|
||||||
{
|
|
||||||
SubmarineInfo previousSub = GameMain.GameSession.SubmarineInfo;
|
|
||||||
GameMain.GameSession.SubmarineInfo = PendingSubmarineSwitch;
|
|
||||||
|
|
||||||
for (int i = 0; i < GameMain.GameSession.OwnedSubmarines.Count; i++)
|
|
||||||
{
|
|
||||||
if (GameMain.GameSession.OwnedSubmarines[i].Name == previousSub.Name)
|
|
||||||
{
|
|
||||||
GameMain.GameSession.OwnedSubmarines[i] = previousSub;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||||
PendingSubmarineSwitch = null;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -766,11 +732,10 @@ namespace Barotrauma
|
|||||||
c.Info.SaveOrderData();
|
c.Info.SaveOrderData();
|
||||||
}
|
}
|
||||||
|
|
||||||
petsElement = new XElement("pets");
|
SavePets(modeElement);
|
||||||
PetBehavior.SavePets(petsElement);
|
var crewManagerElement = CrewManager.Save(modeElement);
|
||||||
modeElement.Add(petsElement);
|
SaveActiveOrders(crewManagerElement);
|
||||||
|
|
||||||
CrewManager.Save(modeElement);
|
|
||||||
CampaignMetadata.Save(modeElement);
|
CampaignMetadata.Save(modeElement);
|
||||||
Map.Save(modeElement);
|
Map.Save(modeElement);
|
||||||
CargoManager?.SavePurchasedItems(modeElement);
|
CargoManager?.SavePurchasedItems(modeElement);
|
||||||
|
|||||||
+1
-1
@@ -257,7 +257,7 @@ namespace Barotrauma.Tutorials
|
|||||||
yield return new WaitForSeconds(2.0f);
|
yield return new WaitForSeconds(2.0f);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.ToggleInventory)); // Medical supplies objective
|
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Medical supplies objective
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -275,7 +275,7 @@ namespace Barotrauma.Tutorials
|
|||||||
do { yield return null; } while (!engineer_equipmentObjectiveSensor.MotionDetected);
|
do { yield return null; } while (!engineer_equipmentObjectiveSensor.MotionDetected);
|
||||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Equipment"), ChatMessageType.Radio, null);
|
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Equipment"), ChatMessageType.Radio, null);
|
||||||
yield return new WaitForSeconds(0.5f, false);
|
yield return new WaitForSeconds(0.5f, false);
|
||||||
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.ToggleInventory)); // Retrieve equipment
|
TriggerTutorialSegment(0, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Retrieve equipment
|
||||||
bool firstSlotRemoved = false;
|
bool firstSlotRemoved = false;
|
||||||
bool secondSlotRemoved = false;
|
bool secondSlotRemoved = false;
|
||||||
bool thirdSlotRemoved = false;
|
bool thirdSlotRemoved = false;
|
||||||
|
|||||||
+2
-2
@@ -330,7 +330,7 @@ namespace Barotrauma.Tutorials
|
|||||||
yield return new WaitForSeconds(0.0f, false);
|
yield return new WaitForSeconds(0.0f, false);
|
||||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Equipment"), ChatMessageType.Radio, null);
|
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Equipment"), ChatMessageType.Radio, null);
|
||||||
do { yield return null; } while (!mechanic_equipmentObjectiveSensor.MotionDetected);
|
do { yield return null; } while (!mechanic_equipmentObjectiveSensor.MotionDetected);
|
||||||
TriggerTutorialSegment(1, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.ToggleInventory)); // Equipment & inventory objective
|
TriggerTutorialSegment(1, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Select), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Deselect)); // Equipment & inventory objective
|
||||||
SetHighlight(mechanic_equipmentCabinet.Item, true);
|
SetHighlight(mechanic_equipmentCabinet.Item, true);
|
||||||
bool firstSlotRemoved = false;
|
bool firstSlotRemoved = false;
|
||||||
bool secondSlotRemoved = false;
|
bool secondSlotRemoved = false;
|
||||||
@@ -372,7 +372,7 @@ namespace Barotrauma.Tutorials
|
|||||||
|
|
||||||
// Room 3
|
// Room 3
|
||||||
do { yield return null; } while (!mechanic_weldingObjectiveSensor.MotionDetected);
|
do { yield return null; } while (!mechanic_weldingObjectiveSensor.MotionDetected);
|
||||||
TriggerTutorialSegment(2, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Aim), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Shoot), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.ToggleInventory)); // Welding objective
|
TriggerTutorialSegment(2, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Aim), GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Shoot)); // Welding objective
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!mechanic.HasEquippedItem("divingmask".ToIdentifier()))
|
if (!mechanic.HasEquippedItem("divingmask".ToIdentifier()))
|
||||||
|
|||||||
+1
-1
@@ -106,7 +106,7 @@ namespace Barotrauma.Tutorials
|
|||||||
Character.Controlled = character;
|
Character.Controlled = character;
|
||||||
character.GiveJobItems(null);
|
character.GiveJobItems(null);
|
||||||
|
|
||||||
var idCard = character.Inventory.FindItemByIdentifier("idcard".ToIdentifier());
|
var idCard = character.Inventory.FindItemByTag("identitycard".ToIdentifier());
|
||||||
if (idCard == null)
|
if (idCard == null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Item prefab \"ID Card\" not found!");
|
DebugConsole.ThrowError("Item prefab \"ID Card\" not found!");
|
||||||
|
|||||||
@@ -525,6 +525,7 @@ namespace Barotrauma
|
|||||||
if (!AccessibleWhenAlive && !character.IsDead && !AccessibleByOwner)
|
if (!AccessibleWhenAlive && !character.IsDead && !AccessibleByOwner)
|
||||||
{
|
{
|
||||||
syncItemsDelay = Math.Max(syncItemsDelay - deltaTime, 0.0f);
|
syncItemsDelay = Math.Max(syncItemsDelay - deltaTime, 0.0f);
|
||||||
|
doubleClickedItems.Clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,7 +932,7 @@ namespace Barotrauma
|
|||||||
// Move the item from the subinventory to the selected container
|
// Move the item from the subinventory to the selected container
|
||||||
return QuickUseAction.PutToContainer;
|
return QuickUseAction.PutToContainer;
|
||||||
}
|
}
|
||||||
else
|
else if (character.Inventory.AccessibleWhenAlive || character.Inventory.AccessibleByOwner)
|
||||||
{
|
{
|
||||||
// Take from the subinventory and place it in the character's main inventory if no target container is selected
|
// Take from the subinventory and place it in the character's main inventory if no target container is selected
|
||||||
return QuickUseAction.TakeFromContainer;
|
return QuickUseAction.TakeFromContainer;
|
||||||
@@ -960,6 +961,7 @@ namespace Barotrauma
|
|||||||
else if (character.SelectedBy?.Inventory != null &&
|
else if (character.SelectedBy?.Inventory != null &&
|
||||||
Character.Controlled == character.SelectedBy &&
|
Character.Controlled == character.SelectedBy &&
|
||||||
!character.SelectedBy.Inventory.Locked &&
|
!character.SelectedBy.Inventory.Locked &&
|
||||||
|
(character.SelectedBy.Inventory.AccessibleWhenAlive || character.SelectedBy.Inventory.AccessibleByOwner) &&
|
||||||
allowInventorySwap)
|
allowInventorySwap)
|
||||||
{
|
{
|
||||||
return QuickUseAction.TakeFromCharacter;
|
return QuickUseAction.TakeFromCharacter;
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ namespace Barotrauma.Items.Components
|
|||||||
rect.Height = (int)(rect.Height * (1.0f - openState));
|
rect.Height = (int)(rect.Height * (1.0f - openState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//only merge the door's convex hull with overlapping wall segments if it's fully open or fully closed
|
||||||
|
//it's the heaviest part of changing the convex hull, and doesn't need to be done while the door is still in motion
|
||||||
|
bool mergeOverlappingSegments = openState <= 0.0f || openState >= 1.0f;
|
||||||
if (Window.Height > 0 && Window.Width > 0)
|
if (Window.Height > 0 && Window.Width > 0)
|
||||||
{
|
{
|
||||||
if (IsHorizontal)
|
if (IsHorizontal)
|
||||||
@@ -88,7 +91,7 @@ namespace Barotrauma.Items.Components
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
convexHull2.Enabled = true;
|
convexHull2.Enabled = true;
|
||||||
convexHull2.SetVertices(GetConvexHullCorners(rect2));
|
convexHull2.SetVertices(GetConvexHullCorners(rect2), mergeOverlappingSegments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,7 +115,7 @@ namespace Barotrauma.Items.Components
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
convexHull2.Enabled = true;
|
convexHull2.Enabled = true;
|
||||||
convexHull2.SetVertices(GetConvexHullCorners(rect2));
|
convexHull2.SetVertices(GetConvexHullCorners(rect2), mergeOverlappingSegments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +130,7 @@ namespace Barotrauma.Items.Components
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
convexHull.Enabled = true;
|
convexHull.Enabled = true;
|
||||||
convexHull.SetVertices(GetConvexHullCorners(rect));
|
convexHull.SetVertices(GetConvexHullCorners(rect), mergeOverlappingSegments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-5
@@ -1,4 +1,5 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Extensions;
|
||||||
|
using Barotrauma.Networking;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -78,7 +79,7 @@ namespace Barotrauma.Items.Components
|
|||||||
activateButton = new GUIButton(new RectTransform(new Vector2(0.95f, 0.8f), buttonContainer.RectTransform), TextManager.Get("DeconstructorDeconstruct"), style: "DeviceButton")
|
activateButton = new GUIButton(new RectTransform(new Vector2(0.95f, 0.8f), buttonContainer.RectTransform), TextManager.Get("DeconstructorDeconstruct"), style: "DeviceButton")
|
||||||
{
|
{
|
||||||
TextBlock = { AutoScaleHorizontal = true },
|
TextBlock = { AutoScaleHorizontal = true },
|
||||||
OnClicked = ToggleActive
|
OnClicked = OnActivateButtonClicked
|
||||||
};
|
};
|
||||||
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform),
|
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform),
|
||||||
TextManager.Get("DeconstructorNoPower"), textColor: GUIStyle.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow", wrap: true)
|
TextManager.Get("DeconstructorNoPower"), textColor: GUIStyle.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow", wrap: true)
|
||||||
@@ -164,7 +165,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
activateButton.Enabled = outputsFound;
|
activateButton.Enabled = outputsFound || !InputContainer.Inventory.IsEmpty();
|
||||||
activateButton.Text = TextManager.Get(ActivateButtonText);
|
activateButton.Text = TextManager.Get(ActivateButtonText);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -236,8 +237,19 @@ namespace Barotrauma.Items.Components
|
|||||||
inSufficientPowerWarning.Visible = IsActive && !hasPower;
|
inSufficientPowerWarning.Visible = IsActive && !hasPower;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ToggleActive(GUIButton button, object obj)
|
private bool OnActivateButtonClicked(GUIButton button, object obj)
|
||||||
{
|
{
|
||||||
|
var disallowedItem = inputContainer.Inventory.FindItem(i => !i.AllowDeconstruct, recursive: false);
|
||||||
|
if (disallowedItem != null)
|
||||||
|
{
|
||||||
|
int index = inputContainer.Inventory.FindIndex(disallowedItem);
|
||||||
|
if (index >= 0 && index < inputContainer.Inventory.visualSlots.Length)
|
||||||
|
{
|
||||||
|
var slot = inputContainer.Inventory.visualSlots[index];
|
||||||
|
slot?.ShowBorderHighlight(GUIStyle.Red, 0.1f, 0.9f);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (GameMain.Client != null)
|
if (GameMain.Client != null)
|
||||||
{
|
{
|
||||||
pendingState = !IsActive;
|
pendingState = !IsActive;
|
||||||
@@ -247,7 +259,6 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
SetActive(!IsActive, Character.Controlled);
|
SetActive(!IsActive, Character.Controlled);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1367,6 +1367,15 @@ namespace Barotrauma.Items.Components
|
|||||||
pingRadius, prevPingRadius,
|
pingRadius, prevPingRadius,
|
||||||
250.0f, 150.0f, range, pingStrength, passive);
|
250.0f, 150.0f, range, pingStrength, passive);
|
||||||
}
|
}
|
||||||
|
if (pingSource.Y - Level.Loaded.BottomPos < range)
|
||||||
|
{
|
||||||
|
CreateBlipsForLine(
|
||||||
|
new Vector2(pingSource.X - range, Level.Loaded.BottomPos),
|
||||||
|
new Vector2(pingSource.X + range, Level.Loaded.BottomPos),
|
||||||
|
pingSource, transducerPos,
|
||||||
|
pingRadius, prevPingRadius,
|
||||||
|
250.0f, 150.0f, range, pingStrength, passive);
|
||||||
|
}
|
||||||
|
|
||||||
List<Voronoi2.VoronoiCell> cells = Level.Loaded.GetCells(pingSource, 7);
|
List<Voronoi2.VoronoiCell> cells = Level.Loaded.GetCells(pingSource, 7);
|
||||||
foreach (Voronoi2.VoronoiCell cell in cells)
|
foreach (Voronoi2.VoronoiCell cell in cells)
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||||
private List<ParticleEmitter> particleEmitterHitStructure = new List<ParticleEmitter>();
|
private readonly List<ParticleEmitter> particleEmitterHitStructure = new List<ParticleEmitter>();
|
||||||
private List<ParticleEmitter> particleEmitterHitCharacter = new List<ParticleEmitter>();
|
private readonly List<ParticleEmitter> particleEmitterHitCharacter = new List<ParticleEmitter>();
|
||||||
private List<Pair<RelatedItem, ParticleEmitter>> particleEmitterHitItem = new List<Pair<RelatedItem, ParticleEmitter>>();
|
private readonly List<(RelatedItem relatedItem, ParticleEmitter emitter)> particleEmitterHitItem = new List<(RelatedItem relatedItem, ParticleEmitter emitter)>();
|
||||||
|
|
||||||
private float prevProgressBarState;
|
private float prevProgressBarState;
|
||||||
private Item prevProgressBarTarget = null;
|
private Item prevProgressBarTarget = null;
|
||||||
@@ -46,10 +46,7 @@ namespace Barotrauma.Items.Components
|
|||||||
Identifier[] excludedIdentifiers = subElement.GetAttributeIdentifierArray("excludedidentifiers", Array.Empty<Identifier>());
|
Identifier[] excludedIdentifiers = subElement.GetAttributeIdentifierArray("excludedidentifiers", Array.Empty<Identifier>());
|
||||||
if (excludedIdentifiers.Length == 0) { excludedIdentifiers = subElement.GetAttributeIdentifierArray("excludedidentifier", Array.Empty<Identifier>()); }
|
if (excludedIdentifiers.Length == 0) { excludedIdentifiers = subElement.GetAttributeIdentifierArray("excludedidentifier", Array.Empty<Identifier>()); }
|
||||||
|
|
||||||
particleEmitterHitItem.Add(
|
particleEmitterHitItem.Add((new RelatedItem(identifiers, excludedIdentifiers), new ParticleEmitter(subElement)));
|
||||||
new Pair<RelatedItem, ParticleEmitter>(
|
|
||||||
new RelatedItem(identifiers, excludedIdentifiers),
|
|
||||||
new ParticleEmitter(subElement)));
|
|
||||||
break;
|
break;
|
||||||
case "particleemitterhitstructure":
|
case "particleemitterhitstructure":
|
||||||
particleEmitterHitStructure.Add(new ParticleEmitter(subElement));
|
particleEmitterHitStructure.Add(new ParticleEmitter(subElement));
|
||||||
@@ -139,11 +136,11 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
|
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
|
||||||
if (targetItem.Submarine != null) particlePos += targetItem.Submarine.DrawPosition;
|
if (targetItem.Submarine != null) particlePos += targetItem.Submarine.DrawPosition;
|
||||||
foreach (var emitter in particleEmitterHitItem)
|
foreach ((RelatedItem relatedItem, ParticleEmitter emitter) in particleEmitterHitItem)
|
||||||
{
|
{
|
||||||
if (!emitter.First.MatchesItem(targetItem)) { continue; }
|
if (!relatedItem.MatchesItem(targetItem)) { continue; }
|
||||||
float particleAngle = item.body.Rotation + MathHelper.ToRadians(BarrelRotation) + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
float particleAngle = item.body.Rotation + MathHelper.ToRadians(BarrelRotation) + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||||
emitter.Second.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
|
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace Barotrauma.Items.Components
|
|||||||
int totalWireCount = 0;
|
int totalWireCount = 0;
|
||||||
foreach (Connection c in panel.Connections)
|
foreach (Connection c in panel.Connections)
|
||||||
{
|
{
|
||||||
totalWireCount += c.Wires.Count(w => w != null);
|
totalWireCount += c.Wires.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
Wire equippedWire = null;
|
Wire equippedWire = null;
|
||||||
@@ -87,8 +87,8 @@ namespace Barotrauma.Items.Components
|
|||||||
(DraggingConnected.Connections[0] == null && DraggingConnected.Connections[1] == null) ||
|
(DraggingConnected.Connections[0] == null && DraggingConnected.Connections[1] == null) ||
|
||||||
(DraggingConnected.Connections.Contains(c) && DraggingConnected.Connections.Contains(null)))
|
(DraggingConnected.Connections.Contains(c) && DraggingConnected.Connections.Contains(null)))
|
||||||
{
|
{
|
||||||
int linkIndex = c.FindWireIndex(DraggingConnected.Item);
|
var linkedWire = c.FindWireByItem(DraggingConnected.Item);
|
||||||
if (linkIndex > -1 || panel.DisconnectedWires.Contains(DraggingConnected))
|
if (linkedWire != null || panel.DisconnectedWires.Contains(DraggingConnected))
|
||||||
{
|
{
|
||||||
Inventory.DraggingItems.Clear();
|
Inventory.DraggingItems.Clear();
|
||||||
Inventory.DraggingItems.Add(DraggingConnected.Item);
|
Inventory.DraggingItems.Add(DraggingConnected.Item);
|
||||||
@@ -108,7 +108,7 @@ namespace Barotrauma.Items.Components
|
|||||||
c.DrawWires(spriteBatch, panel, rightPos, rightWirePos, mouseInRect, equippedWire, wireInterval);
|
c.DrawWires(spriteBatch, panel, rightPos, rightWirePos, mouseInRect, equippedWire, wireInterval);
|
||||||
}
|
}
|
||||||
rightPos.Y += connectorIntervalLeft;
|
rightPos.Y += connectorIntervalLeft;
|
||||||
rightWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
|
rightWirePos.Y += c.Wires.Count * wireInterval;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -121,7 +121,7 @@ namespace Barotrauma.Items.Components
|
|||||||
c.DrawWires(spriteBatch, panel, leftPos, leftWirePos, mouseInRect, equippedWire, wireInterval);
|
c.DrawWires(spriteBatch, panel, leftPos, leftWirePos, mouseInRect, equippedWire, wireInterval);
|
||||||
}
|
}
|
||||||
leftPos.Y += connectorIntervalRight;
|
leftPos.Y += connectorIntervalRight;
|
||||||
leftWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
|
leftWirePos.Y += c.Wires.Count * wireInterval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,15 +228,15 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
float connectorSpriteScale = (35.0f / connectionSprite.SourceRect.Width) * panel.Scale;
|
float connectorSpriteScale = (35.0f / connectionSprite.SourceRect.Width) * panel.Scale;
|
||||||
|
|
||||||
for (int i = 0; i < MaxWires; i++)
|
foreach (var wire in wires)
|
||||||
{
|
{
|
||||||
if (wires[i] == null || wires[i].Hidden || (DraggingConnected == wires[i] && (mouseIn || Screen.Selected == GameMain.SubEditorScreen))) { continue; }
|
if (wire.Hidden || (DraggingConnected == wire && (mouseIn || Screen.Selected == GameMain.SubEditorScreen))) { continue; }
|
||||||
if (wires[i].HiddenInGame && Screen.Selected == GameMain.GameScreen) { continue; }
|
if (wire.HiddenInGame && Screen.Selected == GameMain.GameScreen) { continue; }
|
||||||
|
|
||||||
Connection recipient = wires[i].OtherConnection(this);
|
Connection recipient = wire.OtherConnection(this);
|
||||||
LocalizedString label = recipient == null ? "" : recipient.item.Name + $" ({recipient.DisplayName})";
|
LocalizedString label = recipient == null ? "" : recipient.item.Name + $" ({recipient.DisplayName})";
|
||||||
if (wires[i].Locked) { label += "\n" + TextManager.Get("ConnectionLocked"); }
|
if (wire.Locked) { label += "\n" + TextManager.Get("ConnectionLocked"); }
|
||||||
DrawWire(spriteBatch, wires[i], position, wirePosition, equippedWire, panel, label);
|
DrawWire(spriteBatch, wire, position, wirePosition, equippedWire, panel, label);
|
||||||
|
|
||||||
wirePosition.Y += wireInterval;
|
wirePosition.Y += wireInterval;
|
||||||
}
|
}
|
||||||
@@ -248,18 +248,17 @@ namespace Barotrauma.Items.Components
|
|||||||
if (!PlayerInput.PrimaryMouseButtonHeld())
|
if (!PlayerInput.PrimaryMouseButtonHeld())
|
||||||
{
|
{
|
||||||
if ((GameMain.NetworkMember != null || panel.CheckCharacterSuccess(Character.Controlled)) &&
|
if ((GameMain.NetworkMember != null || panel.CheckCharacterSuccess(Character.Controlled)) &&
|
||||||
Wires.Count(w => w != null) < MaxPlayerConnectableWires)
|
Wires.Count < MaxPlayerConnectableWires)
|
||||||
{
|
{
|
||||||
//find an empty cell for the new connection
|
//find an empty cell for the new connection
|
||||||
int index = FindEmptyIndex();
|
if (WireSlotsAvailable() && !Wires.Contains(DraggingConnected))
|
||||||
if (index > -1 && !Wires.Contains(DraggingConnected))
|
|
||||||
{
|
{
|
||||||
bool alreadyConnected = DraggingConnected.IsConnectedTo(panel.Item);
|
bool alreadyConnected = DraggingConnected.IsConnectedTo(panel.Item);
|
||||||
DraggingConnected.RemoveConnection(panel.Item);
|
DraggingConnected.RemoveConnection(panel.Item);
|
||||||
if (DraggingConnected.Connect(this, !alreadyConnected, true))
|
if (DraggingConnected.Connect(this, !alreadyConnected, true))
|
||||||
{
|
{
|
||||||
var otherConnection = DraggingConnected.OtherConnection(this);
|
var otherConnection = DraggingConnected.OtherConnection(this);
|
||||||
SetWire(index, DraggingConnected);
|
ConnectWire(DraggingConnected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,7 +283,7 @@ namespace Barotrauma.Items.Components
|
|||||||
flashColor * (float)Math.Sin(FlashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f), scale: connectorSpriteScale);
|
flashColor * (float)Math.Sin(FlashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f), scale: connectorSpriteScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Wires.Any(w => w != null && w != DraggingConnected && !w.Hidden && (!w.HiddenInGame || Screen.Selected != GameMain.GameScreen)))
|
if (Wires.Any(w => w != DraggingConnected && !w.Hidden && (!w.HiddenInGame || Screen.Selected != GameMain.GameScreen)))
|
||||||
{
|
{
|
||||||
int screwIndex = (int)Math.Floor(position.Y / 30.0f) % screwSprites.Count;
|
int screwIndex = (int)Math.Floor(position.Y / 30.0f) % screwSprites.Count;
|
||||||
screwSprites[screwIndex].Draw(spriteBatch, position, scale: connectorSpriteScale);
|
screwSprites[screwIndex].Draw(spriteBatch, position, scale: connectorSpriteScale);
|
||||||
|
|||||||
+16
-6
@@ -77,7 +77,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Move(Vector2 amount)
|
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||||
{
|
{
|
||||||
if (item.Submarine == null || item.Submarine.Loading || Screen.Selected != GameMain.SubEditorScreen) { return; }
|
if (item.Submarine == null || item.Submarine.Loading || Screen.Selected != GameMain.SubEditorScreen) { return; }
|
||||||
MoveConnectedWires(amount);
|
MoveConnectedWires(amount);
|
||||||
@@ -173,8 +173,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private void ApplyRemoteState(IReadMessage msg)
|
private void ApplyRemoteState(IReadMessage msg)
|
||||||
{
|
{
|
||||||
List<Wire> prevWires = Connections.SelectMany(c => c.Wires.Where(w => w != null)).ToList();
|
List<Wire> prevWires = Connections.SelectMany(c => c.Wires).ToList();
|
||||||
List<Wire> newWires = new List<Wire>();
|
|
||||||
|
|
||||||
ushort userID = msg.ReadUInt16();
|
ushort userID = msg.ReadUInt16();
|
||||||
|
|
||||||
@@ -195,7 +194,9 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
foreach (Connection connection in Connections)
|
foreach (Connection connection in Connections)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < connection.MaxWires; i++)
|
HashSet<Wire> newWires = new HashSet<Wire>();
|
||||||
|
uint wireCount = msg.ReadVariableUInt32();
|
||||||
|
for (int i = 0; i < wireCount; i++)
|
||||||
{
|
{
|
||||||
ushort wireId = msg.ReadUInt16();
|
ushort wireId = msg.ReadUInt16();
|
||||||
|
|
||||||
@@ -204,9 +205,18 @@ namespace Barotrauma.Items.Components
|
|||||||
if (wireComponent == null) { continue; }
|
if (wireComponent == null) { continue; }
|
||||||
|
|
||||||
newWires.Add(wireComponent);
|
newWires.Add(wireComponent);
|
||||||
|
}
|
||||||
|
|
||||||
connection.SetWire(i, wireComponent);
|
Wire[] oldWires = connection.Wires.Where(w => !newWires.Contains(w)).ToArray();
|
||||||
wireComponent.Connect(connection, false);
|
foreach (var wire in oldWires)
|
||||||
|
{
|
||||||
|
connection.DisconnectWire(wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var wire in newWires.Where(w => !connection.Wires.Contains(w)).ToArray())
|
||||||
|
{
|
||||||
|
connection.ConnectWire(wire);
|
||||||
|
wire.Connect(connection, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ namespace Barotrauma.Items.Components
|
|||||||
foreach (var uiElement in uiElements)
|
foreach (var uiElement in uiElements)
|
||||||
{
|
{
|
||||||
if (!(uiElement.UserData is CustomInterfaceElement element)) { continue; }
|
if (!(uiElement.UserData is CustomInterfaceElement element)) { continue; }
|
||||||
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || element.HasPropertyName || (element.Connection != null && element.Connection.Wires.Any(w => w != null));
|
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || element.HasPropertyName || (element.Connection != null && element.Connection.Wires.Count > 0);
|
||||||
if (visible) { visibleElementCount++; }
|
if (visible) { visibleElementCount++; }
|
||||||
if (uiElement.Visible != visible)
|
if (uiElement.Visible != visible)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -526,7 +526,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Move(Vector2 amount)
|
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||||
{
|
{
|
||||||
//only used in the sub editor, hence only in the client project
|
//only used in the sub editor, hence only in the client project
|
||||||
if (!item.IsSelected) { return; }
|
if (!item.IsSelected) { return; }
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ namespace Barotrauma.Items.Components
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Move(Vector2 amount)
|
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||||
{
|
{
|
||||||
widgets.Clear();
|
widgets.Clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ using Microsoft.Xna.Framework.Graphics;
|
|||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable
|
partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable, IClientSerializable
|
||||||
{
|
{
|
||||||
|
private GUIMessageBox autodockingVerification;
|
||||||
|
|
||||||
public Vector2 DrawSize
|
public Vector2 DrawSize
|
||||||
{
|
{
|
||||||
//use the extents of the item as the draw size
|
//use the extents of the item as the draw size
|
||||||
@@ -180,5 +182,10 @@ namespace Barotrauma.Items.Components
|
|||||||
Undock();
|
Undock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData = null)
|
||||||
|
{
|
||||||
|
msg.Write((byte)allowOutpostAutoDocking);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LocalizedString description = item.Description;
|
LocalizedString description = item.Description;
|
||||||
if (item.Prefab.Identifier == "idcard" || item.Tags.Contains("despawncontainer"))
|
if (item.HasTag("identitycard") || item.HasTag("despawncontainer"))
|
||||||
{
|
{
|
||||||
string[] readTags = item.Tags.Split(',');
|
string[] readTags = item.Tags.Split(',');
|
||||||
string idName = null;
|
string idName = null;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Extensions;
|
||||||
|
using Barotrauma.Items.Components;
|
||||||
|
using Barotrauma.MapCreatures.Behavior;
|
||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using FarseerPhysics;
|
using FarseerPhysics;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
@@ -6,13 +8,8 @@ using Microsoft.Xna.Framework.Graphics;
|
|||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
using Barotrauma.Extensions;
|
|
||||||
using Barotrauma.MapCreatures.Behavior;
|
|
||||||
using FarseerPhysics.Dynamics;
|
|
||||||
using FarseerPhysics.Dynamics.Contacts;
|
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -720,7 +717,7 @@ namespace Barotrauma
|
|||||||
//remove identifiers from the available container tags
|
//remove identifiers from the available container tags
|
||||||
//(otherwise the list will include many irrelevant options,
|
//(otherwise the list will include many irrelevant options,
|
||||||
//e.g. "weldingtool" because a welding fuel tank can be placed inside the container, etc)
|
//e.g. "weldingtool" because a welding fuel tank can be placed inside the container, etc)
|
||||||
.Where(t => !ItemPrefab.Prefabs.Any(ip => ip.Identifier == t))
|
.Where(t => !ItemPrefab.Prefabs.ContainsKey(t))
|
||||||
.ToImmutableHashSet();
|
.ToImmutableHashSet();
|
||||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1), tagsField.RectTransform, Anchor.TopRight), "...")
|
new GUIButton(new RectTransform(new Vector2(0.1f, 1), tagsField.RectTransform, Anchor.TopRight), "...")
|
||||||
{
|
{
|
||||||
@@ -1174,7 +1171,7 @@ namespace Barotrauma
|
|||||||
texts.Clear();
|
texts.Clear();
|
||||||
|
|
||||||
string nameText = Name;
|
string nameText = Name;
|
||||||
if (Prefab.Identifier == "idcard" || Tags.Contains("despawncontainer"))
|
if (Prefab.Tags.Contains("identitycard") || Tags.Contains("despawncontainer"))
|
||||||
{
|
{
|
||||||
string[] readTags = Tags.Split(',');
|
string[] readTags = Tags.Split(',');
|
||||||
string idName = null;
|
string idName = null;
|
||||||
|
|||||||
@@ -80,15 +80,17 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
Vector2 center = new Vector2((minX + maxX) / 2.0f, (minY + maxY) / 2.0f);
|
Vector2 center = new Vector2((minX + maxX) / 2.0f, (minY + maxY) / 2.0f);
|
||||||
if (Submarine.MainSub != null) { center -= Submarine.MainSub.HiddenSubPosition; }
|
if (Submarine.MainSub != null) { center -= Submarine.MainSub.HiddenSubPosition; }
|
||||||
center.X -= MathUtils.RoundTowardsClosest(center.X, Submarine.GridSize.X);
|
|
||||||
center.Y -= MathUtils.RoundTowardsClosest(center.Y, Submarine.GridSize.Y);
|
Vector2 offsetFromGrid = new Vector2(
|
||||||
|
MathUtils.RoundTowardsClosest(center.X, Submarine.GridSize.X) - center.X,
|
||||||
|
MathUtils.RoundTowardsClosest(center.Y, Submarine.GridSize.Y) - center.Y - Submarine.GridSize.Y / 2);
|
||||||
|
|
||||||
MapEntity.SelectedList.Clear();
|
MapEntity.SelectedList.Clear();
|
||||||
assemblyEntities.ForEach(e => MapEntity.AddSelection(e));
|
assemblyEntities.ForEach(e => MapEntity.AddSelection(e));
|
||||||
|
|
||||||
foreach (MapEntity mapEntity in assemblyEntities)
|
foreach (MapEntity mapEntity in assemblyEntities)
|
||||||
{
|
{
|
||||||
mapEntity.Move(-center);
|
mapEntity.Move(-center - offsetFromGrid);
|
||||||
mapEntity.Submarine = Submarine.MainSub;
|
mapEntity.Submarine = Submarine.MainSub;
|
||||||
var entityElement = mapEntity.Save(element);
|
var entityElement = mapEntity.Save(element);
|
||||||
if (disabledEntities.Contains(mapEntity))
|
if (disabledEntities.Contains(mapEntity))
|
||||||
|
|||||||
@@ -461,7 +461,7 @@ namespace Barotrauma.Lights
|
|||||||
Matrix.CreateTranslation(-origin.X, -origin.Y, 0.0f) *
|
Matrix.CreateTranslation(-origin.X, -origin.Y, 0.0f) *
|
||||||
Matrix.CreateRotationZ(amount) *
|
Matrix.CreateRotationZ(amount) *
|
||||||
Matrix.CreateTranslation(origin.X, origin.Y, 0.0f);
|
Matrix.CreateTranslation(origin.X, origin.Y, 0.0f);
|
||||||
SetVertices(vertices.Select(v => v.Pos).ToArray(), rotationMatrix);
|
SetVertices(vertices.Select(v => v.Pos).ToArray(), rotationMatrix: rotationMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CalculateDimensions()
|
private void CalculateDimensions()
|
||||||
@@ -541,7 +541,7 @@ namespace Barotrauma.Lights
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetVertices(Vector2[] points, Matrix? rotationMatrix = null)
|
public void SetVertices(Vector2[] points, bool mergeOverlappingSegments = true, Matrix? rotationMatrix = null)
|
||||||
{
|
{
|
||||||
Debug.Assert(points.Length == 4, "Only rectangular convex hulls are supported");
|
Debug.Assert(points.Length == 4, "Only rectangular convex hulls are supported");
|
||||||
|
|
||||||
@@ -594,13 +594,16 @@ namespace Barotrauma.Lights
|
|||||||
|
|
||||||
if (ParentEntity == null) { return; }
|
if (ParentEntity == null) { return; }
|
||||||
|
|
||||||
var chList = HullLists.Find(h => h.Submarine == ParentEntity.Submarine);
|
if (mergeOverlappingSegments)
|
||||||
if (chList != null)
|
|
||||||
{
|
{
|
||||||
overlappingHulls.Clear();
|
var chList = HullLists.Find(h => h.Submarine == ParentEntity.Submarine);
|
||||||
foreach (ConvexHull ch in chList.List)
|
if (chList != null)
|
||||||
{
|
{
|
||||||
MergeOverlappingSegments(ch);
|
overlappingHulls.Clear();
|
||||||
|
foreach (ConvexHull ch in chList.List)
|
||||||
|
{
|
||||||
|
MergeOverlappingSegments(ch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,11 +81,18 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
catch (System.IO.FileNotFoundException e)
|
catch (System.IO.FileNotFoundException e)
|
||||||
{
|
{
|
||||||
string errorMsg = "Failed to load sound file \"" + filename + "\".";
|
string errorMsg = "Failed to load sound file \"" + filename + "\" (file not found).";
|
||||||
DebugConsole.ThrowError(errorMsg, e);
|
DebugConsole.ThrowError(errorMsg, e);
|
||||||
GameAnalyticsManager.AddErrorEventOnce("RoundSound.LoadRoundSound:FileNotFound" + filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
GameAnalyticsManager.AddErrorEventOnce("RoundSound.LoadRoundSound:FileNotFound" + filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
catch (System.IO.InvalidDataException e)
|
||||||
|
{
|
||||||
|
string errorMsg = "Failed to load sound file \"" + filename + "\" (invalid data).";
|
||||||
|
DebugConsole.ThrowError(errorMsg, e);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("RoundSound.LoadRoundSound:InvalidData" + filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RoundSound newSound = new RoundSound(element, existingSound);
|
RoundSound newSound = new RoundSound(element, existingSound);
|
||||||
|
|||||||
@@ -525,7 +525,7 @@ namespace Barotrauma
|
|||||||
Item.ItemList.Count(it2 => it2.linkedTo.Contains(item) && !item.linkedTo.Contains(it2));
|
Item.ItemList.Count(it2 => it2.linkedTo.Contains(item) && !item.linkedTo.Contains(it2));
|
||||||
for (int i = 0; i < item.Connections.Count; i++)
|
for (int i = 0; i < item.Connections.Count; i++)
|
||||||
{
|
{
|
||||||
int wireCount = item.Connections[i].Wires.Count(w => w != null);
|
int wireCount = item.Connections[i].Wires.Count;
|
||||||
if (doorLinks + wireCount > item.Connections[i].MaxWires)
|
if (doorLinks + wireCount > item.Connections[i].MaxWires)
|
||||||
{
|
{
|
||||||
errorMsgs.Add(TextManager.GetWithVariables("InsufficientFreeConnectionsWarning",
|
errorMsgs.Add(TextManager.GetWithVariables("InsufficientFreeConnectionsWarning",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Barotrauma.Items.Components;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Barotrauma.Networking
|
namespace Barotrauma.Networking
|
||||||
@@ -183,6 +184,11 @@ namespace Barotrauma.Networking
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType, textColor: textColor);
|
GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType, textColor: textColor);
|
||||||
|
if (type == ChatMessageType.Radio && CanUseRadio(senderCharacter, out WifiComponent radio))
|
||||||
|
{
|
||||||
|
Signal s = new Signal(txt, sender: senderCharacter, source: radio.Item);
|
||||||
|
radio.TransmitSignal(s, sentFromChat: true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LastID = id;
|
LastID = id;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Barotrauma.Steam;
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using Barotrauma.IO;
|
using Barotrauma.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -11,6 +12,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Barotrauma.Extensions;
|
using Barotrauma.Extensions;
|
||||||
|
using Microsoft.Xna.Framework.Input;
|
||||||
|
|
||||||
namespace Barotrauma.Networking
|
namespace Barotrauma.Networking
|
||||||
{
|
{
|
||||||
@@ -182,6 +184,20 @@ namespace Barotrauma.Networking
|
|||||||
get { return ownerKey > 0 || steamP2POwner; }
|
get { return ownerKey > 0 || steamP2POwner; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal readonly struct PermissionChangedEvent
|
||||||
|
{
|
||||||
|
public readonly ClientPermissions NewPermissions;
|
||||||
|
public readonly ImmutableArray<string> NewPermittedConsoleCommands;
|
||||||
|
|
||||||
|
public PermissionChangedEvent(ClientPermissions newPermissions, IReadOnlyList<string> newPermittedConsoleCommands)
|
||||||
|
{
|
||||||
|
NewPermissions = newPermissions;
|
||||||
|
NewPermittedConsoleCommands = newPermittedConsoleCommands.ToImmutableArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly NamedEvent<PermissionChangedEvent> OnPermissionChanged = new NamedEvent<PermissionChangedEvent>();
|
||||||
|
|
||||||
public GameClient(string newName, string ip, UInt64 steamId, string serverName = null, int ownerKey = 0, bool steamP2POwner = false)
|
public GameClient(string newName, string ip, UInt64 steamId, string serverName = null, int ownerKey = 0, bool steamP2POwner = false)
|
||||||
{
|
{
|
||||||
//TODO: gui stuff should probably not be here?
|
//TODO: gui stuff should probably not be here?
|
||||||
@@ -570,7 +586,12 @@ namespace Barotrauma.Networking
|
|||||||
public override void Update(float deltaTime)
|
public override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (PlayerInput.GetKeyboardState.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.P)) return;
|
if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.P)) return;
|
||||||
|
|
||||||
|
if (PlayerInput.KeyHit(Keys.Home))
|
||||||
|
{
|
||||||
|
OnPermissionChanged.Invoke(new PermissionChangedEvent(permissions, permittedConsoleCommands));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
foreach (Client c in ConnectedClients)
|
foreach (Client c in ConnectedClients)
|
||||||
@@ -1019,40 +1040,25 @@ namespace Barotrauma.Networking
|
|||||||
GameMain.GameSession.EnforceMissionOrder(serverMissionIdentifiers);
|
GameMain.GameSession.EnforceMissionOrder(serverMissionIdentifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte equalityCheckValueCount = inc.ReadByte();
|
var levelEqualityCheckValues = new Dictionary<Level.LevelGenStage, int>();
|
||||||
List<int> levelEqualityCheckValues = new List<int>();
|
foreach (Level.LevelGenStage stage in Enum.GetValues(typeof(Level.LevelGenStage)).OfType<Level.LevelGenStage>().OrderBy(s => s))
|
||||||
for (int i = 0; i < equalityCheckValueCount; i++)
|
|
||||||
{
|
{
|
||||||
levelEqualityCheckValues.Add(inc.ReadInt32());
|
levelEqualityCheckValues.Add(stage, inc.ReadInt32());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Level.Loaded.EqualityCheckValues.Count != levelEqualityCheckValues.Count)
|
foreach (var stage in levelEqualityCheckValues.Keys)
|
||||||
{
|
{
|
||||||
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server" +
|
if (Level.Loaded.EqualityCheckValues[stage] != levelEqualityCheckValues[stage])
|
||||||
" (client value count: " + Level.Loaded.EqualityCheckValues.Count +
|
|
||||||
", level value count: " + levelEqualityCheckValues.Count +
|
|
||||||
", seed: " + Level.Loaded.Seed +
|
|
||||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
|
|
||||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
|
||||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
|
||||||
throw new Exception(errorMsg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < equalityCheckValueCount; i++)
|
|
||||||
{
|
{
|
||||||
if (Level.Loaded.EqualityCheckValues[i] != levelEqualityCheckValues[i])
|
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server" +
|
||||||
{
|
" (client value " + stage + ": " + Level.Loaded.EqualityCheckValues[stage].ToString("X") +
|
||||||
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server" +
|
", server value " + stage + ": " + levelEqualityCheckValues[stage].ToString("X") +
|
||||||
" (client value #" + i + ": " + Level.Loaded.EqualityCheckValues[i] +
|
", level value count: " + levelEqualityCheckValues.Count +
|
||||||
", server value #" + i + ": " + levelEqualityCheckValues[i].ToString("X") +
|
", seed: " + Level.Loaded.Seed +
|
||||||
", level value count: " + levelEqualityCheckValues.Count +
|
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
|
||||||
", seed: " + Level.Loaded.Seed +
|
", mirrored: " + Level.Loaded.Mirrored + ").";
|
||||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
|
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
throw new Exception(errorMsg);
|
||||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
|
||||||
throw new Exception(errorMsg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1076,6 +1082,7 @@ namespace Barotrauma.Networking
|
|||||||
reconnectBox?.Close();
|
reconnectBox?.Close();
|
||||||
reconnectBox = null;
|
reconnectBox = null;
|
||||||
|
|
||||||
|
GameMain.ModDownloadScreen.Reset();
|
||||||
ContentPackageManager.EnabledPackages.Restore();
|
ContentPackageManager.EnabledPackages.Restore();
|
||||||
|
|
||||||
GUI.ClearCursorWait();
|
GUI.ClearCursorWait();
|
||||||
@@ -1380,18 +1387,13 @@ namespace Barotrauma.Networking
|
|||||||
private void SetMyPermissions(ClientPermissions newPermissions, IEnumerable<string> permittedConsoleCommands)
|
private void SetMyPermissions(ClientPermissions newPermissions, IEnumerable<string> permittedConsoleCommands)
|
||||||
{
|
{
|
||||||
if (!(this.permittedConsoleCommands.Any(c => !permittedConsoleCommands.Contains(c)) ||
|
if (!(this.permittedConsoleCommands.Any(c => !permittedConsoleCommands.Contains(c)) ||
|
||||||
permittedConsoleCommands.Any(c => !this.permittedConsoleCommands.Contains(c))))
|
permittedConsoleCommands.Any(c => !this.permittedConsoleCommands.Contains(c))))
|
||||||
{
|
{
|
||||||
if (newPermissions == permissions) return;
|
if (newPermissions == permissions) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool refreshCampaignUI = false;
|
bool refreshCampaignUI = permissions.HasFlag(ClientPermissions.ManageCampaign) != newPermissions.HasFlag(ClientPermissions.ManageCampaign) ||
|
||||||
|
permissions.HasFlag(ClientPermissions.ManageRound) != newPermissions.HasFlag(ClientPermissions.ManageRound);
|
||||||
if (permissions.HasFlag(ClientPermissions.ManageCampaign) != newPermissions.HasFlag(ClientPermissions.ManageCampaign) ||
|
|
||||||
permissions.HasFlag(ClientPermissions.ManageRound) != newPermissions.HasFlag(ClientPermissions.ManageRound))
|
|
||||||
{
|
|
||||||
refreshCampaignUI = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
permissions = newPermissions;
|
permissions = newPermissions;
|
||||||
this.permittedConsoleCommands = new List<string>(permittedConsoleCommands);
|
this.permittedConsoleCommands = new List<string>(permittedConsoleCommands);
|
||||||
@@ -1430,7 +1432,7 @@ namespace Barotrauma.Networking
|
|||||||
if (newPermissions.HasFlag(ClientPermissions.ConsoleCommands))
|
if (newPermissions.HasFlag(ClientPermissions.ConsoleCommands))
|
||||||
{
|
{
|
||||||
var commandsLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), rightColumn.RectTransform),
|
var commandsLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), rightColumn.RectTransform),
|
||||||
TextManager.Get("PermittedConsoleCommands"), wrap: true, font: GUIStyle.SubHeadingFont);
|
TextManager.Get("PermittedConsoleCommands"), wrap: true, font: GUIStyle.SubHeadingFont);
|
||||||
var commandList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform));
|
var commandList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform));
|
||||||
foreach (string permittedCommand in permittedConsoleCommands)
|
foreach (string permittedCommand in permittedConsoleCommands)
|
||||||
{
|
{
|
||||||
@@ -1469,6 +1471,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
|
|
||||||
GameMain.NetLobbyScreen.RefreshEnabledElements();
|
GameMain.NetLobbyScreen.RefreshEnabledElements();
|
||||||
|
OnPermissionChanged.Invoke(new PermissionChangedEvent(permissions, this.permittedConsoleCommands));
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<CoroutineStatus> StartGame(IReadMessage inc)
|
private IEnumerable<CoroutineStatus> StartGame(IReadMessage inc)
|
||||||
@@ -3680,7 +3683,9 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
if (Level.Loaded != null)
|
if (Level.Loaded != null)
|
||||||
{
|
{
|
||||||
errorLines.Add("Level: " + Level.Loaded.Seed + ", " + string.Join(", ", Level.Loaded.EqualityCheckValues.Select(cv => cv.ToString("X"))));
|
errorLines.Add("Level: " + Level.Loaded.Seed + ", "
|
||||||
|
+ string.Join("; ", Level.Loaded.EqualityCheckValues.Select(cv
|
||||||
|
=> cv.Key + "=" + cv.Value.ToString("X"))));
|
||||||
errorLines.Add("Entity count before generating level: " + Level.Loaded.EntityCountBeforeGenerate);
|
errorLines.Add("Entity count before generating level: " + Level.Loaded.EntityCountBeforeGenerate);
|
||||||
errorLines.Add("Entities:");
|
errorLines.Add("Entities:");
|
||||||
foreach (Entity e in Level.Loaded.EntitiesBeforeGenerate.OrderBy(e => e.CreationIndex))
|
foreach (Entity e in Level.Loaded.EntitiesBeforeGenerate.OrderBy(e => e.CreationIndex))
|
||||||
|
|||||||
@@ -634,6 +634,14 @@ namespace Barotrauma.Networking
|
|||||||
var traitorsMinPlayerCount = CreateLabeledNumberInput(roundsTab, "ServerSettingsTraitorsMinPlayerCount", 1, 16, "ServerSettingsTraitorsMinPlayerCountToolTip");
|
var traitorsMinPlayerCount = CreateLabeledNumberInput(roundsTab, "ServerSettingsTraitorsMinPlayerCount", 1, 16, "ServerSettingsTraitorsMinPlayerCountToolTip");
|
||||||
GetPropertyData(nameof(TraitorsMinPlayerCount)).AssignGUIComponent(traitorsMinPlayerCount);
|
GetPropertyData(nameof(TraitorsMinPlayerCount)).AssignGUIComponent(traitorsMinPlayerCount);
|
||||||
|
|
||||||
|
var maximumTransferAmount = CreateLabeledNumberInput(roundsTab, "serversettingsmaximumtransferrequest", 0, CampaignMode.MaxMoney, "serversettingsmaximumtransferrequesttooltip");
|
||||||
|
GetPropertyData(nameof(MaximumTransferRequest)).AssignGUIComponent(maximumTransferAmount);
|
||||||
|
|
||||||
|
var lootedMoneyDestination = CreateLabeledDropdown(roundsTab, "serversettingslootedmoneydestination", numElements: 2, "serversettingslootedmoneydestinationtooltip");
|
||||||
|
lootedMoneyDestination.AddItem(TextManager.Get("lootedmoneydestination.bank"), LootedMoneyDestination.Bank);
|
||||||
|
lootedMoneyDestination.AddItem(TextManager.Get("lootedmoneydestination.wallet"), LootedMoneyDestination.Wallet);
|
||||||
|
GetPropertyData(nameof(LootedMoneyDestination)).AssignGUIComponent(lootedMoneyDestination);
|
||||||
|
|
||||||
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
|
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
|
||||||
GetPropertyData(nameof(AllowRagdollButton)).AssignGUIComponent(ragdollButtonBox);
|
GetPropertyData(nameof(AllowRagdollButton)).AssignGUIComponent(ragdollButtonBox);
|
||||||
|
|
||||||
@@ -991,6 +999,32 @@ namespace Barotrauma.Networking
|
|||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GUIDropDown CreateLabeledDropdown(GUIComponent parent, string labelTag, int numElements, string toolTipTag = null)
|
||||||
|
{
|
||||||
|
var container = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), parent.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f,
|
||||||
|
ToolTip = TextManager.Get(labelTag)
|
||||||
|
};
|
||||||
|
|
||||||
|
var label = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), container.RectTransform),
|
||||||
|
TextManager.Get(labelTag), textAlignment: Alignment.CenterLeft, font: GUIStyle.SmallFont)
|
||||||
|
{
|
||||||
|
AutoScaleHorizontal = true
|
||||||
|
};
|
||||||
|
if (!string.IsNullOrEmpty(toolTipTag))
|
||||||
|
{
|
||||||
|
label.ToolTip = TextManager.Get(toolTipTag);
|
||||||
|
}
|
||||||
|
var input = new GUIDropDown(new RectTransform(new Vector2(0.3f, 1.0f), container.RectTransform), elementCount: numElements);
|
||||||
|
|
||||||
|
container.RectTransform.MinSize = new Point(0, input.RectTransform.MinSize.Y);
|
||||||
|
container.RectTransform.MaxSize = new Point(int.MaxValue, input.RectTransform.MaxSize.Y);
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
private bool SelectSettingsTab(GUIButton button, object obj)
|
private bool SelectSettingsTab(GUIButton button, object obj)
|
||||||
{
|
{
|
||||||
settingsTabIndex = (int)obj;
|
settingsTabIndex = (int)obj;
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ namespace Barotrauma.Particles
|
|||||||
{
|
{
|
||||||
return debugName;
|
return debugName;
|
||||||
}
|
}
|
||||||
public void Init(ParticlePrefab prefab, Vector2 position, Vector2 speed, float rotation, Hull hullGuess = null, bool drawOnTop = false, float collisionIgnoreTimer = 0f, Tuple<Vector2, Vector2> tracerPoints = null)
|
public void Init(ParticlePrefab prefab, Vector2 position, Vector2 speed, float rotation, Hull hullGuess = null, bool drawOnTop = false, float collisionIgnoreTimer = 0f, float lifeTimeMultiplier = 1f, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||||
{
|
{
|
||||||
this.prefab = prefab;
|
this.prefab = prefab;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@@ -149,13 +149,13 @@ namespace Barotrauma.Particles
|
|||||||
|
|
||||||
if (prefab.LifeTimeMin <= 0.0f)
|
if (prefab.LifeTimeMin <= 0.0f)
|
||||||
{
|
{
|
||||||
totalLifeTime = prefab.LifeTime;
|
totalLifeTime = prefab.LifeTime * lifeTimeMultiplier;
|
||||||
lifeTime = prefab.LifeTime;
|
lifeTime = prefab.LifeTime * lifeTimeMultiplier;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
totalLifeTime = Rand.Range(prefab.LifeTimeMin, prefab.LifeTime);
|
totalLifeTime = Rand.Range(prefab.LifeTimeMin, prefab.LifeTime) * lifeTimeMultiplier;
|
||||||
lifeTime = totalLifeTime;
|
lifeTime = totalLifeTime * lifeTimeMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
startDelay = Rand.Range(prefab.StartDelayMin, prefab.StartDelayMax);
|
startDelay = Rand.Range(prefab.StartDelayMin, prefab.StartDelayMax);
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ namespace Barotrauma.Particles
|
|||||||
[Editable, Serialize("1,1,1,1", IsPropertySaveable.Yes)]
|
[Editable, Serialize("1,1,1,1", IsPropertySaveable.Yes)]
|
||||||
public Color ColorMultiplier { get; set; }
|
public Color ColorMultiplier { get; set; }
|
||||||
|
|
||||||
|
[Editable, Serialize(1f, IsPropertySaveable.Yes)]
|
||||||
|
public float LifeTimeMultiplier { get; set; }
|
||||||
|
|
||||||
[Editable, Serialize(false, IsPropertySaveable.Yes)]
|
[Editable, Serialize(false, IsPropertySaveable.Yes)]
|
||||||
public bool DrawOnTop { get; set; }
|
public bool DrawOnTop { get; set; }
|
||||||
|
|
||||||
@@ -197,7 +200,7 @@ namespace Barotrauma.Particles
|
|||||||
position += dir * Rand.Range(Prefab.Properties.DistanceMin, Prefab.Properties.DistanceMax);
|
position += dir * Rand.Range(Prefab.Properties.DistanceMin, Prefab.Properties.DistanceMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
var particle = GameMain.ParticleManager.CreateParticle(particlePrefab, position, velocity, particleRotation, hullGuess, Prefab.DrawOnTop, tracerPoints: tracerPoints);
|
var particle = GameMain.ParticleManager.CreateParticle(particlePrefab, position, velocity, particleRotation, hullGuess, Prefab.DrawOnTop, lifeTimeMultiplier: Prefab.Properties.LifeTimeMultiplier, tracerPoints: tracerPoints);
|
||||||
|
|
||||||
if (particle != null)
|
if (particle != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ namespace Barotrauma.Particles
|
|||||||
return CreateParticle(prefab, position, velocity, rotation, hullGuess, collisionIgnoreTimer: collisionIgnoreTimer, tracerPoints:tracerPoints);
|
return CreateParticle(prefab, position, velocity, rotation, hullGuess, collisionIgnoreTimer: collisionIgnoreTimer, tracerPoints:tracerPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Particle CreateParticle(ParticlePrefab prefab, Vector2 position, Vector2 velocity, float rotation = 0.0f, Hull hullGuess = null, bool drawOnTop = false, float collisionIgnoreTimer = 0f, Tuple<Vector2, Vector2> tracerPoints = null)
|
public Particle CreateParticle(ParticlePrefab prefab, Vector2 position, Vector2 velocity, float rotation = 0.0f, Hull hullGuess = null, bool drawOnTop = false, float collisionIgnoreTimer = 0f, float lifeTimeMultiplier = 1f, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||||
{
|
{
|
||||||
if (prefab == null || prefab.Sprites.Count == 0) { return null; }
|
if (prefab == null || prefab.Sprites.Count == 0) { return null; }
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ namespace Barotrauma.Particles
|
|||||||
|
|
||||||
if (particles[particleCount] == null) { particles[particleCount] = new Particle(); }
|
if (particles[particleCount] == null) { particles[particleCount] = new Particle(); }
|
||||||
|
|
||||||
particles[particleCount].Init(prefab, position, velocity, rotation, hullGuess, drawOnTop, collisionIgnoreTimer, tracerPoints: tracerPoints);
|
particles[particleCount].Init(prefab, position, velocity, rotation, hullGuess, drawOnTop, collisionIgnoreTimer, lifeTimeMultiplier, tracerPoints: tracerPoints);
|
||||||
|
|
||||||
particleCount++;
|
particleCount++;
|
||||||
|
|
||||||
|
|||||||
@@ -77,9 +77,20 @@ namespace Barotrauma
|
|||||||
if (remoteContentDoc?.Root != null)
|
if (remoteContentDoc?.Root != null)
|
||||||
{
|
{
|
||||||
remoteContentContainer.ClearChildren();
|
remoteContentContainer.ClearChildren();
|
||||||
foreach (var subElement in remoteContentDoc.Root.Elements())
|
try
|
||||||
{
|
{
|
||||||
GUIComponent.FromXML(subElement.FromPackage(null), remoteContentContainer.RectTransform);
|
foreach (var subElement in remoteContentDoc.Root.Elements())
|
||||||
|
{
|
||||||
|
GUIComponent.FromXML(subElement.FromPackage(null), remoteContentContainer.RectTransform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
DebugConsole.ThrowError("Reading received remote main menu content failed.", e);
|
||||||
|
#endif
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.RemoteContentParse:Exception", GameAnalyticsManager.ErrorSeverity.Error,
|
||||||
|
"Reading received remote main menu content failed. " + e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,10 +20,11 @@ namespace Barotrauma
|
|||||||
private ServerContentPackage? currentDownload;
|
private ServerContentPackage? currentDownload;
|
||||||
|
|
||||||
private readonly List<ContentPackage> downloadedPackages = new List<ContentPackage>();
|
private readonly List<ContentPackage> downloadedPackages = new List<ContentPackage>();
|
||||||
|
public IEnumerable<ContentPackage> DownloadedPackages => downloadedPackages;
|
||||||
|
|
||||||
private bool confirmDownload;
|
private bool confirmDownload;
|
||||||
|
|
||||||
private void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
pendingDownloads.Clear();
|
pendingDownloads.Clear();
|
||||||
downloadedPackages.Clear();
|
downloadedPackages.Clear();
|
||||||
@@ -255,12 +256,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Deselect()
|
|
||||||
{
|
|
||||||
Reset();
|
|
||||||
base.Deselect();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(double deltaTime)
|
public override void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
base.Update(deltaTime);
|
base.Update(deltaTime);
|
||||||
|
|||||||
@@ -1400,7 +1400,7 @@ namespace Barotrauma
|
|||||||
public void CreatePlayerFrame(GUIComponent parent, bool createPendingText = true, bool alwaysAllowEditing = false)
|
public void CreatePlayerFrame(GUIComponent parent, bool createPendingText = true, bool alwaysAllowEditing = false)
|
||||||
{
|
{
|
||||||
UpdatePlayerFrame(
|
UpdatePlayerFrame(
|
||||||
Character.Controlled?.Info ?? playerInfoContainer.Children?.First().UserData as CharacterInfo,
|
Character.Controlled?.Info ?? playerInfoContainer.Children?.First().UserData as CharacterInfo ?? GameMain.Client.CharacterInfo,
|
||||||
allowEditing: alwaysAllowEditing || campaignCharacterInfo == null,
|
allowEditing: alwaysAllowEditing || campaignCharacterInfo == null,
|
||||||
parent: parent,
|
parent: parent,
|
||||||
createPendingText: createPendingText);
|
createPendingText: createPendingText);
|
||||||
@@ -3131,10 +3131,11 @@ namespace Barotrauma
|
|||||||
retVal[i] = new GUIImage[outfitPreview.Sprites.Count];
|
retVal[i] = new GUIImage[outfitPreview.Sprites.Count];
|
||||||
for (int j = 0; j < outfitPreview.Sprites.Count; j++)
|
for (int j = 0; j < outfitPreview.Sprites.Count; j++)
|
||||||
{
|
{
|
||||||
Pair<Sprite, Vector2> sprite = outfitPreview.Sprites[j];
|
Sprite sprite = outfitPreview.Sprites[j].sprite;
|
||||||
|
Vector2 drawOffset = outfitPreview.Sprites[j].drawOffset;
|
||||||
float aspectRatio = outfitPreview.Dimensions.Y / outfitPreview.Dimensions.X;
|
float aspectRatio = outfitPreview.Dimensions.Y / outfitPreview.Dimensions.X;
|
||||||
retVal[i][j] = new GUIImage(new RectTransform(new Vector2(0.7f / aspectRatio, 0.7f), innerFrame.RectTransform, Anchor.Center)
|
retVal[i][j] = new GUIImage(new RectTransform(new Vector2(0.7f / aspectRatio, 0.7f), innerFrame.RectTransform, Anchor.Center)
|
||||||
{ RelativeOffset = sprite.Second / outfitPreview.Dimensions }, sprite.First, scaleToFit: true)
|
{ RelativeOffset = drawOffset / outfitPreview.Dimensions }, sprite, scaleToFit: true)
|
||||||
{
|
{
|
||||||
PressedColor = Color.White,
|
PressedColor = Color.White,
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
|
|||||||
@@ -1190,18 +1190,23 @@ namespace Barotrauma
|
|||||||
frame.RectTransform.MaxSize = new Point(int.MaxValue, frame.Rect.Width);
|
frame.RectTransform.MaxSize = new Point(int.MaxValue, frame.Rect.Width);
|
||||||
|
|
||||||
LocalizedString name = legacy ? TextManager.GetWithVariable("legacyitemformat", "[name]", ep.Name) : ep.Name;
|
LocalizedString name = legacy ? TextManager.GetWithVariable("legacyitemformat", "[name]", ep.Name) : ep.Name;
|
||||||
frame.ToolTip = ep.Description.IsNullOrEmpty() ? name : name + '\n' + ep.Description;
|
frame.ToolTip = $"{frame.ToolTip}\n‖color:{XMLExtensions.ToStringHex(GUIStyle.TextColorBright)}‖{name}‖color:end‖";
|
||||||
|
if (!ep.Description.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
frame.ToolTip += '\n' + ep.Description;
|
||||||
|
}
|
||||||
|
|
||||||
if (ep.ContentPackage != GameMain.VanillaContent && ep.ContentPackage != null)
|
if (ep.ContentPackage != GameMain.VanillaContent && ep.ContentPackage != null)
|
||||||
{
|
{
|
||||||
frame.Color = Color.Magenta;
|
frame.Color = Color.Magenta;
|
||||||
frame.ToolTip = RichString.Rich($"{frame.ToolTip}\n‖color:{XMLExtensions.ToStringHex(Color.MediumPurple)}‖{ep.ContentPackage?.Name}‖color:end‖");
|
frame.ToolTip = $"{frame.ToolTip}\n‖color:{XMLExtensions.ToStringHex(Color.MediumPurple)}‖{ep.ContentPackage?.Name}‖color:end‖";
|
||||||
}
|
}
|
||||||
if (ep.HideInMenus)
|
if (ep.HideInMenus)
|
||||||
{
|
{
|
||||||
frame.Color = Color.Red;
|
frame.Color = Color.Red;
|
||||||
name = "[HIDDEN] " + name;
|
name = "[HIDDEN] " + name;
|
||||||
}
|
}
|
||||||
|
frame.ToolTip = RichString.Rich(frame.ToolTip);
|
||||||
|
|
||||||
GUILayoutGroup paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.8f), frame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
GUILayoutGroup paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.8f), frame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||||
{
|
{
|
||||||
@@ -1976,7 +1981,7 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
nameBox.Text = subNameLabel?.Text?.SanitizedValue ?? "";
|
nameBox.Text = MainSub?.Info.Name ?? "";
|
||||||
|
|
||||||
submarineNameCharacterCount.Text = nameBox.Text.Length + " / " + submarineNameLimit;
|
submarineNameCharacterCount.Text = nameBox.Text.Length + " / " + submarineNameLimit;
|
||||||
|
|
||||||
@@ -2750,6 +2755,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nameBox.Text = nameBox.Text.Trim();
|
||||||
|
|
||||||
bool hideInMenus = nameBox.Parent.GetChildByUserData("hideinmenus") is GUITickBox hideInMenusTickBox && hideInMenusTickBox.Selected;
|
bool hideInMenus = nameBox.Parent.GetChildByUserData("hideinmenus") is GUITickBox hideInMenusTickBox && hideInMenusTickBox.Selected;
|
||||||
string saveFolder = Path.Combine(ContentPackage.LocalModsDir, nameBox.Text);
|
string saveFolder = Path.Combine(ContentPackage.LocalModsDir, nameBox.Text);
|
||||||
string filePath = Path.Combine(saveFolder, $"{nameBox.Text}.xml").CleanUpPathCrossPlatform();
|
string filePath = Path.Combine(saveFolder, $"{nameBox.Text}.xml").CleanUpPathCrossPlatform();
|
||||||
@@ -2884,8 +2891,30 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (deleteButtonHolder.FindChild("delete") is GUIButton deleteBtn)
|
if (deleteButtonHolder.FindChild("delete") is GUIButton deleteBtn)
|
||||||
{
|
{
|
||||||
deleteBtn.Enabled = userData is SubmarineInfo subInfo
|
deleteBtn.ToolTip = string.Empty;
|
||||||
&& GetContentPackageIntrinsicallyTiedToSub(subInfo) != null;
|
if (!(userData is SubmarineInfo subInfo))
|
||||||
|
{
|
||||||
|
deleteBtn.Enabled = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var package = GetContentPackageIntrinsicallyTiedToSub(subInfo);
|
||||||
|
if (package != null)
|
||||||
|
{
|
||||||
|
deleteBtn.Enabled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deleteBtn.Enabled = false;
|
||||||
|
if (ContentPackageManager.VanillaCorePackage?.Files.Any(f => f.Path == subInfo.FilePath) ?? false)
|
||||||
|
{
|
||||||
|
deleteBtn.ToolTip = TextManager.Get("cantdeletevanillasub");
|
||||||
|
}
|
||||||
|
else if (ContentPackageManager.AllPackages.FirstOrDefault(p => p.Files.Any(f => f.Path == subInfo.FilePath)) is ContentPackage subPackage)
|
||||||
|
{
|
||||||
|
deleteBtn.ToolTip = TextManager.GetWithVariable("cantdeletemodsub", "[modname]", subPackage.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2925,6 +2954,21 @@ namespace Barotrauma
|
|||||||
ToolTip = sub.FilePath
|
ToolTip = sub.FilePath
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!(ContentPackageManager.VanillaCorePackage?.Files.Any(f => f.Path == sub.FilePath) ?? false))
|
||||||
|
{
|
||||||
|
if (GetContentPackageIntrinsicallyTiedToSub(sub) == null &&
|
||||||
|
ContentPackageManager.AllPackages.FirstOrDefault(p => p.Files.Any(f => f.Path == sub.FilePath)) is ContentPackage subPackage)
|
||||||
|
{
|
||||||
|
//workshop mod
|
||||||
|
textBlock.OverrideTextColor(Color.MediumPurple);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//local mod
|
||||||
|
textBlock.OverrideTextColor(GUIStyle.TextColorBright);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sub.HasTag(SubmarineTag.Shuttle))
|
if (sub.HasTag(SubmarineTag.Shuttle))
|
||||||
{
|
{
|
||||||
var shuttleText = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1.0f), textBlock.RectTransform, Anchor.CenterRight),
|
var shuttleText = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1.0f), textBlock.RectTransform, Anchor.CenterRight),
|
||||||
@@ -3037,6 +3081,24 @@ namespace Barotrauma
|
|||||||
if (!(child.UserData is SubmarineInfo sub)) { continue; }
|
if (!(child.UserData is SubmarineInfo sub)) { continue; }
|
||||||
child.Visible = string.IsNullOrEmpty(filter) || sub.Name.ToLower().Contains(filter.ToLower());
|
child.Visible = string.IsNullOrEmpty(filter) || sub.Name.ToLower().Contains(filter.ToLower());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go through the elements backwards, and disable the labels for sub categories if there's no subs visible in them
|
||||||
|
bool subVisibleInCategory = false;
|
||||||
|
foreach (GUIComponent child in subList.Content.Children.Reverse())
|
||||||
|
{
|
||||||
|
if (!(child.UserData is SubmarineInfo sub))
|
||||||
|
{
|
||||||
|
if (child.Enabled)
|
||||||
|
{
|
||||||
|
child.Visible = subVisibleInCategory;
|
||||||
|
}
|
||||||
|
subVisibleInCategory = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subVisibleInCategory |= child.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -4828,7 +4890,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameSettings.CurrentConfig.KeyMap.Bindings[InputType.ToggleInventory].IsHit() && mode == Mode.Default)
|
if (PlayerInput.KeyHit(Keys.Q) && mode == Mode.Default)
|
||||||
{
|
{
|
||||||
toggleEntityMenuButton.OnClicked?.Invoke(toggleEntityMenuButton, toggleEntityMenuButton.UserData);
|
toggleEntityMenuButton.OnClicked?.Invoke(toggleEntityMenuButton, toggleEntityMenuButton.UserData);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,16 +233,18 @@ namespace Barotrauma
|
|||||||
|
|
||||||
float dist = diff.Length();
|
float dist = diff.Length();
|
||||||
float distFallOff = dist / FlowSoundRange;
|
float distFallOff = dist / FlowSoundRange;
|
||||||
if (distFallOff >= 0.99f) continue;
|
if (distFallOff >= 0.99f) { continue; }
|
||||||
|
|
||||||
|
float gain = MathHelper.Clamp(gapFlow / 100.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
//flow at the left side
|
//flow at the left side
|
||||||
if (diff.X < 0)
|
if (diff.X < 0)
|
||||||
{
|
{
|
||||||
targetFlowLeft[flowSoundIndex] += 1.0f - distFallOff;
|
targetFlowLeft[flowSoundIndex] += gain - distFallOff;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
targetFlowRight[flowSoundIndex] += 1.0f - distFallOff;
|
targetFlowRight[flowSoundIndex] += gain - distFallOff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,7 +289,7 @@ namespace Barotrauma
|
|||||||
flowSoundChannels[i] = FlowSounds[i].Sound.Play(1.0f, FlowSoundRange, soundPos);
|
flowSoundChannels[i] = FlowSounds[i].Sound.Play(1.0f, FlowSoundRange, soundPos);
|
||||||
flowSoundChannels[i].Looping = true;
|
flowSoundChannels[i].Looping = true;
|
||||||
}
|
}
|
||||||
flowSoundChannels[i].Gain = Math.Min(Math.Max(flowVolumeRight[i], flowVolumeLeft[i]), 1.0f);
|
flowSoundChannels[i].Gain = Math.Max(flowVolumeRight[i], flowVolumeLeft[i]);
|
||||||
flowSoundChannels[i].Position = new Vector3(soundPos, 0.0f);
|
flowSoundChannels[i].Position = new Vector3(soundPos, 0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -853,7 +855,7 @@ namespace Barotrauma
|
|||||||
if (SplashSounds.Count == 0) { return; }
|
if (SplashSounds.Count == 0) { return; }
|
||||||
int splashIndex = MathHelper.Clamp((int)(strength + Rand.Range(-2.0f, 2.0f)), 0, SplashSounds.Count - 1);
|
int splashIndex = MathHelper.Clamp((int)(strength + Rand.Range(-2.0f, 2.0f)), 0, SplashSounds.Count - 1);
|
||||||
float range = 800.0f;
|
float range = 800.0f;
|
||||||
var channel = SplashSounds[splashIndex].Sound.Play(1.0f, range, worldPosition, muffle: ShouldMuffleSound(Character.Controlled, worldPosition, range, null));
|
SplashSounds[splashIndex].Sound?.Play(1.0f, range, worldPosition, muffle: ShouldMuffleSound(Character.Controlled, worldPosition, range, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PlayDamageSound(string damageType, float damage, PhysicsBody body)
|
public static void PlayDamageSound(string damageType, float damage, PhysicsBody body)
|
||||||
|
|||||||
@@ -39,9 +39,8 @@ namespace Barotrauma
|
|||||||
get { return texture != null && !cannotBeLoaded; }
|
get { return texture != null && !cannotBeLoaded; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sprite(Sprite other) : this(other.texture, other.sourceRect, other.offset, other.rotation)
|
public Sprite(Sprite other) : this(other.texture, other.sourceRect, other.offset, other.rotation, other.FilePath.Value)
|
||||||
{
|
{
|
||||||
FilePath = other.FilePath;
|
|
||||||
Compress = other.Compress;
|
Compress = other.Compress;
|
||||||
size = other.size;
|
size = other.size;
|
||||||
effects = other.effects;
|
effects = other.effects;
|
||||||
@@ -58,6 +57,17 @@ namespace Barotrauma
|
|||||||
rotation = newRotation;
|
rotation = newRotation;
|
||||||
FilePath = ContentPath.FromRaw(path);
|
FilePath = ContentPath.FromRaw(path);
|
||||||
AddToList(this);
|
AddToList(this);
|
||||||
|
if (!string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
Identifier fullPath = Path.GetFullPath(path).CleanUpPathCrossPlatform(correctFilenameCase: false).ToIdentifier();
|
||||||
|
lock (list)
|
||||||
|
{
|
||||||
|
if (!textureRefCounts.TryAdd(fullPath, new TextureRefCounter { RefCount = 1, Texture = texture }))
|
||||||
|
{
|
||||||
|
textureRefCounts[fullPath].RefCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void LoadTexture(ref Vector4 sourceVector, ref bool shouldReturn)
|
partial void LoadTexture(ref Vector4 sourceVector, ref bool shouldReturn)
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ namespace Barotrauma.Steam
|
|||||||
{
|
{
|
||||||
public static partial class Workshop
|
public static partial class Workshop
|
||||||
{
|
{
|
||||||
|
public const int MaxThumbnailSize = 1024 * 1024;
|
||||||
|
|
||||||
public static readonly ImmutableArray<Identifier> Tags = new []
|
public static readonly ImmutableArray<Identifier> Tags = new []
|
||||||
{
|
{
|
||||||
"submarine",
|
"submarine",
|
||||||
@@ -177,7 +179,7 @@ namespace Barotrauma.Steam
|
|||||||
|
|
||||||
DeletePublishStagingCopy();
|
DeletePublishStagingCopy();
|
||||||
Directory.CreateDirectory(PublishStagingDir);
|
Directory.CreateDirectory(PublishStagingDir);
|
||||||
await CopyDirectory(contentPackage.Dir, contentPackage.Name, Path.GetDirectoryName(contentPackage.Path)!, PublishStagingDir);
|
await CopyDirectory(contentPackage.Dir, contentPackage.Name, Path.GetDirectoryName(contentPackage.Path)!, PublishStagingDir, ShouldCorrectPaths.No);
|
||||||
|
|
||||||
//Load filelist.xml and write the hash into it so anyone downloading this mod knows what it should be
|
//Load filelist.xml and write the hash into it so anyone downloading this mod knows what it should be
|
||||||
ModProject modProject = new ModProject(contentPackage)
|
ModProject modProject = new ModProject(contentPackage)
|
||||||
@@ -218,7 +220,7 @@ namespace Barotrauma.Steam
|
|||||||
throw new Exception($"{newPath} already exists");
|
throw new Exception($"{newPath} already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
await CopyDirectory(contentPackage.Dir, contentPackage.Name, Path.GetDirectoryName(contentPackage.Path)!, newPath);
|
await CopyDirectory(contentPackage.Dir, contentPackage.Name, Path.GetDirectoryName(contentPackage.Path)!, newPath, ShouldCorrectPaths.Yes);
|
||||||
|
|
||||||
ModProject modProject = new ModProject(contentPackage);
|
ModProject modProject = new ModProject(contentPackage);
|
||||||
modProject.DiscardHashAndInstallTime();
|
modProject.DiscardHashAndInstallTime();
|
||||||
|
|||||||
@@ -197,6 +197,11 @@ namespace Barotrauma.Steam
|
|||||||
|
|
||||||
FileSelection.OnFileSelected = (fn) =>
|
FileSelection.OnFileSelected = (fn) =>
|
||||||
{
|
{
|
||||||
|
if (new FileInfo(fn).Length > SteamManager.Workshop.MaxThumbnailSize)
|
||||||
|
{
|
||||||
|
new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("WorkshopItemPreviewImageTooLarge"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
thumbnailPath = fn;
|
thumbnailPath = fn;
|
||||||
CreateLocalThumbnail(thumbnailPath, thumbnailContainer);
|
CreateLocalThumbnail(thumbnailPath, thumbnailContainer);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -119,6 +119,11 @@ namespace Barotrauma.Steam
|
|||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
|
new GUICustomComponent(new RectTransform(Vector2.Zero, searchHolder.RectTransform), onUpdate:
|
||||||
|
(f, component) =>
|
||||||
|
{
|
||||||
|
searchTitle.RectTransform.NonScaledSize = searchBox.Frame.RectTransform.NonScaledSize;
|
||||||
|
});
|
||||||
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
|
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
|
||||||
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = searchBox.Text.IsNullOrWhiteSpace(); };
|
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = searchBox.Text.IsNullOrWhiteSpace(); };
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ namespace Barotrauma
|
|||||||
private readonly int maxWidth;
|
private readonly int maxWidth;
|
||||||
|
|
||||||
private ScalableFont? cachedFont = null;
|
private ScalableFont? cachedFont = null;
|
||||||
private uint cachedFontSize = 0;
|
|
||||||
|
|
||||||
public LimitLString(LocalizedString text, GUIFont font, int maxWidth)
|
public LimitLString(LocalizedString text, GUIFont font, int maxWidth)
|
||||||
{
|
{
|
||||||
@@ -27,7 +26,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
cachedValue = ToolBox.LimitString(nestedStr.Value, font.Value, maxWidth);
|
cachedValue = ToolBox.LimitString(nestedStr.Value, font.Value, maxWidth);
|
||||||
cachedFont = font.Value;
|
cachedFont = font.Value;
|
||||||
cachedFontSize = font.Size;
|
|
||||||
UpdateLanguage();
|
UpdateLanguage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static string LimitString(string str, ScalableFont font, int maxWidth)
|
public static string LimitString(string str, ScalableFont font, int maxWidth)
|
||||||
{
|
{
|
||||||
if (maxWidth <= 0 || string.IsNullOrWhiteSpace(str)) return "";
|
if (maxWidth <= 0 || string.IsNullOrWhiteSpace(str)) { return ""; }
|
||||||
|
|
||||||
float currWidth = font.MeasureString("...").X;
|
float currWidth = font.MeasureString("...").X;
|
||||||
for (int i = 0; i < str.Length; i++)
|
for (int i = 0; i < str.Length; i++)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.17.15.0</Version>
|
<Version>0.18.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.17.15.0</Version>
|
<Version>0.18.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.17.15.0</Version>
|
<Version>0.18.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.17.15.0</Version>
|
<Version>0.18.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.17.15.0</Version>
|
<Version>0.18.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace Barotrauma
|
|||||||
partial void OnPermanentStatChanged(StatTypes statType)
|
partial void OnPermanentStatChanged(StatTypes statType)
|
||||||
{
|
{
|
||||||
if (Character == null || Character.Removed) { return; }
|
if (Character == null || Character.Removed) { return; }
|
||||||
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.UpdatePermanentStatsEventData());
|
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.UpdatePermanentStatsEventData(statType));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ServerWrite(IWriteMessage msg)
|
public void ServerWrite(IWriteMessage msg)
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ namespace Barotrauma
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves bots in multiplayer
|
/// Saves bots in multiplayer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SaveMultiplayer(XElement root)
|
public XElement SaveMultiplayer(XElement parentElement)
|
||||||
{
|
{
|
||||||
XElement saveElement = new XElement("bots", new XAttribute("hasbots", HasBots));
|
var element = new XElement("bots", new XAttribute("hasbots", HasBots));
|
||||||
foreach (CharacterInfo info in characterInfos)
|
foreach (CharacterInfo info in characterInfos)
|
||||||
{
|
{
|
||||||
if (Level.Loaded != null)
|
if (Level.Loaded != null)
|
||||||
@@ -35,13 +35,13 @@ namespace Barotrauma
|
|||||||
if (!info.IsNewHire && (info.Character == null || info.Character.IsDead)) { continue; }
|
if (!info.IsNewHire && (info.Character == null || info.Character.IsDead)) { continue; }
|
||||||
}
|
}
|
||||||
|
|
||||||
XElement characterElement = info.Save(saveElement);
|
XElement characterElement = info.Save(element);
|
||||||
if (info.InventoryData != null) { characterElement.Add(info.InventoryData); }
|
if (info.InventoryData != null) { characterElement.Add(info.InventoryData); }
|
||||||
if (info.HealthData != null) { characterElement.Add(info.HealthData); }
|
if (info.HealthData != null) { characterElement.Add(info.HealthData); }
|
||||||
if (info.OrderData != null) { characterElement.Add(info.OrderData); }
|
if (info.OrderData != null) { characterElement.Add(info.OrderData); }
|
||||||
}
|
}
|
||||||
SaveActiveOrders(saveElement);
|
parentElement?.Add(element);
|
||||||
root.Add(saveElement);
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ServerWriteActiveOrders(IWriteMessage msg)
|
public void ServerWriteActiveOrders(IWriteMessage msg)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Extensions;
|
||||||
|
using Barotrauma.Networking;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -10,6 +11,31 @@ namespace Barotrauma
|
|||||||
protected set;
|
protected set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsOwner(Client client) => client != null && client.Connection == GameMain.Server.OwnerConnection;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// There is a client-side implementation of the method in <see cref="CampaignMode"/>
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowedToManageCampaign(Client client, ClientPermissions permissions)
|
||||||
|
{
|
||||||
|
//allow managing the campaign if the client has permissions, is the owner, or the only client in the server,
|
||||||
|
//or if no-one has management permissions
|
||||||
|
return
|
||||||
|
client.HasPermission(permissions) ||
|
||||||
|
client.HasPermission(ClientPermissions.ManageCampaign) ||
|
||||||
|
GameMain.Server.ConnectedClients.Count == 1 ||
|
||||||
|
IsOwner(client) ||
|
||||||
|
GameMain.Server.ConnectedClients.None(c => c.InGame && (IsOwner(c) || c.HasPermission(permissions)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AllowedToManageWallets(Client client)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
client.HasPermission(ClientPermissions.ManageCampaign) ||
|
||||||
|
client.HasPermission(ClientPermissions.ManageMoney) ||
|
||||||
|
IsOwner(client);
|
||||||
|
}
|
||||||
|
|
||||||
public override void ShowStartMessage()
|
public override void ShowStartMessage()
|
||||||
{
|
{
|
||||||
foreach (Mission mission in Missions)
|
foreach (Mission mission in Missions)
|
||||||
|
|||||||
+13
-70
@@ -163,29 +163,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private static bool IsOwner(Client client) => client != null && client.Connection == GameMain.Server.OwnerConnection;
|
private static bool IsOwner(Client client) => client != null && client.Connection == GameMain.Server.OwnerConnection;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// There is a client-side implementation of the method in <see cref="CampaignMode"/>
|
|
||||||
/// </summary>
|
|
||||||
public bool AllowedToManageCampaign(Client client, ClientPermissions permissions)
|
|
||||||
{
|
|
||||||
//allow managing the campaign if the client has permissions, is the owner, or the only client in the server,
|
|
||||||
//or if no-one has management permissions
|
|
||||||
return
|
|
||||||
client.HasPermission(permissions) ||
|
|
||||||
client.HasPermission(ClientPermissions.ManageCampaign) ||
|
|
||||||
GameMain.Server.ConnectedClients.Count == 1 ||
|
|
||||||
IsOwner(client) ||
|
|
||||||
GameMain.Server.ConnectedClients.None(c => c.InGame && (IsOwner(c) || c.HasPermission(permissions)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AllowedToManageWallets(Client client)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
client.HasPermission(ClientPermissions.ManageCampaign) ||
|
|
||||||
client.HasPermission(ClientPermissions.ManageMoney) ||
|
|
||||||
IsOwner(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveExperiencePoints(Client client)
|
public void SaveExperiencePoints(Client client)
|
||||||
{
|
{
|
||||||
ClearSavedExperiencePoints(client);
|
ClearSavedExperiencePoints(client);
|
||||||
@@ -200,14 +177,6 @@ namespace Barotrauma
|
|||||||
savedExperiencePoints.RemoveAll(s => s.SteamID != 0 && client.SteamID == s.SteamID || client.EndpointMatches(s.EndPoint));
|
savedExperiencePoints.RemoveAll(s => s.SteamID != 0 && client.SteamID == s.SteamID || client.EndpointMatches(s.EndPoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadPets()
|
|
||||||
{
|
|
||||||
if (petsElement != null)
|
|
||||||
{
|
|
||||||
PetBehavior.LoadPets(petsElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SavePlayers()
|
public void SavePlayers()
|
||||||
{
|
{
|
||||||
//refresh the character data of clients who are still in the server
|
//refresh the character data of clients who are still in the server
|
||||||
@@ -261,8 +230,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
characterData.ForEach(cd => cd.HasSpawned = false);
|
characterData.ForEach(cd => cd.HasSpawned = false);
|
||||||
|
|
||||||
petsElement = new XElement("pets");
|
SavePets();
|
||||||
PetBehavior.SavePets(petsElement);
|
|
||||||
|
|
||||||
//remove all items that are in someone's inventory
|
//remove all items that are in someone's inventory
|
||||||
foreach (Character c in Character.CharacterList)
|
foreach (Character c in Character.CharacterList)
|
||||||
@@ -285,6 +253,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
c.Inventory.DeleteAllItems();
|
c.Inventory.DeleteAllItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SaveActiveOrders();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MoveDiscardedCharacterBalancesToBank()
|
public void MoveDiscardedCharacterBalancesToBank()
|
||||||
@@ -348,44 +318,10 @@ namespace Barotrauma
|
|||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
SavePlayers();
|
SavePlayers();
|
||||||
|
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
LeaveUnconnectedSubs(leavingSub);
|
||||||
if (leavingSub != Submarine.MainSub && !leavingSub.DockedTo.Contains(Submarine.MainSub))
|
|
||||||
{
|
|
||||||
Submarine.MainSub = leavingSub;
|
|
||||||
GameMain.GameSession.Submarine = leavingSub;
|
|
||||||
GameMain.GameSession.SubmarineInfo = leavingSub.Info;
|
|
||||||
leavingSub.Info.FilePath = System.IO.Path.Combine(SaveUtil.TempPath, leavingSub.Info.Name + ".sub");
|
|
||||||
var subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
|
||||||
GameMain.GameSession.OwnedSubmarines.Add(leavingSub.Info);
|
|
||||||
foreach (Submarine sub in subsToLeaveBehind)
|
|
||||||
{
|
|
||||||
GameMain.GameSession.OwnedSubmarines.RemoveAll(s => s != leavingSub.Info && s.Name == sub.Info.Name);
|
|
||||||
MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine);
|
|
||||||
LinkedSubmarine.CreateDummy(leavingSub, sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NextLevel = newLevel;
|
NextLevel = newLevel;
|
||||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
|
||||||
|
|
||||||
if (PendingSubmarineSwitch != null)
|
|
||||||
{
|
|
||||||
SubmarineInfo previousSub = GameMain.GameSession.SubmarineInfo;
|
|
||||||
GameMain.GameSession.SubmarineInfo = PendingSubmarineSwitch;
|
|
||||||
|
|
||||||
for (int i = 0; i < GameMain.GameSession.OwnedSubmarines.Count; i++)
|
|
||||||
{
|
|
||||||
if (GameMain.GameSession.OwnedSubmarines[i].Name == previousSub.Name)
|
|
||||||
{
|
|
||||||
GameMain.GameSession.OwnedSubmarines[i] = previousSub;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||||
PendingSubmarineSwitch = null;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -977,6 +913,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
NetWalletTransfer transfer = INetSerializableStruct.Read<NetWalletTransfer>(msg);
|
NetWalletTransfer transfer = INetSerializableStruct.Read<NetWalletTransfer>(msg);
|
||||||
|
|
||||||
|
if (GameMain.Server is null) { return; }
|
||||||
|
|
||||||
switch (transfer.Sender)
|
switch (transfer.Sender)
|
||||||
{
|
{
|
||||||
case Some<ushort> { Value: var id }:
|
case Some<ushort> { Value: var id }:
|
||||||
@@ -992,7 +930,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (transfer.Receiver is Some<ushort> { Value: var receiverId } && receiverId == sender.CharacterID)
|
if (transfer.Receiver is Some<ushort> { Value: var receiverId } && receiverId == sender.CharacterID)
|
||||||
{
|
{
|
||||||
GameMain.Server?.Voting.StartTransferVote(sender, null, transfer.Amount, sender);
|
if (transfer.Amount > GameMain.Server.ServerSettings.MaximumTransferRequest) { return; }
|
||||||
|
GameMain.Server.Voting.StartTransferVote(sender, null, transfer.Amount, sender);
|
||||||
GameServer.Log($"{sender.Name} started a vote to transfer {transfer.Amount} mk from the bank.", ServerLog.MessageType.Money);
|
GameServer.Log($"{sender.Name} started a vote to transfer {transfer.Amount} mk from the bank.", ServerLog.MessageType.Money);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1301,7 +1240,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
// save bots
|
// save bots
|
||||||
CrewManager.SaveMultiplayer(modeElement);
|
var crewManagerElement = CrewManager.SaveMultiplayer(modeElement);
|
||||||
|
if (ActiveOrdersElement != null)
|
||||||
|
{
|
||||||
|
crewManagerElement.Add(ActiveOrdersElement);
|
||||||
|
}
|
||||||
|
|
||||||
XElement savedExperiencePointsElement = new XElement("SavedExperiencePoints");
|
XElement savedExperiencePointsElement = new XElement("SavedExperiencePoints");
|
||||||
foreach (var savedExperiencePoint in savedExperiencePoints)
|
foreach (var savedExperiencePoint in savedExperiencePoints)
|
||||||
|
|||||||
@@ -1,19 +1,27 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable
|
partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable, IClientSerializable
|
||||||
{
|
{
|
||||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||||
{
|
{
|
||||||
msg.Write(docked);
|
msg.Write(docked);
|
||||||
|
|
||||||
if (docked)
|
if (docked)
|
||||||
{
|
{
|
||||||
msg.Write(DockingTarget.item.ID);
|
msg.Write(DockingTarget.item.ID);
|
||||||
msg.Write(IsLocked);
|
msg.Write(IsLocked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void ServerEventRead(IReadMessage msg, Client c)
|
||||||
|
{
|
||||||
|
var allowOutpostAutoDocking = (AllowOutpostAutoDocking)msg.ReadByte();
|
||||||
|
if (outpostAutoDockingPromptShown &&
|
||||||
|
(GameMain.GameSession?.Campaign?.AllowedToManageCampaign(c, ClientPermissions.ManageMap) ?? false))
|
||||||
|
{
|
||||||
|
this.allowOutpostAutoDocking = allowOutpostAutoDocking;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ namespace Barotrauma.Items.Components
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Move(Vector2 amount)
|
public override void Move(Vector2 amount, bool ignoreContacts = false)
|
||||||
{
|
{
|
||||||
//do nothing
|
//do nothing
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ namespace Barotrauma.Items.Components
|
|||||||
for (int i = 0; i < Connections.Count; i++)
|
for (int i = 0; i < Connections.Count; i++)
|
||||||
{
|
{
|
||||||
wires[i] = new List<Wire>();
|
wires[i] = new List<Wire>();
|
||||||
for (int j = 0; j < Connections[i].MaxWires; j++)
|
uint wireCount = msg.ReadVariableUInt32();
|
||||||
|
for (int j = 0; j < wireCount; j++)
|
||||||
{
|
{
|
||||||
ushort wireId = msg.ReadUInt16();
|
ushort wireId = msg.ReadUInt16();
|
||||||
|
|
||||||
@@ -91,12 +92,8 @@ namespace Barotrauma.Items.Components
|
|||||||
//go through existing wire links
|
//go through existing wire links
|
||||||
for (int i = 0; i < Connections.Count; i++)
|
for (int i = 0; i < Connections.Count; i++)
|
||||||
{
|
{
|
||||||
int j = -1;
|
foreach (Wire existingWire in Connections[i].Wires.ToArray())
|
||||||
foreach (Wire existingWire in Connections[i].Wires)
|
|
||||||
{
|
{
|
||||||
j++;
|
|
||||||
if (existingWire == null) { continue; }
|
|
||||||
|
|
||||||
//existing wire not in the list of new wires -> disconnect it
|
//existing wire not in the list of new wires -> disconnect it
|
||||||
if (!wires[i].Contains(existingWire))
|
if (!wires[i].Contains(existingWire))
|
||||||
{
|
{
|
||||||
@@ -163,7 +160,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections[i].SetWire(j, null);
|
Connections[i].DisconnectWire(existingWire);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
|||||||
foreach (BallastFloraBranch branch in Branches)
|
foreach (BallastFloraBranch branch in Branches)
|
||||||
{
|
{
|
||||||
//don't notify about minuscule amounts of damage (<= 1.0f)
|
//don't notify about minuscule amounts of damage (<= 1.0f)
|
||||||
if (branch.AccumulatedDamage > 1.0f)
|
if (Math.Abs(branch.AccumulatedDamage) > 1.0f)
|
||||||
{
|
{
|
||||||
CreateNetworkMessage(new BranchDamageEventData(branch));
|
CreateNetworkMessage(new BranchDamageEventData(branch));
|
||||||
branch.AccumulatedDamage = 0.0f;
|
branch.AccumulatedDamage = 0.0f;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace Barotrauma.Networking
|
|||||||
public UInt16 LastRecvCampaignUpdate = 0;
|
public UInt16 LastRecvCampaignUpdate = 0;
|
||||||
public UInt16 LastRecvCampaignSave = 0;
|
public UInt16 LastRecvCampaignSave = 0;
|
||||||
|
|
||||||
public Pair<UInt16, float> LastCampaignSaveSendTime;
|
public (UInt16 saveId, float time) LastCampaignSaveSendTime;
|
||||||
|
|
||||||
public readonly List<ChatMessage> ChatMsgQueue = new List<ChatMessage>();
|
public readonly List<ChatMessage> ChatMsgQueue = new List<ChatMessage>();
|
||||||
public UInt16 LastChatMsgQueueID;
|
public UInt16 LastChatMsgQueueID;
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ namespace Barotrauma.Networking
|
|||||||
StartTransfer(inc.Sender, FileTransferType.CampaignSave, GameMain.GameSession.SavePath);
|
StartTransfer(inc.Sender, FileTransferType.CampaignSave, GameMain.GameSession.SavePath);
|
||||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
|
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
|
||||||
{
|
{
|
||||||
client.LastCampaignSaveSendTime = new Pair<ushort, float>(campaign.LastSaveID, (float)Lidgren.Network.NetTime.Now);
|
client.LastCampaignSaveSendTime = (campaign.LastSaveID, (float)Lidgren.Network.NetTime.Now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -955,7 +955,9 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
if (Level.Loaded != null)
|
if (Level.Loaded != null)
|
||||||
{
|
{
|
||||||
errorLines.Add("Level: " + Level.Loaded.Seed + ", " + string.Join(", ", Level.Loaded.EqualityCheckValues.Select(cv => cv.ToString("X"))));
|
errorLines.Add("Level: " + Level.Loaded.Seed + ", "
|
||||||
|
+ string.Join("; ", Level.Loaded.EqualityCheckValues.Select(cv
|
||||||
|
=> cv.Key + "=" + cv.Value.ToString("X"))));
|
||||||
errorLines.Add("Entity count before generating level: " + Level.Loaded.EntityCountBeforeGenerate);
|
errorLines.Add("Entity count before generating level: " + Level.Loaded.EntityCountBeforeGenerate);
|
||||||
errorLines.Add("Entities:");
|
errorLines.Add("Entities:");
|
||||||
foreach (Entity e in Level.Loaded.EntitiesBeforeGenerate.OrderBy(e => e.CreationIndex))
|
foreach (Entity e in Level.Loaded.EntitiesBeforeGenerate.OrderBy(e => e.CreationIndex))
|
||||||
@@ -1548,11 +1550,11 @@ namespace Barotrauma.Networking
|
|||||||
NetIdUtils.IdMoreRecent(campaign.LastSaveID, c.LastRecvCampaignSave))
|
NetIdUtils.IdMoreRecent(campaign.LastSaveID, c.LastRecvCampaignSave))
|
||||||
{
|
{
|
||||||
//already sent an up-to-date campaign save
|
//already sent an up-to-date campaign save
|
||||||
if (c.LastCampaignSaveSendTime != null && campaign.LastSaveID == c.LastCampaignSaveSendTime.First)
|
if (c.LastCampaignSaveSendTime != default && campaign.LastSaveID == c.LastCampaignSaveSendTime.saveId)
|
||||||
{
|
{
|
||||||
//the save was sent less than 5 second ago, don't attempt to resend yet
|
//the save was sent less than 5 second ago, don't attempt to resend yet
|
||||||
//(the client may have received it but hasn't acked us yet)
|
//(the client may have received it but hasn't acked us yet)
|
||||||
if (c.LastCampaignSaveSendTime.Second > NetTime.Now - 5.0f)
|
if (c.LastCampaignSaveSendTime.time > NetTime.Now - 5.0f)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1561,7 +1563,7 @@ namespace Barotrauma.Networking
|
|||||||
if (!FileSender.ActiveTransfers.Any(t => t.Connection == c.Connection && t.FileType == FileTransferType.CampaignSave))
|
if (!FileSender.ActiveTransfers.Any(t => t.Connection == c.Connection && t.FileType == FileTransferType.CampaignSave))
|
||||||
{
|
{
|
||||||
FileSender.StartTransfer(c.Connection, FileTransferType.CampaignSave, GameMain.GameSession.SavePath);
|
FileSender.StartTransfer(c.Connection, FileTransferType.CampaignSave, GameMain.GameSession.SavePath);
|
||||||
c.LastCampaignSaveSendTime = new Pair<ushort, float>(campaign.LastSaveID, (float)NetTime.Now);
|
c.LastCampaignSaveSendTime = (campaign.LastSaveID, (float)NetTime.Now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2193,7 +2195,7 @@ namespace Barotrauma.Networking
|
|||||||
Level.Loaded?.SpawnNPCs();
|
Level.Loaded?.SpawnNPCs();
|
||||||
Level.Loaded?.SpawnCorpses();
|
Level.Loaded?.SpawnCorpses();
|
||||||
Level.Loaded?.PrepareBeaconStation();
|
Level.Loaded?.PrepareBeaconStation();
|
||||||
AutoItemPlacer.PlaceIfNeeded();
|
AutoItemPlacer.SpawnItems();
|
||||||
|
|
||||||
CrewManager crewManager = campaign?.CrewManager;
|
CrewManager crewManager = campaign?.CrewManager;
|
||||||
|
|
||||||
@@ -2388,7 +2390,9 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
|
|
||||||
campaign?.LoadPets();
|
campaign?.LoadPets();
|
||||||
crewManager?.LoadActiveOrders();
|
campaign?.LoadActiveOrders();
|
||||||
|
|
||||||
|
campaign?.CargoManager.InitPurchasedIDCards();
|
||||||
|
|
||||||
foreach (Submarine sub in Submarine.MainSubs)
|
foreach (Submarine sub in Submarine.MainSubs)
|
||||||
{
|
{
|
||||||
@@ -2400,7 +2404,7 @@ namespace Barotrauma.Networking
|
|||||||
spawnList.Add(new PurchasedItem(kvp.Key, kvp.Value, buyer: null));
|
spawnList.Add(new PurchasedItem(kvp.Key, kvp.Value, buyer: null));
|
||||||
}
|
}
|
||||||
|
|
||||||
CargoManager.CreateItems(spawnList, sub);
|
CargoManager.CreateItems(spawnList, sub, cargoManager: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
TraitorManager = null;
|
TraitorManager = null;
|
||||||
@@ -2531,10 +2535,9 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
msg.Write(mission.Prefab.Identifier);
|
msg.Write(mission.Prefab.Identifier);
|
||||||
}
|
}
|
||||||
msg.Write((byte)GameMain.GameSession.Level.EqualityCheckValues.Count);
|
foreach (Level.LevelGenStage stage in Enum.GetValues(typeof(Level.LevelGenStage)).OfType<Level.LevelGenStage>().OrderBy(s => s))
|
||||||
foreach (int equalityCheckValue in GameMain.GameSession.Level.EqualityCheckValues)
|
|
||||||
{
|
{
|
||||||
msg.Write(equalityCheckValue);
|
msg.Write(GameMain.GameSession.Level.EqualityCheckValues[stage]);
|
||||||
}
|
}
|
||||||
foreach (Mission mission in GameMain.GameSession.Missions)
|
foreach (Mission mission in GameMain.GameSession.Missions)
|
||||||
{
|
{
|
||||||
@@ -3178,9 +3181,9 @@ namespace Barotrauma.Networking
|
|||||||
Client recipient = connectedClients.Find(c => c.Connection == transfer.Connection);
|
Client recipient = connectedClients.Find(c => c.Connection == transfer.Connection);
|
||||||
if (transfer.FileType == FileTransferType.CampaignSave &&
|
if (transfer.FileType == FileTransferType.CampaignSave &&
|
||||||
(transfer.Status == FileTransferStatus.Sending || transfer.Status == FileTransferStatus.Finished) &&
|
(transfer.Status == FileTransferStatus.Sending || transfer.Status == FileTransferStatus.Finished) &&
|
||||||
recipient.LastCampaignSaveSendTime != null)
|
recipient.LastCampaignSaveSendTime != default)
|
||||||
{
|
{
|
||||||
recipient.LastCampaignSaveSendTime.Second = (float)Lidgren.Network.NetTime.Now;
|
recipient.LastCampaignSaveSendTime.time = (float)NetTime.Now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -278,12 +278,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
static bool isValid(Item item)
|
static bool isValid(Item item)
|
||||||
{
|
{
|
||||||
return item.Prefab.Identifier == "idcard" || item.GetComponent<RangedWeapon>() != null || item.GetComponent<MeleeWeapon>() != null;
|
return item.GetComponent<IdCard>() != null || item.GetComponent<RangedWeapon>() != null || item.GetComponent<MeleeWeapon>() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundItem == null) { return; }
|
if (foundItem == null) { return; }
|
||||||
|
|
||||||
bool isIdCard = ((MapEntity)foundItem).Prefab.Identifier == "idcard";
|
bool isIdCard = foundItem.GetComponent<IdCard>() != null;
|
||||||
bool isWeapon = foundItem.GetComponent<RangedWeapon>() != null || foundItem.GetComponent<MeleeWeapon>() != null;
|
bool isWeapon = foundItem.GetComponent<RangedWeapon>() != null || foundItem.GetComponent<MeleeWeapon>() != null;
|
||||||
|
|
||||||
if (isIdCard)
|
if (isIdCard)
|
||||||
|
|||||||
@@ -441,32 +441,43 @@ namespace Barotrauma.Networking
|
|||||||
GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", GameServer.ClientLogName(clients[i]), clients[i].Connection?.EndPointString, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
|
GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", GameServer.ClientLogName(clients[i]), clients[i].Connection?.EndPointString, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (divingSuitPrefab != null && oxyPrefab != null && RespawnShuttle != null)
|
if (RespawnShuttle != null)
|
||||||
{
|
{
|
||||||
Vector2 pos = cargoSp == null ? character.Position : cargoSp.Position;
|
Vector2 pos = cargoSp == null ? character.Position : cargoSp.Position;
|
||||||
if (divingSuitPrefab != null && oxyPrefab != null)
|
if (divingSuitPrefab != null)
|
||||||
{
|
{
|
||||||
var divingSuit = new Item(divingSuitPrefab, pos, respawnSub);
|
var divingSuit = new Item(divingSuitPrefab, pos, respawnSub);
|
||||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(divingSuit));
|
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(divingSuit));
|
||||||
respawnItems.Add(divingSuit);
|
respawnItems.Add(divingSuit);
|
||||||
|
|
||||||
var oxyTank = new Item(oxyPrefab, pos, respawnSub);
|
if (oxyPrefab != null && divingSuit.GetComponent<ItemContainer>() != null)
|
||||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(oxyTank));
|
{
|
||||||
divingSuit.Combine(oxyTank, user: null);
|
var oxyTank = new Item(oxyPrefab, pos, respawnSub);
|
||||||
respawnItems.Add(oxyTank);
|
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(oxyTank));
|
||||||
|
divingSuit.Combine(oxyTank, user: null);
|
||||||
|
respawnItems.Add(oxyTank);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scooterPrefab != null && batteryPrefab != null)
|
if (!(GameMain.GameSession.GameMode is CampaignMode))
|
||||||
{
|
{
|
||||||
var scooter = new Item(scooterPrefab, pos, respawnSub);
|
if (scooterPrefab != null)
|
||||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(scooter));
|
{
|
||||||
|
var scooter = new Item(scooterPrefab, pos, respawnSub);
|
||||||
var battery = new Item(batteryPrefab, pos, respawnSub);
|
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(scooter));
|
||||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(battery));
|
respawnItems.Add(scooter);
|
||||||
|
if (batteryPrefab != null)
|
||||||
scooter.Combine(battery, user: null);
|
{
|
||||||
respawnItems.Add(scooter);
|
var battery = new Item(batteryPrefab, pos, respawnSub);
|
||||||
respawnItems.Add(battery);
|
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(battery));
|
||||||
|
scooter.Combine(battery, user: null);
|
||||||
|
respawnItems.Add(battery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (respawnContainer != null)
|
||||||
|
{
|
||||||
|
AutoItemPlacer.RegenerateLoot(RespawnShuttle, respawnContainer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +515,7 @@ namespace Barotrauma.Networking
|
|||||||
//add the ID card tags they should've gotten when spawning in the shuttle
|
//add the ID card tags they should've gotten when spawning in the shuttle
|
||||||
foreach (Item item in character.Inventory.AllItems.Distinct())
|
foreach (Item item in character.Inventory.AllItems.Distinct())
|
||||||
{
|
{
|
||||||
if (item.Prefab.Identifier != "idcard") { continue; }
|
if (item.GetComponent<IdCard>() == null) { continue; }
|
||||||
foreach (string s in shuttleSpawnPoints[i].IdCardTags)
|
foreach (string s in shuttleSpawnPoints[i].IdCardTags)
|
||||||
{
|
{
|
||||||
item.AddTag(s);
|
item.AddTag(s);
|
||||||
|
|||||||
@@ -44,12 +44,14 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
GameMain.Server?.SwitchSubmarine();
|
GameMain.Server?.SwitchSubmarine();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
voting.RegisterRejectedVote(this);
|
||||||
|
}
|
||||||
voting.StopSubmarineVote(passed);
|
voting.StopSubmarineVote(passed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IVote ActiveVote;
|
|
||||||
|
|
||||||
public class TransferVote : IVote
|
public class TransferVote : IVote
|
||||||
{
|
{
|
||||||
public Client VoteStarter { get; }
|
public Client VoteStarter { get; }
|
||||||
@@ -83,12 +85,22 @@ namespace Barotrauma
|
|||||||
toWallet.Give(TransferAmount);
|
toWallet.Give(TransferAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
voting.RegisterRejectedVote(this);
|
||||||
|
}
|
||||||
voting.StopMoneyTransferVote(passed);
|
voting.StopMoneyTransferVote(passed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IVote ActiveVote;
|
||||||
|
|
||||||
private static readonly Queue<IVote> pendingVotes = new Queue<IVote>();
|
private static readonly Queue<IVote> pendingVotes = new Queue<IVote>();
|
||||||
|
|
||||||
|
private readonly TimeSpan rejectedVoteCooldown = new TimeSpan(0, 1, 0);
|
||||||
|
|
||||||
|
private readonly Dictionary<Client, (VoteType voteType, DateTime time)> rejectedVoteTimes = new Dictionary<Client, (VoteType voteType, DateTime time)>();
|
||||||
|
|
||||||
private void StartSubmarineVote(SubmarineInfo subInfo, VoteType voteType, Client sender)
|
private void StartSubmarineVote(SubmarineInfo subInfo, VoteType voteType, Client sender)
|
||||||
{
|
{
|
||||||
if (ActiveVote == null)
|
if (ActiveVote == null)
|
||||||
@@ -136,6 +148,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void StartTransferVote(Client starter, Client from, int transferAmount, Client to)
|
public void StartTransferVote(Client starter, Client from, int transferAmount, Client to)
|
||||||
{
|
{
|
||||||
|
if (ShouldRejectVote(starter, VoteType.TransferMoney))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (ActiveVote == null)
|
if (ActiveVote == null)
|
||||||
{
|
{
|
||||||
starter.SetVote(VoteType.TransferMoney, 2);
|
starter.SetVote(VoteType.TransferMoney, 2);
|
||||||
@@ -156,6 +172,31 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ShouldRejectVote(Client sender, VoteType voteType)
|
||||||
|
{
|
||||||
|
if (rejectedVoteTimes.ContainsKey(sender))
|
||||||
|
{
|
||||||
|
TimeSpan remainingCooldown = (rejectedVoteTimes[sender].time + rejectedVoteCooldown) - DateTime.Now;
|
||||||
|
if (rejectedVoteTimes[sender].voteType == voteType &&
|
||||||
|
remainingCooldown.TotalSeconds > 0)
|
||||||
|
{
|
||||||
|
GameMain.Server.SendDirectChatMessage(
|
||||||
|
TextManager.FormatServerMessage("voterejectedpleasewait", ("[time]", ((int)remainingCooldown.TotalSeconds).ToString())),
|
||||||
|
sender, ChatMessageType.ServerMessageBox);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RegisterRejectedVote(IVote vote)
|
||||||
|
{
|
||||||
|
if (vote.VoteStarter != null)
|
||||||
|
{
|
||||||
|
rejectedVoteTimes[vote.VoteStarter] = (vote.VoteType, DateTime.Now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Update(float deltaTime)
|
public void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
if (ActiveVote == null) { return; }
|
if (ActiveVote == null) { return; }
|
||||||
@@ -227,7 +268,6 @@ namespace Barotrauma
|
|||||||
GameServer.Log(GameServer.ClientLogName(sender) + (ready ? " is ready to start the game." : " is not ready to start the game."), ServerLog.MessageType.ServerMessage);
|
GameServer.Log(GameServer.ClientLogName(sender) + (ready ? " is ready to start the game." : " is not ready to start the game."), ServerLog.MessageType.ServerMessage);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VoteType.PurchaseAndSwitchSub:
|
case VoteType.PurchaseAndSwitchSub:
|
||||||
case VoteType.PurchaseSub:
|
case VoteType.PurchaseSub:
|
||||||
case VoteType.SwitchSub:
|
case VoteType.SwitchSub:
|
||||||
@@ -240,18 +280,25 @@ namespace Barotrauma
|
|||||||
int amount = inc.ReadInt32();
|
int amount = inc.ReadInt32();
|
||||||
int fromClientId = inc.ReadByte();
|
int fromClientId = inc.ReadByte();
|
||||||
int toClientId = inc.ReadByte();
|
int toClientId = inc.ReadByte();
|
||||||
pendingVotes.Enqueue(new TransferVote(sender,
|
if (!ShouldRejectVote(sender, voteType))
|
||||||
GameMain.Server.ConnectedClients.Find(c => c.ID == fromClientId),
|
{
|
||||||
amount,
|
pendingVotes.Enqueue(new TransferVote(sender,
|
||||||
GameMain.Server.ConnectedClients.Find(c => c.ID == toClientId)));
|
GameMain.Server.ConnectedClients.Find(c => c.ID == fromClientId),
|
||||||
|
amount,
|
||||||
|
GameMain.Server.ConnectedClients.Find(c => c.ID == toClientId)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string subName = inc.ReadString();
|
string subName = inc.ReadString();
|
||||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
|
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
|
||||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign && (campaign.CanPurchaseSub(subInfo, sender) || GameMain.GameSession.IsSubmarineOwned(subInfo)))
|
if (!ShouldRejectVote(sender, voteType))
|
||||||
{
|
{
|
||||||
StartSubmarineVote(subInfo, voteType, sender);
|
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign &&
|
||||||
|
(campaign.CanPurchaseSub(subInfo, sender) || GameMain.GameSession.IsSubmarineOwned(subInfo)))
|
||||||
|
{
|
||||||
|
StartSubmarineVote(subInfo, voteType, sender);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.17.15.0</Version>
|
<Version>0.18.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -31,6 +31,17 @@ namespace Barotrauma
|
|||||||
if (_previousAiTarget != null)
|
if (_previousAiTarget != null)
|
||||||
{
|
{
|
||||||
_lastAiTarget = _previousAiTarget;
|
_lastAiTarget = _previousAiTarget;
|
||||||
|
if (_selectedAiTarget != null)
|
||||||
|
{
|
||||||
|
if (_selectedAiTarget.Entity is Item i && _previousAiTarget.Entity is Character c)
|
||||||
|
{
|
||||||
|
if (i.IsOwnedBy(c)) { return; }
|
||||||
|
}
|
||||||
|
else if (_previousAiTarget.Entity is Item it && _selectedAiTarget.Entity is Character ch)
|
||||||
|
{
|
||||||
|
if (it.IsOwnedBy(ch)) { return; }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OnTargetChanged(_previousAiTarget, _selectedAiTarget);
|
OnTargetChanged(_previousAiTarget, _selectedAiTarget);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1055,6 +1055,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private Vector2 attackWorldPos;
|
private Vector2 attackWorldPos;
|
||||||
private Vector2 attackSimPos;
|
private Vector2 attackSimPos;
|
||||||
|
private float reachTimer;
|
||||||
|
// How long the monster tries to reach out for the target when it's close to it before ignoring it.
|
||||||
|
private const float reachTimeOut = 10;
|
||||||
|
|
||||||
private void UpdateAttack(float deltaTime)
|
private void UpdateAttack(float deltaTime)
|
||||||
{
|
{
|
||||||
@@ -1427,6 +1430,22 @@ namespace Barotrauma
|
|||||||
// Check that we can reach the target
|
// Check that we can reach the target
|
||||||
distance = toTarget.Length();
|
distance = toTarget.Length();
|
||||||
canAttack = distance < AttackLimb.attack.Range;
|
canAttack = distance < AttackLimb.attack.Range;
|
||||||
|
if (canAttack)
|
||||||
|
{
|
||||||
|
reachTimer = 0;
|
||||||
|
}
|
||||||
|
else if (selectedTargetingParams.AttackPattern == AttackPattern.Straight && distance < AttackLimb.attack.Range * 5)
|
||||||
|
{
|
||||||
|
reachTimer += deltaTime;
|
||||||
|
if (reachTimer > reachTimeOut)
|
||||||
|
{
|
||||||
|
reachTimer = 0;
|
||||||
|
IgnoreTarget(SelectedAiTarget);
|
||||||
|
State = AIState.Idle;
|
||||||
|
ResetAITarget();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Crouch if the target is down (only humanoids), so that we can reach it.
|
// Crouch if the target is down (only humanoids), so that we can reach it.
|
||||||
if (Character.AnimController is HumanoidAnimController humanoidAnimController && distance < AttackLimb.attack.Range * 2)
|
if (Character.AnimController is HumanoidAnimController humanoidAnimController && distance < AttackLimb.attack.Range * 2)
|
||||||
@@ -1958,9 +1977,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (!isFriendly && attackResult.Damage > 0.0f)
|
if (!isFriendly && attackResult.Damage > 0.0f)
|
||||||
{
|
{
|
||||||
ignoredTargets.Remove(attacker.AiTarget);
|
|
||||||
bool canAttack = attacker.Submarine == Character.Submarine && canAttackCharacters || attacker.Submarine != null && canAttackWalls;
|
bool canAttack = attacker.Submarine == Character.Submarine && canAttackCharacters || attacker.Submarine != null && canAttackWalls;
|
||||||
if (AIParams.AttackWhenProvoked && canAttack)
|
if (AIParams.AttackWhenProvoked && canAttack && !ignoredTargets.Contains(attacker.AiTarget))
|
||||||
{
|
{
|
||||||
if (attacker.IsHusk)
|
if (attacker.IsHusk)
|
||||||
{
|
{
|
||||||
@@ -3476,6 +3494,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
observeTimer = targetParams.Timer * Rand.Range(0.75f, 1.25f);
|
observeTimer = targetParams.Timer * Rand.Range(0.75f, 1.25f);
|
||||||
}
|
}
|
||||||
|
reachTimer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnStateChanged(AIState from, AIState to)
|
protected override void OnStateChanged(AIState from, AIState to)
|
||||||
@@ -3496,6 +3515,7 @@ namespace Barotrauma
|
|||||||
SetStateResetTimer();
|
SetStateResetTimer();
|
||||||
}
|
}
|
||||||
blockCheckTimer = 0;
|
blockCheckTimer = 0;
|
||||||
|
reachTimer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetStateResetTimer() => stateResetTimer = stateResetCooldown * Rand.Range(0.75f, 1.25f);
|
private void SetStateResetTimer() => stateResetTimer = stateResetCooldown * Rand.Range(0.75f, 1.25f);
|
||||||
|
|||||||
@@ -59,7 +59,11 @@ namespace Barotrauma
|
|||||||
private readonly float enemyCheckInterval = 0.2f;
|
private readonly float enemyCheckInterval = 0.2f;
|
||||||
private readonly float enemySpotDistanceOutside = 800;
|
private readonly float enemySpotDistanceOutside = 800;
|
||||||
private readonly float enemySpotDistanceInside = 1000;
|
private readonly float enemySpotDistanceInside = 1000;
|
||||||
private float enemycheckTimer;
|
private float enemyCheckTimer;
|
||||||
|
|
||||||
|
private readonly float reportProblemsInterval = 1.0f;
|
||||||
|
private float reportProblemsTimer;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How far other characters can hear reports done by this character (e.g. reports for fires, intruders). Defaults to infinity.
|
/// How far other characters can hear reports done by this character (e.g. reports for fires, intruders). Defaults to infinity.
|
||||||
@@ -166,6 +170,7 @@ namespace Barotrauma
|
|||||||
objectiveManager = new AIObjectiveManager(c);
|
objectiveManager = new AIObjectiveManager(c);
|
||||||
reactTimer = GetReactionTime();
|
reactTimer = GetReactionTime();
|
||||||
SortTimer = Rand.Range(0f, sortObjectiveInterval);
|
SortTimer = Rand.Range(0f, sortObjectiveInterval);
|
||||||
|
reportProblemsTimer = Rand.Range(0f, reportProblemsInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime)
|
public override void Update(float deltaTime)
|
||||||
@@ -309,10 +314,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
// Spot enemies while staying outside or inside an enemy ship.
|
// Spot enemies while staying outside or inside an enemy ship.
|
||||||
// does not apply for escorted characters, such as prisoners or terrorists who have their own behavior
|
// does not apply for escorted characters, such as prisoners or terrorists who have their own behavior
|
||||||
enemycheckTimer -= deltaTime;
|
enemyCheckTimer -= deltaTime;
|
||||||
if (enemycheckTimer < 0)
|
if (enemyCheckTimer < 0)
|
||||||
{
|
{
|
||||||
enemycheckTimer = enemyCheckInterval * Rand.Range(0.75f, 1.25f);
|
enemyCheckTimer = enemyCheckInterval * Rand.Range(0.75f, 1.25f);
|
||||||
if (!objectiveManager.IsCurrentObjective<AIObjectiveCombat>())
|
if (!objectiveManager.IsCurrentObjective<AIObjectiveCombat>())
|
||||||
{
|
{
|
||||||
float closestDistance = 0;
|
float closestDistance = 0;
|
||||||
@@ -407,19 +412,29 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (Character.IsOnPlayerTeam)
|
if (Character.IsOnPlayerTeam)
|
||||||
{
|
{
|
||||||
VisibleHulls.ForEach(h => PropagateHullSafety(Character, h));
|
foreach (Hull h in VisibleHulls)
|
||||||
|
{
|
||||||
|
PropagateHullSafety(Character, h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Outpost npcs don't inform each other about threats, like crew members do.
|
foreach (Hull h in VisibleHulls)
|
||||||
VisibleHulls.ForEach(h => RefreshHullSafety(h));
|
{
|
||||||
|
RefreshHullSafety(h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Character.SpeechImpediment < 100.0f)
|
if (Character.SpeechImpediment < 100.0f)
|
||||||
{
|
{
|
||||||
if (Character.Submarine != null && (Character.Submarine.TeamID == Character.TeamID || Character.IsEscorted) && !Character.Submarine.Info.IsWreck)
|
reportProblemsTimer -= deltaTime;
|
||||||
|
if (reportProblemsTimer <= 0.0f)
|
||||||
{
|
{
|
||||||
ReportProblems();
|
if (Character.Submarine != null && (Character.Submarine.TeamID == Character.TeamID || Character.IsEscorted) && !Character.Submarine.Info.IsWreck)
|
||||||
|
{
|
||||||
|
ReportProblems();
|
||||||
|
}
|
||||||
|
reportProblemsTimer = reportProblemsInterval;
|
||||||
}
|
}
|
||||||
UpdateSpeaking();
|
UpdateSpeaking();
|
||||||
}
|
}
|
||||||
@@ -785,9 +800,10 @@ namespace Barotrauma
|
|||||||
if (item == null || item.Removed) { return; }
|
if (item == null || item.Removed) { return; }
|
||||||
if (!itemsToRelocate.Contains(item)) { return; }
|
if (!itemsToRelocate.Contains(item)) { return; }
|
||||||
var mainSub = Submarine.MainSub;
|
var mainSub = Submarine.MainSub;
|
||||||
if (item.ParentInventory != null)
|
Entity owner = item.GetRootInventoryOwner();
|
||||||
|
if (owner != null)
|
||||||
{
|
{
|
||||||
if (item.ParentInventory.Owner is Character c)
|
if (owner is Character c)
|
||||||
{
|
{
|
||||||
if (c.TeamID == CharacterTeamType.Team1 || c.TeamID == CharacterTeamType.Team2)
|
if (c.TeamID == CharacterTeamType.Team1 || c.TeamID == CharacterTeamType.Team2)
|
||||||
{
|
{
|
||||||
@@ -795,24 +811,37 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (item.ParentInventory.Owner.Submarine == mainSub)
|
else if (owner.Submarine == mainSub)
|
||||||
{
|
{
|
||||||
// Placed inside an inventory that's already in the main sub.
|
// Placed inside an inventory that's already in the main sub.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Laying on ground inside the main sub.
|
// Laying on the ground inside the main sub.
|
||||||
if (item.Submarine == mainSub)
|
if (item.Submarine == mainSub)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, mainSub);
|
if (owner != null && owner != item)
|
||||||
if (wp != null)
|
|
||||||
{
|
{
|
||||||
item.Submarine = mainSub;
|
item.Drop(null);
|
||||||
item.SetTransform(wp.SimPosition, 0.0f);
|
}
|
||||||
|
item.Submarine = mainSub;
|
||||||
|
Item newContainer = mainSub.FindContainerFor(item, onlyPrimary: false);
|
||||||
|
if (newContainer == null || !newContainer.OwnInventory.TryPutItem(item, user: null))
|
||||||
|
{
|
||||||
|
WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, mainSub) ?? WayPoint.GetRandom(SpawnType.Path, null, mainSub);
|
||||||
|
if (wp != null)
|
||||||
|
{
|
||||||
|
item.SetTransform(wp.SimPosition, 0.0f, findNewHull: false, setPrevTransform: false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.AddWarning($"Failed to relocate item {item.Prefab.Identifier} ({item.ID}), because no cargo spawn point could be found!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
itemsToRelocate.Remove(item);
|
itemsToRelocate.Remove(item);
|
||||||
|
DebugConsole.Log($"Relocated item {item.Prefab.Identifier} ({item.ID}) back to the main sub.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1149,7 +1178,7 @@ namespace Barotrauma
|
|||||||
bool isAttackerFightingEnemy = false;
|
bool isAttackerFightingEnemy = false;
|
||||||
float minorDamageThreshold = 1;
|
float minorDamageThreshold = 1;
|
||||||
float majorDamageThreshold = 20;
|
float majorDamageThreshold = 20;
|
||||||
if (attacker.TeamID == Character.TeamID)
|
if (attacker.TeamID == Character.TeamID && !attacker.IsInstigator)
|
||||||
{
|
{
|
||||||
minorDamageThreshold = 10;
|
minorDamageThreshold = 10;
|
||||||
majorDamageThreshold = 40;
|
majorDamageThreshold = 40;
|
||||||
@@ -1356,6 +1385,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
Character FindInstigator()
|
Character FindInstigator()
|
||||||
{
|
{
|
||||||
|
if (Character.IsInstigator)
|
||||||
|
{
|
||||||
|
return Character;
|
||||||
|
}
|
||||||
if (attacker.IsInstigator)
|
if (attacker.IsInstigator)
|
||||||
{
|
{
|
||||||
return attacker;
|
return attacker;
|
||||||
@@ -1545,7 +1578,7 @@ namespace Barotrauma
|
|||||||
(!requireEquipped || character.HasEquippedItem(i)) &&
|
(!requireEquipped || character.HasEquippedItem(i)) &&
|
||||||
(predicate == null || predicate(i)), recursive, matchingItems);
|
(predicate == null || predicate(i)), recursive, matchingItems);
|
||||||
items = matchingItems;
|
items = matchingItems;
|
||||||
return matchingItems.Any(i => i != null && (containedTag.IsEmpty || i.ContainedItems.Any(it => it.HasTag(containedTag) && it.ConditionPercentage > conditionPercentage)));
|
return matchingItems.Any(i => i != null && (containedTag.IsEmpty || i.OwnInventory == null || i.ContainedItems.Any(it => it.HasTag(containedTag) && it.ConditionPercentage > conditionPercentage)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void StructureDamaged(Structure structure, float damageAmount, Character character)
|
public static void StructureDamaged(Structure structure, float damageAmount, Character character)
|
||||||
@@ -1889,7 +1922,7 @@ namespace Barotrauma
|
|||||||
float fireFactor = 1;
|
float fireFactor = 1;
|
||||||
if (!ignoreFire)
|
if (!ignoreFire)
|
||||||
{
|
{
|
||||||
float calculateFire(Hull h) => h.FireSources.Count * 0.5f + h.FireSources.Sum(fs => fs.DamageRange) / h.Size.X;
|
static float calculateFire(Hull h) => h.FireSources.Count * 0.5f + h.FireSources.Sum(fs => fs.DamageRange) / h.Size.X;
|
||||||
// Even the smallest fire reduces the safety by 50%
|
// Even the smallest fire reduces the safety by 50%
|
||||||
float fire = visibleHulls == null ? calculateFire(hull) : visibleHulls.Sum(h => calculateFire(h));
|
float fire = visibleHulls == null ? calculateFire(hull) : visibleHulls.Sum(h => calculateFire(h));
|
||||||
fireFactor = MathHelper.Lerp(1, 0, MathHelper.Clamp(fire, 0, 1));
|
fireFactor = MathHelper.Lerp(1, 0, MathHelper.Clamp(fire, 0, 1));
|
||||||
@@ -1897,10 +1930,22 @@ namespace Barotrauma
|
|||||||
float enemyFactor = 1;
|
float enemyFactor = 1;
|
||||||
if (!ignoreEnemies)
|
if (!ignoreEnemies)
|
||||||
{
|
{
|
||||||
bool isValidTarget(Character e) => IsActive(e) && !IsFriendly(character, e) && !e.IsArrested;
|
int enemyCount = 0;
|
||||||
int enemyCount = visibleHulls == null ?
|
foreach (Character c in Character.CharacterList)
|
||||||
Character.CharacterList.Count(e => isValidTarget(e) && e.CurrentHull == hull) :
|
{
|
||||||
Character.CharacterList.Count(e => isValidTarget(e) && visibleHulls.Contains(e.CurrentHull));
|
if (visibleHulls == null)
|
||||||
|
{
|
||||||
|
if (c.CurrentHull != hull) { continue; }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!visibleHulls.Contains(c.CurrentHull)) { continue; }
|
||||||
|
}
|
||||||
|
if (IsActive(c) && !IsFriendly(character, c) && !c.IsArrested)
|
||||||
|
{
|
||||||
|
enemyCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
// The hull safety decreases 90% per enemy up to 100% (TODO: test smaller percentages)
|
// The hull safety decreases 90% per enemy up to 100% (TODO: test smaller percentages)
|
||||||
enemyFactor = MathHelper.Lerp(1, 0, MathHelper.Clamp(enemyCount * 0.9f, 0, 1));
|
enemyFactor = MathHelper.Lerp(1, 0, MathHelper.Clamp(enemyCount * 0.9f, 0, 1));
|
||||||
}
|
}
|
||||||
@@ -1911,6 +1956,7 @@ namespace Barotrauma
|
|||||||
if (item.Prefab != null && item.Prefab.IsDangerous)
|
if (item.Prefab != null && item.Prefab.IsDangerous)
|
||||||
{
|
{
|
||||||
dangerousItemsFactor = 0;
|
dangerousItemsFactor = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
float safety = oxygenFactor * waterFactor * fireFactor * enemyFactor * dangerousItemsFactor;
|
float safety = oxygenFactor * waterFactor * fireFactor * enemyFactor * dangerousItemsFactor;
|
||||||
|
|||||||
+1
-1
@@ -113,7 +113,7 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var connectionPanel = item.GetComponent<ConnectionPanel>();
|
var connectionPanel = item.GetComponent<ConnectionPanel>();
|
||||||
if (connectionPanel != null && connectionPanel.Connections.Any(c => c.Wires.Any(w => w != null)))
|
if (connectionPanel != null && connectionPanel.Connections.Any(c => c.Wires.Count > 0))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-15
@@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FarseerPhysics.Dynamics;
|
using FarseerPhysics.Dynamics;
|
||||||
|
using static Barotrauma.AIObjectiveFindSafety;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -775,7 +776,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
retreatTarget = findSafety.FindBestHull(HumanAIController.VisibleHulls, allowChangingTheSubmarine: character.TeamID != CharacterTeamType.FriendlyNPC);
|
HullSearchStatus hullSearchStatus = findSafety.FindBestHull(out Hull potentialSafeHull, HumanAIController.VisibleHulls, allowChangingSubmarine: character.TeamID != CharacterTeamType.FriendlyNPC);
|
||||||
|
if (hullSearchStatus != HullSearchStatus.Finished)
|
||||||
|
{
|
||||||
|
findSafety.UpdateSimpleEscape(deltaTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
retreatTarget = potentialSafeHull;
|
||||||
findHullTimer = findHullInterval * Rand.Range(0.9f, 1.1f);
|
findHullTimer = findHullInterval * Rand.Range(0.9f, 1.1f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -785,21 +792,21 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
UsePathingOutside = false
|
UsePathingOutside = false
|
||||||
},
|
},
|
||||||
onAbandon: () =>
|
onAbandon: () =>
|
||||||
|
{
|
||||||
|
if (Enemy != null && HumanAIController.VisibleHulls.Contains(Enemy.CurrentHull))
|
||||||
{
|
{
|
||||||
if (Enemy != null && HumanAIController.VisibleHulls.Contains(Enemy.CurrentHull))
|
// If in the same room with an enemy -> don't try to escape because we'd want to fight it
|
||||||
{
|
SteeringManager.Reset();
|
||||||
// If in the same room with an enemy -> don't try to escape because we'd want to fight it
|
RemoveSubObjective(ref retreatObjective);
|
||||||
SteeringManager.Reset();
|
}
|
||||||
RemoveSubObjective(ref retreatObjective);
|
else
|
||||||
}
|
{
|
||||||
else
|
// else abandon and fall back to find safety mode
|
||||||
{
|
Abandon = true;
|
||||||
// else abandon and fall back to find safety mode
|
}
|
||||||
Abandon = true;
|
},
|
||||||
}
|
onCompleted: () => RemoveSubObjective(ref retreatObjective));
|
||||||
},
|
|
||||||
onCompleted: () => RemoveSubObjective(ref retreatObjective));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+194
-116
@@ -1,4 +1,5 @@
|
|||||||
using FarseerPhysics;
|
using Barotrauma.Extensions;
|
||||||
|
using FarseerPhysics;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -192,9 +193,17 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
HullSearchStatus hullSearchStatus = FindBestHull(out Hull potentialSafeHull, allowChangingSubmarine: character.TeamID != CharacterTeamType.FriendlyNPC);
|
||||||
|
if (hullSearchStatus != HullSearchStatus.Finished)
|
||||||
|
{
|
||||||
|
UpdateSimpleEscape(deltaTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
searchHullTimer = SearchHullInterval * Rand.Range(0.9f, 1.1f);
|
searchHullTimer = SearchHullInterval * Rand.Range(0.9f, 1.1f);
|
||||||
previousSafeHull = currentSafeHull;
|
previousSafeHull = currentSafeHull;
|
||||||
currentSafeHull = FindBestHull(allowChangingTheSubmarine: character.TeamID != CharacterTeamType.FriendlyNPC);
|
currentSafeHull = potentialSafeHull;
|
||||||
|
|
||||||
cannotFindSafeHull = currentSafeHull == null || HumanAIController.NeedsDivingGear(currentSafeHull, out _);
|
cannotFindSafeHull = currentSafeHull == null || HumanAIController.NeedsDivingGear(currentSafeHull, out _);
|
||||||
if (currentSafeHull == null)
|
if (currentSafeHull == null)
|
||||||
{
|
{
|
||||||
@@ -250,58 +259,122 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (subObjectives.Any(so => so.CanBeCompleted)) { return; }
|
if (subObjectives.Any(so => so.CanBeCompleted)) { return; }
|
||||||
if (currentHull != null)
|
UpdateSimpleEscape(deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateSimpleEscape(float deltaTime)
|
||||||
|
{
|
||||||
|
Vector2 escapeVel = Vector2.Zero;
|
||||||
|
if (character.CurrentHull != null)
|
||||||
|
{
|
||||||
|
foreach (Hull hull in HumanAIController.VisibleHulls)
|
||||||
{
|
{
|
||||||
//goto objective doesn't exist (a safe hull not found, or a path to a safe hull not found)
|
foreach (FireSource fireSource in hull.FireSources)
|
||||||
// -> attempt to manually steer away from hazards
|
|
||||||
Vector2 escapeVel = Vector2.Zero;
|
|
||||||
foreach (Hull hull in HumanAIController.VisibleHulls)
|
|
||||||
{
|
{
|
||||||
foreach (FireSource fireSource in hull.FireSources)
|
Vector2 dir = character.Position - fireSource.Position;
|
||||||
{
|
float distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(fireSource.Position, character.Position), 0.1f, 10.0f);
|
||||||
Vector2 dir = character.Position - fireSource.Position;
|
escapeVel += new Vector2(Math.Sign(dir.X) * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
|
||||||
float distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(fireSource.Position, character.Position), 0.1f, 10.0f);
|
|
||||||
escapeVel += new Vector2(Math.Sign(dir.X) * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (Character enemy in Character.CharacterList)
|
|
||||||
{
|
|
||||||
if (!HumanAIController.IsActive(enemy) || HumanAIController.IsFriendly(enemy) || enemy.IsArrested) { continue; }
|
|
||||||
if (HumanAIController.VisibleHulls.Contains(enemy.CurrentHull))
|
|
||||||
{
|
|
||||||
Vector2 dir = character.Position - enemy.Position;
|
|
||||||
float distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(enemy.Position, character.Position), 0.1f, 10.0f);
|
|
||||||
escapeVel += new Vector2(Math.Sign(dir.X) * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (escapeVel != Vector2.Zero)
|
|
||||||
{
|
|
||||||
float left = currentHull.Rect.X + 50;
|
|
||||||
float right = currentHull.Rect.Right - 50;
|
|
||||||
//only move if we haven't reached the edge of the room
|
|
||||||
if (escapeVel.X < 0 && character.Position.X > left || escapeVel.X > 0 && character.Position.X < right)
|
|
||||||
{
|
|
||||||
character.AIController.SteeringManager.SteeringManual(deltaTime, escapeVel);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
character.AnimController.TargetDir = escapeVel.X < 0.0f ? Direction.Right : Direction.Left;
|
|
||||||
character.AIController.SteeringManager.Reset();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach (Character enemy in Character.CharacterList)
|
||||||
|
{
|
||||||
|
if (!HumanAIController.IsActive(enemy) || HumanAIController.IsFriendly(enemy) || enemy.IsArrested) { continue; }
|
||||||
|
if (HumanAIController.VisibleHulls.Contains(enemy.CurrentHull))
|
||||||
|
{
|
||||||
|
Vector2 dir = character.Position - enemy.Position;
|
||||||
|
float distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(enemy.Position, character.Position), 0.1f, 10.0f);
|
||||||
|
escapeVel += new Vector2(Math.Sign(dir.X) * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (escapeVel != Vector2.Zero)
|
||||||
|
{
|
||||||
|
float left = character.CurrentHull.Rect.X + 50;
|
||||||
|
float right = character.CurrentHull.Rect.Right - 50;
|
||||||
|
//only move if we haven't reached the edge of the room
|
||||||
|
if (escapeVel.X < 0 && character.Position.X > left || escapeVel.X > 0 && character.Position.X < right)
|
||||||
|
{
|
||||||
|
character.AIController.SteeringManager.SteeringManual(deltaTime, escapeVel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
character.AnimController.TargetDir = escapeVel.X < 0.0f ? Direction.Right : Direction.Left;
|
||||||
|
character.AIController.SteeringManager.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
objectiveManager.GetObjective<AIObjectiveIdle>().Wander(deltaTime);
|
objectiveManager.GetObjective<AIObjectiveIdle>().Wander(deltaTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Hull FindBestHull(IEnumerable<Hull> ignoredHulls = null, bool allowChangingTheSubmarine = true)
|
public enum HullSearchStatus
|
||||||
{
|
{
|
||||||
//sort the hulls based on distance and which sub they're in
|
Running,
|
||||||
//tends to make the method much faster, because we find a potential hull earlier and can discard further-away hulls more easily
|
Finished
|
||||||
//(for instance, an NPC in an outpost might otherwise go through all the hulls in the main sub first and do tons of expensive
|
}
|
||||||
//path calculations, only to discard all of them when going through the hulls in the outpost)
|
|
||||||
float EstimateHullSuitability(Hull hull)
|
private readonly List<Hull> hulls = new List<Hull>();
|
||||||
|
private int hullSearchIndex = -1;
|
||||||
|
float bestHullValue = 0;
|
||||||
|
bool bestHullIsAirlock = false;
|
||||||
|
Hull potentialBestHull;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to find the best (safe, nearby) hull the character can find a path to.
|
||||||
|
/// Checks one hull at a time, and returns HullSearchStatus.Finished when all potential hulls have been checked.
|
||||||
|
/// </summary>
|
||||||
|
public HullSearchStatus FindBestHull(out Hull bestHull, IEnumerable<Hull> ignoredHulls = null, bool allowChangingSubmarine = true)
|
||||||
|
{
|
||||||
|
if (hullSearchIndex == -1)
|
||||||
|
{
|
||||||
|
bestHullValue = 0;
|
||||||
|
potentialBestHull = null;
|
||||||
|
bestHullIsAirlock = false;
|
||||||
|
hulls.Clear();
|
||||||
|
var connectedSubs = character.Submarine?.GetConnectedSubs();
|
||||||
|
foreach (Hull hull in Hull.HullList)
|
||||||
|
{
|
||||||
|
if (hull.Submarine == null) { continue; }
|
||||||
|
// Ruins are mazes filled with water. There's no safe hulls and we don't want to use the resources on it.
|
||||||
|
if (hull.Submarine.Info.IsRuin) { continue; }
|
||||||
|
if (!allowChangingSubmarine && hull.Submarine != character.Submarine) { continue; }
|
||||||
|
if (hull.Rect.Height < ConvertUnits.ToDisplayUnits(character.AnimController.ColliderHeightFromFloor) * 2) { continue; }
|
||||||
|
if (ignoredHulls != null && ignoredHulls.Contains(hull)) { continue; }
|
||||||
|
if (HumanAIController.UnreachableHulls.Contains(hull)) { continue; }
|
||||||
|
if (connectedSubs != null && !connectedSubs.Contains(hull.Submarine)) { continue; }
|
||||||
|
|
||||||
|
//sort the hulls based on distance and which sub they're in
|
||||||
|
//tends to make the method much faster, because we find a potential hull earlier and can discard further-away hulls more easily
|
||||||
|
//(for instance, an NPC in an outpost might otherwise go through all the hulls in the main sub first and do tons of expensive
|
||||||
|
//path calculations, only to discard all of them when going through the hulls in the outpost)
|
||||||
|
float hullSuitability = EstimateHullSuitability(character, hull);
|
||||||
|
if (!hulls.Any())
|
||||||
|
{
|
||||||
|
hulls.Add(hull);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < hulls.Count; i++)
|
||||||
|
{
|
||||||
|
if (hullSuitability > EstimateHullSuitability(character, hulls[i]))
|
||||||
|
{
|
||||||
|
hulls.Insert(i, hull);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hulls.None())
|
||||||
|
{
|
||||||
|
bestHull = null;
|
||||||
|
return HullSearchStatus.Finished;
|
||||||
|
}
|
||||||
|
hullSearchIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float EstimateHullSuitability(Character character, Hull hull)
|
||||||
{
|
{
|
||||||
float dist =
|
float dist =
|
||||||
Math.Abs(hull.WorldPosition.X - character.WorldPosition.X) +
|
Math.Abs(hull.WorldPosition.X - character.WorldPosition.X) +
|
||||||
@@ -314,86 +387,91 @@ namespace Barotrauma
|
|||||||
return suitability;
|
return suitability;
|
||||||
}
|
}
|
||||||
|
|
||||||
Hull bestHull = null;
|
Hull potentialHull = hulls[hullSearchIndex];
|
||||||
float bestValue = 0;
|
|
||||||
bool bestIsAirlock = false;
|
float hullSafety = 0;
|
||||||
foreach (Hull hull in Hull.HullList.OrderByDescending(h => EstimateHullSuitability(h)))
|
bool hullIsAirlock = false;
|
||||||
|
bool isCharacterInside = character.CurrentHull != null && character.Submarine != null;
|
||||||
|
if (isCharacterInside)
|
||||||
{
|
{
|
||||||
if (hull.Submarine == null) { continue; }
|
hullSafety = HumanAIController.GetHullSafety(potentialHull, potentialHull.GetConnectedHulls(true, 1), character);
|
||||||
// Ruins are mazes filled with water. There's no safe hulls and we don't want to use the resources on it.
|
float yDist = Math.Abs(character.WorldPosition.Y - potentialHull.WorldPosition.Y);
|
||||||
if (hull.Submarine.Info.IsRuin) { continue; }
|
yDist = yDist > 100 ? yDist * 3 : 0;
|
||||||
if (!allowChangingTheSubmarine && hull.Submarine != character.Submarine) { continue; }
|
float dist = Math.Abs(character.WorldPosition.X - potentialHull.WorldPosition.X) + yDist;
|
||||||
if (hull.Rect.Height < ConvertUnits.ToDisplayUnits(character.AnimController.ColliderHeightFromFloor) * 2) { continue; }
|
float distanceFactor = MathHelper.Lerp(1, 0.9f, MathUtils.InverseLerp(0, 10000, dist));
|
||||||
if (ignoredHulls != null && ignoredHulls.Contains(hull)) { continue; }
|
hullSafety *= distanceFactor;
|
||||||
if (HumanAIController.UnreachableHulls.Contains(hull)) { continue; }
|
//skip the hull if the safety is already less than the best hull
|
||||||
float hullSafety = 0;
|
//(no need to do the expensive pathfinding if we already know we're not going to choose this hull)
|
||||||
bool hullIsAirlock = false;
|
if (hullSafety > bestHullValue)
|
||||||
bool isCharacterInside = character.CurrentHull != null && character.Submarine != null;
|
|
||||||
if (isCharacterInside)
|
|
||||||
{
|
{
|
||||||
if (!character.Submarine.IsConnectedTo(hull.Submarine)) { continue; }
|
|
||||||
hullSafety = HumanAIController.GetHullSafety(hull, hull.GetConnectedHulls(true, 1), character);
|
|
||||||
float yDist = Math.Abs(character.WorldPosition.Y - hull.WorldPosition.Y);
|
|
||||||
yDist = yDist > 100 ? yDist * 3 : 0;
|
|
||||||
float dist = Math.Abs(character.WorldPosition.X - hull.WorldPosition.X) + yDist;
|
|
||||||
float distanceFactor = MathHelper.Lerp(1, 0.9f, MathUtils.InverseLerp(0, 10000, dist));
|
|
||||||
hullSafety *= distanceFactor;
|
|
||||||
//skip the hull if the safety is already less than the best hull
|
|
||||||
//(no need to do the expensive pathfinding if we already know we're not going to choose this hull)
|
|
||||||
if (hullSafety < bestValue) { continue; }
|
|
||||||
//avoid airlock modules if not allowed to change the sub
|
//avoid airlock modules if not allowed to change the sub
|
||||||
if (!allowChangingTheSubmarine && hull.OutpostModuleTags.Any(t => t == "airlock"))
|
if (allowChangingSubmarine || !potentialHull.OutpostModuleTags.Any(t => t == "airlock"))
|
||||||
{
|
{
|
||||||
continue;
|
// Don't allow to go outside if not already outside.
|
||||||
|
var path = PathSteering.PathFinder.FindPath(character.SimPosition, potentialHull.SimPosition, character.Submarine, nodeFilter: node => node.Waypoint.CurrentHull != null);
|
||||||
|
if (path.Unreachable)
|
||||||
|
{
|
||||||
|
hullSafety = 0;
|
||||||
|
HumanAIController.UnreachableHulls.Add(potentialHull);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Each unsafe node reduces the hull safety value.
|
||||||
|
// Ignore the current hull, because otherwise we couldn't find a path out.
|
||||||
|
int unsafeNodes = path.Nodes.Count(n => n.CurrentHull != character.CurrentHull && HumanAIController.UnsafeHulls.Contains(n.CurrentHull));
|
||||||
|
hullSafety /= 1 + unsafeNodes;
|
||||||
|
// If the target is not inside a friendly submarine, considerably reduce the hull safety.
|
||||||
|
if (!character.Submarine.IsEntityFoundOnThisSub(potentialHull, true))
|
||||||
|
{
|
||||||
|
hullSafety /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Don't allow to go outside if not already outside.
|
else
|
||||||
var path = PathSteering.PathFinder.FindPath(character.SimPosition, hull.SimPosition, character.Submarine, nodeFilter: node => node.Waypoint.CurrentHull != null);
|
|
||||||
if (path.Unreachable)
|
|
||||||
{
|
{
|
||||||
HumanAIController.UnreachableHulls.Add(hull);
|
hullSafety = 0;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
// Each unsafe node reduces the hull safety value.
|
|
||||||
// Ignore the current hull, because otherwise we couldn't find a path out.
|
|
||||||
int unsafeNodes = path.Nodes.Count(n => n.CurrentHull != character.CurrentHull && HumanAIController.UnsafeHulls.Contains(n.CurrentHull));
|
|
||||||
hullSafety /= 1 + unsafeNodes;
|
|
||||||
// If the target is not inside a friendly submarine, considerably reduce the hull safety.
|
|
||||||
if (!character.Submarine.IsEntityFoundOnThisSub(hull, true))
|
|
||||||
{
|
|
||||||
hullSafety /= 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: could also target gaps that get us inside?
|
|
||||||
if (hull.IsTaggedAirlock())
|
|
||||||
{
|
|
||||||
hullSafety = 100;
|
|
||||||
hullIsAirlock = true;
|
|
||||||
}
|
|
||||||
else if(!bestIsAirlock && hull.LeadsOutside(character))
|
|
||||||
{
|
|
||||||
hullSafety = 100;
|
|
||||||
}
|
|
||||||
// Huge preference for closer targets
|
|
||||||
float distance = Vector2.DistanceSquared(character.WorldPosition, hull.WorldPosition);
|
|
||||||
float distanceFactor = MathHelper.Lerp(1, 0.2f, MathUtils.InverseLerp(0, MathUtils.Pow(100000, 2), distance));
|
|
||||||
hullSafety *= distanceFactor;
|
|
||||||
// If the target is not inside a friendly submarine, considerably reduce the hull safety.
|
|
||||||
// Intentionally exclude wrecks from this check
|
|
||||||
if (hull.Submarine.TeamID != character.TeamID && hull.Submarine.TeamID != CharacterTeamType.FriendlyNPC)
|
|
||||||
{
|
|
||||||
hullSafety /= 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hullSafety > bestValue || (!isCharacterInside && hullIsAirlock && !bestIsAirlock))
|
|
||||||
{
|
|
||||||
bestHull = hull;
|
|
||||||
bestValue = hullSafety;
|
|
||||||
bestIsAirlock = hullIsAirlock;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bestHull;
|
else
|
||||||
|
{
|
||||||
|
// TODO: could also target gaps that get us inside?
|
||||||
|
if (potentialHull.IsTaggedAirlock())
|
||||||
|
{
|
||||||
|
hullSafety = 100;
|
||||||
|
hullIsAirlock = true;
|
||||||
|
}
|
||||||
|
else if(!bestHullIsAirlock && potentialHull.LeadsOutside(character))
|
||||||
|
{
|
||||||
|
hullSafety = 100;
|
||||||
|
}
|
||||||
|
// Huge preference for closer targets
|
||||||
|
float distance = Vector2.DistanceSquared(character.WorldPosition, potentialHull.WorldPosition);
|
||||||
|
float distanceFactor = MathHelper.Lerp(1, 0.2f, MathUtils.InverseLerp(0, MathUtils.Pow(100000, 2), distance));
|
||||||
|
hullSafety *= distanceFactor;
|
||||||
|
// If the target is not inside a friendly submarine, considerably reduce the hull safety.
|
||||||
|
// Intentionally exclude wrecks from this check
|
||||||
|
if (potentialHull.Submarine.TeamID != character.TeamID && potentialHull.Submarine.TeamID != CharacterTeamType.FriendlyNPC)
|
||||||
|
{
|
||||||
|
hullSafety /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hullSafety > bestHullValue || (!isCharacterInside && hullIsAirlock && !bestHullIsAirlock))
|
||||||
|
{
|
||||||
|
potentialBestHull = potentialHull;
|
||||||
|
bestHullValue = hullSafety;
|
||||||
|
bestHullIsAirlock = hullIsAirlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
bestHull = potentialBestHull;
|
||||||
|
hullSearchIndex++;
|
||||||
|
|
||||||
|
if (hullSearchIndex >= hulls.Count)
|
||||||
|
{
|
||||||
|
hullSearchIndex = -1;
|
||||||
|
return HullSearchStatus.Finished;
|
||||||
|
}
|
||||||
|
return HullSearchStatus.Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Reset()
|
public override void Reset()
|
||||||
|
|||||||
+1
@@ -165,6 +165,7 @@ namespace Barotrauma
|
|||||||
requiredCondition = () =>
|
requiredCondition = () =>
|
||||||
Leak.Submarine == character.Submarine &&
|
Leak.Submarine == character.Submarine &&
|
||||||
Leak.linkedTo.Any(e => e is Hull h && character.CurrentHull == h),
|
Leak.linkedTo.Any(e => e is Hull h && character.CurrentHull == h),
|
||||||
|
endNodeFilter = n => n.Waypoint.CurrentHull != null && Leak.linkedTo.Any(e => e is Hull h && h == n.Waypoint.CurrentHull),
|
||||||
// The Go To objective can be abandoned if the leak is fixed (in which case we don't want to use the dialogue)
|
// The Go To objective can be abandoned if the leak is fixed (in which case we don't want to use the dialogue)
|
||||||
SpeakCannotReachCondition = () => !CheckObjectiveSpecific()
|
SpeakCannotReachCondition = () => !CheckObjectiveSpecific()
|
||||||
},
|
},
|
||||||
|
|||||||
+29
-1
@@ -471,7 +471,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (spawnItemIfNotFound)
|
if (spawnItemIfNotFound)
|
||||||
{
|
{
|
||||||
if (!(MapEntityPrefab.List.FirstOrDefault(me => me is ItemPrefab ip && IdentifiersOrTags.Any(id => id == ip.Identifier || ip.Tags.Contains(id))) is ItemPrefab prefab))
|
ItemPrefab prefab = FindItemToSpawn();
|
||||||
|
if (prefab == null)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugConsole.NewMessage($"{character.Name}: Cannot find an item with the following identifier(s) or tag(s): {string.Join(", ", IdentifiersOrTags)}, tried to spawn the item but no matching item prefabs were found.", Color.Yellow);
|
DebugConsole.NewMessage($"{character.Name}: Cannot find an item with the following identifier(s) or tag(s): {string.Join(", ", IdentifiersOrTags)}, tried to spawn the item but no matching item prefabs were found.", Color.Yellow);
|
||||||
@@ -501,6 +502,33 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the "best" item to spawn when using <see cref="spawnItemIfNotFound"/> and there's multiple suitable items.
|
||||||
|
/// Best in this context is the one that's sold at the lowest price in stores (usually the most "basic" item)
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private ItemPrefab FindItemToSpawn()
|
||||||
|
{
|
||||||
|
ItemPrefab bestItem = null;
|
||||||
|
float lowestCost = float.MaxValue;
|
||||||
|
foreach (MapEntityPrefab prefab in MapEntityPrefab.List)
|
||||||
|
{
|
||||||
|
if (!(prefab is ItemPrefab itemPrefab)) { continue; }
|
||||||
|
if (IdentifiersOrTags.Any(id => id == prefab.Identifier || prefab.Tags.Contains(id)))
|
||||||
|
{
|
||||||
|
float cost = itemPrefab.DefaultPrice != null && itemPrefab.CanBeBought ?
|
||||||
|
itemPrefab.DefaultPrice.Price :
|
||||||
|
float.MaxValue;
|
||||||
|
if (cost < lowestCost || bestItem == null)
|
||||||
|
{
|
||||||
|
bestItem = itemPrefab;
|
||||||
|
lowestCost = cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestItem;
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool CheckObjectiveSpecific()
|
protected override bool CheckObjectiveSpecific()
|
||||||
{
|
{
|
||||||
if (IsCompleted) { return true; }
|
if (IsCompleted) { return true; }
|
||||||
|
|||||||
+4
-1
@@ -4,6 +4,7 @@ using Microsoft.Xna.Framework;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using static Barotrauma.AIObjectiveFindSafety;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -186,7 +187,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
safeHull = objectiveManager.GetObjective<AIObjectiveFindSafety>().FindBestHull(HumanAIController.VisibleHulls);
|
HullSearchStatus hullSearchStatus = objectiveManager.GetObjective<AIObjectiveFindSafety>().FindBestHull(out Hull potentialSafeHull, HumanAIController.VisibleHulls);
|
||||||
|
if (hullSearchStatus != HullSearchStatus.Finished) { return; }
|
||||||
|
safeHull = potentialSafeHull;
|
||||||
findHullTimer = findHullInterval * Rand.Range(0.9f, 1.1f);
|
findHullTimer = findHullInterval * Rand.Range(0.9f, 1.1f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace Barotrauma
|
|||||||
public bool IsAiming => wasAiming;
|
public bool IsAiming => wasAiming;
|
||||||
public bool IsAimingMelee => wasAimingMelee;
|
public bool IsAimingMelee => wasAimingMelee;
|
||||||
|
|
||||||
protected bool Aiming => aiming || aimingMelee;
|
protected bool Aiming => aiming || aimingMelee || LockFlippingUntil > Timing.TotalTime && character.IsKeyDown(InputType.Aim);
|
||||||
|
|
||||||
public float ArmLength => upperArmLength + forearmLength;
|
public float ArmLength => upperArmLength + forearmLength;
|
||||||
|
|
||||||
@@ -275,6 +275,8 @@ namespace Barotrauma
|
|||||||
// We need some margin, because if a hatch has closed, it's possible that the height from floor is slightly negative.
|
// We need some margin, because if a hatch has closed, it's possible that the height from floor is slightly negative.
|
||||||
public bool IsAboveFloor => GetHeightFromFloor() > -0.1f;
|
public bool IsAboveFloor => GetHeightFromFloor() > -0.1f;
|
||||||
|
|
||||||
|
public float LockFlippingUntil;
|
||||||
|
|
||||||
public void UpdateUseItem(bool allowMovement, Vector2 handWorldPos)
|
public void UpdateUseItem(bool allowMovement, Vector2 handWorldPos)
|
||||||
{
|
{
|
||||||
useItemTimer = 0.5f;
|
useItemTimer = 0.5f;
|
||||||
@@ -380,18 +382,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
//if holding two items that should control the characters' pose, let the item in the right hand do it
|
//if holding two items that should control the characters' pose, let the item in the right hand do it
|
||||||
bool anotherItemControlsPose = equippedInLefthand && rightHandItem != item && (rightHandItem?.GetComponent<Holdable>()?.ControlPose ?? false);
|
bool anotherItemControlsPose = equippedInLefthand && rightHandItem != item && (rightHandItem?.GetComponent<Holdable>()?.ControlPose ?? false);
|
||||||
if (!anotherItemControlsPose)
|
if (!anotherItemControlsPose && TargetMovement == Vector2.Zero && inWater)
|
||||||
{
|
{
|
||||||
var head = GetLimb(LimbType.Head);
|
torso.body.AngularVelocity -= torso.body.AngularVelocity * 0.1f;
|
||||||
if (head != null)
|
torso.body.ApplyForce(torso.body.LinearVelocity * -0.5f);
|
||||||
{
|
|
||||||
head.body.SmoothRotate(itemAngle, force: 30 * head.Mass);
|
|
||||||
}
|
|
||||||
if (TargetMovement == Vector2.Zero && inWater)
|
|
||||||
{
|
|
||||||
torso.body.AngularVelocity -= torso.body.AngularVelocity * 0.1f;
|
|
||||||
torso.body.ApplyForce(torso.body.LinearVelocity * -0.5f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
aiming = true;
|
aiming = true;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -164,8 +164,6 @@ namespace Barotrauma
|
|||||||
public float LegBendTorque => CurrentGroundedParams.LegBendTorque * RagdollParams.JointScale;
|
public float LegBendTorque => CurrentGroundedParams.LegBendTorque * RagdollParams.JointScale;
|
||||||
public Vector2 HandMoveOffset => CurrentGroundedParams.HandMoveOffset * RagdollParams.JointScale;
|
public Vector2 HandMoveOffset => CurrentGroundedParams.HandMoveOffset * RagdollParams.JointScale;
|
||||||
|
|
||||||
public float LockFlippingUntil;
|
|
||||||
|
|
||||||
public override Vector2 AimSourceSimPos
|
public override Vector2 AimSourceSimPos
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -841,7 +839,7 @@ namespace Barotrauma
|
|||||||
rotation += 360;
|
rotation += 360;
|
||||||
}
|
}
|
||||||
float targetSpeed = TargetMovement.Length();
|
float targetSpeed = TargetMovement.Length();
|
||||||
if (targetSpeed > 0.1f && !character.IsRemotelyControlled && !character.IsKeyDown(InputType.Aim))
|
if (targetSpeed > 0.1f && !character.IsRemotelyControlled && !Aiming)
|
||||||
{
|
{
|
||||||
if (Anim != Animation.UsingConstruction && !(character.SelectedConstruction?.GetComponent<Controller>()?.ControlCharacterPose ?? false))
|
if (Anim != Animation.UsingConstruction && !(character.SelectedConstruction?.GetComponent<Controller>()?.ControlCharacterPose ?? false))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -153,12 +153,12 @@ namespace Barotrauma
|
|||||||
protected ActiveTeamChange currentTeamChange;
|
protected ActiveTeamChange currentTeamChange;
|
||||||
const string OriginalTeamIdentifier = "original";
|
const string OriginalTeamIdentifier = "original";
|
||||||
|
|
||||||
public static void ThrowIfAccessingWalletsInSingleplayer()
|
private void ThrowIfAccessingWalletsInSingleplayer()
|
||||||
{
|
{
|
||||||
#if CLIENT && DEBUG
|
#if CLIENT && DEBUG
|
||||||
if (Screen.Selected is TestScreen) { return; }
|
if (Screen.Selected is TestScreen) { return; }
|
||||||
#endif
|
#endif
|
||||||
if (GameMain.NetworkMember is null || GameMain.IsSingleplayer)
|
if ((GameMain.NetworkMember is null || GameMain.IsSingleplayer) && IsPlayer)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Tried to access crew wallets in singleplayer. Use {nameof(CampaignMode)}.{nameof(CampaignMode.Bank)} or {nameof(CampaignMode)}.{nameof(CampaignMode.GetWallet)} instead.");
|
throw new InvalidOperationException($"Tried to access crew wallets in singleplayer. Use {nameof(CampaignMode)}.{nameof(CampaignMode.Bank)} or {nameof(CampaignMode)}.{nameof(CampaignMode.GetWallet)} instead.");
|
||||||
}
|
}
|
||||||
@@ -560,18 +560,35 @@ namespace Barotrauma
|
|||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
CharacterHealth.SetHealthBarVisibility(value == null);
|
CharacterHealth.SetHealthBarVisibility(value == null);
|
||||||
#elif SERVER
|
#endif
|
||||||
if (value is { IsDead: true, Wallet: { Balance: var balance } grabbedWallet } && balance > 0)
|
bool isServerOrSingleplayer = GameMain.IsSingleplayer || GameMain.NetworkMember is { IsServer: true };
|
||||||
|
if (IsPlayer && isServerOrSingleplayer && value is { IsDead: true, Wallet: { Balance: var balance } grabbedWallet } && balance > 0)
|
||||||
{
|
{
|
||||||
if (GameMain.GameSession.Campaign is MultiPlayerCampaign mpCampaign)
|
#if SERVER
|
||||||
|
if (GameMain.GameSession.Campaign is MultiPlayerCampaign mpCampaign && GameMain.Server is { ServerSettings: { } settings })
|
||||||
{
|
{
|
||||||
mpCampaign.Bank.Give(balance);
|
switch (settings.LootedMoneyDestination)
|
||||||
|
{
|
||||||
|
case LootedMoneyDestination.Wallet when IsPlayer:
|
||||||
|
Wallet.Give(balance);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mpCampaign.Bank.Give(balance);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
grabbedWallet.Deduct(balance);
|
|
||||||
GameServer.Log($"{GameServer.CharacterLogName(this)} grabbed {value.Name}'s body and received {grabbedWallet.Balance} mk.", ServerLog.MessageType.Money);
|
GameServer.Log($"{GameServer.CharacterLogName(this)} grabbed {value.Name}'s body and received {grabbedWallet.Balance} mk.", ServerLog.MessageType.Money);
|
||||||
}
|
#elif CLIENT
|
||||||
|
if (GameMain.GameSession.Campaign is SinglePlayerCampaign spCampaign)
|
||||||
|
{
|
||||||
|
spCampaign.Bank.Give(balance);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
grabbedWallet.Deduct(balance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1443,7 +1460,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
foreach (Item item in Inventory.AllItems)
|
foreach (Item item in Inventory.AllItems)
|
||||||
{
|
{
|
||||||
if (item?.Prefab.Identifier != "idcard") { continue; }
|
if (item?.GetComponent<IdCard>() == null) { continue; }
|
||||||
foreach (string s in spawnPoint.IdCardTags)
|
foreach (string s in spawnPoint.IdCardTags)
|
||||||
{
|
{
|
||||||
item.AddTag(s);
|
item.AddTag(s);
|
||||||
@@ -3954,7 +3971,10 @@ namespace Barotrauma
|
|||||||
if (actionType != ActionType.OnDamaged && actionType != ActionType.OnSevered)
|
if (actionType != ActionType.OnDamaged && actionType != ActionType.OnSevered)
|
||||||
{
|
{
|
||||||
// OnDamaged is called only for the limb that is hit.
|
// OnDamaged is called only for the limb that is hit.
|
||||||
AnimController.Limbs.ForEach(l => l.ApplyStatusEffects(actionType, deltaTime));
|
foreach (Limb limb in AnimController.Limbs)
|
||||||
|
{
|
||||||
|
limb.ApplyStatusEffects(actionType, deltaTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//OnActive effects are handled by the afflictions themselves
|
//OnActive effects are handled by the afflictions themselves
|
||||||
if (actionType != ActionType.OnActive)
|
if (actionType != ActionType.OnActive)
|
||||||
|
|||||||
@@ -252,12 +252,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Endocrine boosters can unlock talents outside the user's talent tree. This method is used to specifically get them
|
/// Returns unlocked talents that aren't part of the character's talent tree (which can be unlocked e.g. with an endocrine booster)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<Identifier> GetEndocrineTalents()
|
public IEnumerable<Identifier> GetUnlockedTalentsOutsideTree()
|
||||||
{
|
{
|
||||||
if (!TalentTree.JobTalentTrees.TryGet(Job.Prefab.Identifier, out TalentTree talentTree)) { return Enumerable.Empty<Identifier>(); }
|
if (!TalentTree.JobTalentTrees.TryGet(Job.Prefab.Identifier, out TalentTree talentTree)) { return Enumerable.Empty<Identifier>(); }
|
||||||
|
|
||||||
return UnlockedTalents.Where(t => !talentTree.TalentIsInTree(t));
|
return UnlockedTalents.Where(t => !talentTree.TalentIsInTree(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1182,7 +1181,7 @@ namespace Barotrauma
|
|||||||
// Replace the name tag of any existing id cards or duffel bags
|
// Replace the name tag of any existing id cards or duffel bags
|
||||||
foreach (var item in Item.ItemList)
|
foreach (var item in Item.ItemList)
|
||||||
{
|
{
|
||||||
if (item.Prefab.Identifier != "idcard" && !item.Tags.Contains("despawncontainer")) { continue; }
|
if (!item.HasTag("identitycard") && !item.HasTag("despawncontainer")) { continue; }
|
||||||
foreach (var tag in item.Tags.Split(','))
|
foreach (var tag in item.Tags.Split(','))
|
||||||
{
|
{
|
||||||
var splitTag = tag.Split(":");
|
var splitTag = tag.Split(":");
|
||||||
|
|||||||
+1
@@ -300,6 +300,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static AfflictionPrefab InternalDamage => Prefabs["internaldamage"];
|
public static AfflictionPrefab InternalDamage => Prefabs["internaldamage"];
|
||||||
|
public static AfflictionPrefab BiteWounds => Prefabs["bitewounds"];
|
||||||
public static AfflictionPrefab ImpactDamage => Prefabs["blunttrauma"];
|
public static AfflictionPrefab ImpactDamage => Prefabs["blunttrauma"];
|
||||||
public static AfflictionPrefab Bleeding => Prefabs["bleeding"];
|
public static AfflictionPrefab Bleeding => Prefabs["bleeding"];
|
||||||
public static AfflictionPrefab Burn => Prefabs["burn"];
|
public static AfflictionPrefab Burn => Prefabs["burn"];
|
||||||
|
|||||||
@@ -124,7 +124,18 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public float PressureKillDelay { get; private set; } = 5.0f;
|
public float PressureKillDelay { get; private set; } = 5.0f;
|
||||||
|
|
||||||
public float Vitality { get; private set; }
|
private float vitality;
|
||||||
|
public float Vitality
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Character.IsDead ? minVitality : vitality;
|
||||||
|
}
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
vitality = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public float HealthPercentage => MathUtils.Percentage(Vitality, MaxVitality);
|
public float HealthPercentage => MathUtils.Percentage(Vitality, MaxVitality);
|
||||||
|
|
||||||
@@ -725,6 +736,8 @@ namespace Barotrauma
|
|||||||
AddLimbAffliction(limbHealth: null, newAffliction, allowStacking);
|
AddLimbAffliction(limbHealth: null, newAffliction, allowStacking);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void UpdateSkinTint();
|
||||||
|
|
||||||
partial void UpdateLimbAfflictionOverlays();
|
partial void UpdateLimbAfflictionOverlays();
|
||||||
|
|
||||||
public void Update(float deltaTime)
|
public void Update(float deltaTime)
|
||||||
@@ -798,23 +811,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateSkinTint()
|
|
||||||
{
|
|
||||||
FaceTint = DefaultFaceTint;
|
|
||||||
BodyTint = Color.TransparentBlack;
|
|
||||||
|
|
||||||
if (!(Character?.Params?.Health.ApplyAfflictionColors ?? false)) { return; }
|
|
||||||
|
|
||||||
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
|
||||||
{
|
|
||||||
var affliction = kvp.Key;
|
|
||||||
Color faceTint = affliction.GetFaceTint();
|
|
||||||
if (faceTint.A > FaceTint.A) { FaceTint = faceTint; }
|
|
||||||
Color bodyTint = affliction.GetBodyTint();
|
|
||||||
if (bodyTint.A > BodyTint.A) { BodyTint = bodyTint; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateDamageReductions(float deltaTime)
|
private void UpdateDamageReductions(float deltaTime)
|
||||||
{
|
{
|
||||||
float healthRegen = Character.Params.Health.ConstantHealthRegeneration;
|
float healthRegen = Character.Params.Health.ConstantHealthRegeneration;
|
||||||
@@ -905,6 +901,7 @@ namespace Barotrauma
|
|||||||
if (Unkillable || Character.GodMode) { return; }
|
if (Unkillable || Character.GodMode) { return; }
|
||||||
|
|
||||||
var (type, affliction) = GetCauseOfDeath();
|
var (type, affliction) = GetCauseOfDeath();
|
||||||
|
UpdateLimbAfflictionOverlays();
|
||||||
UpdateSkinTint();
|
UpdateSkinTint();
|
||||||
Character.Kill(type, affliction);
|
Character.Kill(type, affliction);
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
|
|||||||
@@ -105,9 +105,9 @@ namespace Barotrauma
|
|||||||
return spawnPointTags;
|
return spawnPointTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JobPrefab GetJobPrefab(Rand.RandSync randSync = Rand.RandSync.Unsynced)
|
public JobPrefab GetJobPrefab(Rand.RandSync randSync = Rand.RandSync.Unsynced, Func<JobPrefab, bool> predicate = null)
|
||||||
{
|
{
|
||||||
return Job != null && Job != "any" ? JobPrefab.Get(Job) : JobPrefab.Random(randSync);
|
return Job != null && Job != "any" ? JobPrefab.Get(Job) : JobPrefab.Random(randSync, predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitializeCharacter(Character npc, ISpatialEntity positionToStayIn = null)
|
public void InitializeCharacter(Character npc, ISpatialEntity positionToStayIn = null)
|
||||||
|
|||||||
@@ -209,11 +209,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.Prefab.Identifier == "idcard")
|
IdCard idCardComponent = item.GetComponent<IdCard>();
|
||||||
{
|
idCardComponent?.Initialize(spawnPoint, character);
|
||||||
IdCard idCardComponent = item.GetComponent<IdCard>();
|
|
||||||
idCardComponent?.Initialize(spawnPoint, character);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
|
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -293,6 +293,6 @@ namespace Barotrauma
|
|||||||
//ClothingElement = element.GetChildElement("PortraitClothing");
|
//ClothingElement = element.GetChildElement("PortraitClothing");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JobPrefab Random(Rand.RandSync sync) => Prefabs.GetRandom(p => !p.HiddenJob, sync);
|
public static JobPrefab Random(Rand.RandSync sync, Func<JobPrefab, bool> predicate = null) => Prefabs.GetRandom(p => !p.HiddenJob && (predicate == null || predicate(p)), sync);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ namespace Barotrauma
|
|||||||
#if CLIENT
|
#if CLIENT
|
||||||
if (isSevered)
|
if (isSevered)
|
||||||
{
|
{
|
||||||
damageOverlayStrength = 100.0f;
|
damageOverlayStrength = 1.0f;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -597,18 +597,7 @@ namespace Barotrauma
|
|||||||
dir = Direction.Right;
|
dir = Direction.Right;
|
||||||
body = new PhysicsBody(limbParams);
|
body = new PhysicsBody(limbParams);
|
||||||
type = limbParams.Type;
|
type = limbParams.Type;
|
||||||
if (limbParams.IgnoreCollisions)
|
IgnoreCollisions = limbParams.IgnoreCollisions;
|
||||||
{
|
|
||||||
body.CollisionCategories = Category.None;
|
|
||||||
body.CollidesWith = Category.None;
|
|
||||||
IgnoreCollisions = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//limbs don't collide with each other
|
|
||||||
body.CollisionCategories = Physics.CollisionCharacter;
|
|
||||||
body.CollidesWith = Physics.CollisionAll & ~Physics.CollisionCharacter & ~Physics.CollisionItem & ~Physics.CollisionItemBlocking;
|
|
||||||
}
|
|
||||||
body.UserData = this;
|
body.UserData = this;
|
||||||
pullJoint = new FixedMouseJoint(body.FarseerBody, ConvertUnits.ToSimUnits(limbParams.PullPos * Scale))
|
pullJoint = new FixedMouseJoint(body.FarseerBody, ConvertUnits.ToSimUnits(limbParams.PullPos * Scale))
|
||||||
{
|
{
|
||||||
@@ -646,10 +635,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
attack.DamageRange = ConvertUnits.ToDisplayUnits(attack.DamageRange);
|
attack.DamageRange = ConvertUnits.ToDisplayUnits(attack.DamageRange);
|
||||||
}
|
}
|
||||||
if (!character.VariantOf.IsEmpty)
|
if (character is { VariantOf: { IsEmpty: false } })
|
||||||
{
|
{
|
||||||
var attackElement = CharacterPrefab.Prefabs.TryGet(character.VariantOf, out var basePrefab)
|
var attackElement = character.Params.VariantFile.Root.GetChildElement("attack");
|
||||||
? basePrefab.ConfigElement.GetChildElement("attack") : null;
|
|
||||||
if (attackElement != null)
|
if (attackElement != null)
|
||||||
{
|
{
|
||||||
attack.DamageMultiplier = attackElement.GetAttributeFloat("damagemultiplier", 1f);
|
attack.DamageMultiplier = attackElement.GetAttributeFloat("damagemultiplier", 1f);
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected override bool MatchesSingular(Identifier identifier) => identifier == "ballastflorabehavior";
|
protected override bool MatchesSingular(Identifier identifier) => identifier == "ballastflorabehavior";
|
||||||
protected override bool MatchesPlural(Identifier identifier) => identifier == "ballastflorabehaviors";
|
protected override bool MatchesPlural(Identifier identifier) => identifier == "ballastflorabehaviors";
|
||||||
protected override PrefabCollection<BallastFloraPrefab> prefabs => BallastFloraPrefab.Prefabs;
|
protected override PrefabCollection<BallastFloraPrefab> Prefabs => BallastFloraPrefab.Prefabs;
|
||||||
|
|
||||||
protected override BallastFloraPrefab CreatePrefab(ContentXElement element)
|
protected override BallastFloraPrefab CreatePrefab(ContentXElement element)
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected override bool MatchesSingular(Identifier identifier) => identifier == "cave";
|
protected override bool MatchesSingular(Identifier identifier) => identifier == "cave";
|
||||||
protected override bool MatchesPlural(Identifier identifier) => identifier == "cavegenerationparameters";
|
protected override bool MatchesPlural(Identifier identifier) => identifier == "cavegenerationparameters";
|
||||||
protected override PrefabCollection<CaveGenerationParams> prefabs => CaveGenerationParams.CaveParams;
|
protected override PrefabCollection<CaveGenerationParams> Prefabs => CaveGenerationParams.CaveParams;
|
||||||
protected override CaveGenerationParams CreatePrefab(ContentXElement element)
|
protected override CaveGenerationParams CreatePrefab(ContentXElement element)
|
||||||
{
|
{
|
||||||
return new CaveGenerationParams(element, this);
|
return new CaveGenerationParams(element, this);
|
||||||
|
|||||||
+1
-1
@@ -77,7 +77,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
HashSet<string> texturePaths = new HashSet<string>
|
HashSet<string> texturePaths = new HashSet<string>
|
||||||
{
|
{
|
||||||
ragdollParams.Texture
|
ContentPath.FromRaw(CharacterPrefab.Prefabs[speciesName].ContentPackage, ragdollParams.Texture).Value
|
||||||
};
|
};
|
||||||
foreach (RagdollParams.LimbParams limb in ragdollParams.Limbs)
|
foreach (RagdollParams.LimbParams limb in ragdollParams.Limbs)
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected override bool MatchesSingular(Identifier identifier) => identifier == "corpse";
|
protected override bool MatchesSingular(Identifier identifier) => identifier == "corpse";
|
||||||
protected override bool MatchesPlural(Identifier identifier) => identifier == "corpses";
|
protected override bool MatchesPlural(Identifier identifier) => identifier == "corpses";
|
||||||
protected override PrefabCollection<CorpsePrefab> prefabs => CorpsePrefab.Prefabs;
|
protected override PrefabCollection<CorpsePrefab> Prefabs => CorpsePrefab.Prefabs;
|
||||||
protected override CorpsePrefab CreatePrefab(ContentXElement element)
|
protected override CorpsePrefab CreatePrefab(ContentXElement element)
|
||||||
{
|
{
|
||||||
return new CorpsePrefab(element, this);
|
return new CorpsePrefab(element, this);
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected override bool MatchesSingular(Identifier identifier) => !MatchesPlural(identifier);
|
protected override bool MatchesSingular(Identifier identifier) => !MatchesPlural(identifier);
|
||||||
protected override bool MatchesPlural(Identifier identifier) => identifier == "EventManagerSettings";
|
protected override bool MatchesPlural(Identifier identifier) => identifier == "EventManagerSettings";
|
||||||
protected override PrefabCollection<EventManagerSettings> prefabs => EventManagerSettings.Prefabs;
|
protected override PrefabCollection<EventManagerSettings> Prefabs => EventManagerSettings.Prefabs;
|
||||||
protected override EventManagerSettings CreatePrefab(ContentXElement element)
|
protected override EventManagerSettings CreatePrefab(ContentXElement element)
|
||||||
{
|
{
|
||||||
return new EventManagerSettings(element, this);
|
return new EventManagerSettings(element, this);
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected override bool MatchesSingular(Identifier identifier) => identifier == "faction";
|
protected override bool MatchesSingular(Identifier identifier) => identifier == "faction";
|
||||||
protected override bool MatchesPlural(Identifier identifier) => identifier == "factions";
|
protected override bool MatchesPlural(Identifier identifier) => identifier == "factions";
|
||||||
protected override PrefabCollection<FactionPrefab> prefabs => FactionPrefab.Prefabs;
|
protected override PrefabCollection<FactionPrefab> Prefabs => FactionPrefab.Prefabs;
|
||||||
protected override FactionPrefab CreatePrefab(ContentXElement element)
|
protected override FactionPrefab CreatePrefab(ContentXElement element)
|
||||||
{
|
{
|
||||||
return new FactionPrefab(element, this);
|
return new FactionPrefab(element, this);
|
||||||
|
|||||||
+6
-6
@@ -9,7 +9,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected abstract bool MatchesSingular(Identifier identifier);
|
protected abstract bool MatchesSingular(Identifier identifier);
|
||||||
protected abstract bool MatchesPlural(Identifier identifier);
|
protected abstract bool MatchesPlural(Identifier identifier);
|
||||||
protected abstract PrefabCollection<T> prefabs { get; }
|
protected abstract PrefabCollection<T> Prefabs { get; }
|
||||||
protected abstract T CreatePrefab(ContentXElement element);
|
protected abstract T CreatePrefab(ContentXElement element);
|
||||||
|
|
||||||
private void LoadFromXElement(ContentXElement parentElement, bool overriding)
|
private void LoadFromXElement(ContentXElement parentElement, bool overriding)
|
||||||
@@ -29,14 +29,14 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (elemName == "clear")
|
else if (elemName == "clear")
|
||||||
{
|
{
|
||||||
prefabs.AddOverrideFile(this);
|
Prefabs.AddOverrideFile(this);
|
||||||
}
|
}
|
||||||
else if (MatchesSingular(elemName))
|
else if (MatchesSingular(elemName))
|
||||||
{
|
{
|
||||||
T prefab = CreatePrefab(parentElement);
|
T prefab = CreatePrefab(parentElement);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
prefabs.Add(prefab, overriding);
|
Prefabs.Add(prefab, overriding);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -53,7 +53,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Invalid {GetType().Name} element: {parentElement.Name} in {Path}");
|
DebugConsole.ThrowError($"GenericPrefabFile: Invalid {GetType().Name} element: {parentElement.Name} in {Path}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,12 +68,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public override sealed void UnloadFile()
|
public override sealed void UnloadFile()
|
||||||
{
|
{
|
||||||
prefabs.RemoveByFile(this);
|
Prefabs.RemoveByFile(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed override void Sort()
|
public sealed override void Sort()
|
||||||
{
|
{
|
||||||
prefabs.SortAll();
|
Prefabs.SortAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user