Unstable 0.1500.0.0
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Sounds;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Particles;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Xml.Linq;
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace Barotrauma
|
||||
public static bool DebugDrawInteract;
|
||||
|
||||
protected float soundTimer;
|
||||
protected float soundInterval;
|
||||
protected float hudInfoTimer = 1.0f;
|
||||
protected bool hudInfoVisible = false;
|
||||
|
||||
@@ -130,7 +129,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public static bool IsMouseOnUI => GUI.MouseOn != null ||
|
||||
(CharacterInventory.IsMouseOnInventory() && !CharacterInventory.DraggingItemToWorld);
|
||||
(CharacterInventory.IsMouseOnInventory && !CharacterInventory.DraggingItemToWorld);
|
||||
|
||||
public class ObjectiveEntity
|
||||
{
|
||||
@@ -161,8 +160,7 @@ namespace Barotrauma
|
||||
|
||||
partial void InitProjSpecific(XElement mainElement)
|
||||
{
|
||||
soundInterval = mainElement.GetAttributeFloat("soundinterval", 10.0f);
|
||||
soundTimer = Rand.Range(0.0f, soundInterval);
|
||||
soundTimer = Rand.Range(0.0f, Params.SoundInterval);
|
||||
|
||||
sounds = new List<CharacterSound>();
|
||||
Params.Sounds.ForEach(s => sounds.Add(new CharacterSound(s)));
|
||||
@@ -390,12 +388,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (attackResult.Damage <= 1.0f) { return; }
|
||||
}
|
||||
|
||||
if (soundTimer < soundInterval * 0.5f)
|
||||
{
|
||||
PlaySound(CharacterSound.SoundType.Damage);
|
||||
soundTimer = soundInterval;
|
||||
}
|
||||
PlaySound(CharacterSound.SoundType.Damage, maxInterval: 2);
|
||||
}
|
||||
|
||||
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool log)
|
||||
@@ -470,9 +463,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
|
||||
private List<Item> debugInteractablesInRange = new List<Item>();
|
||||
private List<Item> debugInteractablesAtCursor = new List<Item>();
|
||||
private List<Pair<Item, float>> debugInteractablesNearCursor = new List<Pair<Item, float>>();
|
||||
private readonly List<Item> debugInteractablesInRange = new List<Item>();
|
||||
private readonly List<Item> debugInteractablesAtCursor = new List<Item>();
|
||||
private readonly List<(Item item, float dist)> debugInteractablesNearCursor = new List<(Item item, float dist)>();
|
||||
|
||||
/// <summary>
|
||||
/// Finds the front (lowest depth) interactable item at a position. "Interactable" in this case means that the character can "reach" the item.
|
||||
@@ -568,7 +561,7 @@ namespace Barotrauma
|
||||
if (distanceToItem > closestItemDistance) { continue; }
|
||||
if (!CanInteractWith(item)) { continue; }
|
||||
|
||||
debugInteractablesNearCursor.Add(new Pair<Item, float>(item, 1.0f - distanceToItem / (100.0f * aimAssistModifier)));
|
||||
debugInteractablesNearCursor.Add((item, 1.0f - distanceToItem / (100.0f * aimAssistModifier)));
|
||||
closestItem = item;
|
||||
closestItemDistance = distanceToItem;
|
||||
}
|
||||
@@ -579,31 +572,20 @@ namespace Barotrauma
|
||||
private Character FindCharacterAtPosition(Vector2 mouseSimPos, float maxDist = 150.0f)
|
||||
{
|
||||
Character closestCharacter = null;
|
||||
float closestDist = 0.0f;
|
||||
|
||||
maxDist = ConvertUnits.ToSimUnits(maxDist);
|
||||
|
||||
float closestDist = maxDist * maxDist;
|
||||
foreach (Character c in CharacterList)
|
||||
{
|
||||
if (!CanInteractWith(c, checkVisibility: false) || (c.AnimController?.SimplePhysicsEnabled ?? true)) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(mouseSimPos, c.SimPosition);
|
||||
if (dist < maxDist * maxDist && (closestCharacter == null || dist < closestDist))
|
||||
if (dist < closestDist ||
|
||||
(c.CampaignInteractionType != CampaignMode.InteractionType.None && closestCharacter?.CampaignInteractionType == CampaignMode.InteractionType.None && dist * 0.9f < closestDist))
|
||||
{
|
||||
closestCharacter = c;
|
||||
closestDist = dist;
|
||||
}
|
||||
|
||||
/*FarseerPhysics.Common.Transform transform;
|
||||
c.AnimController.Collider.FarseerBody.GetTransform(out transform);
|
||||
for (int i = 0; i < c.AnimController.Collider.FarseerBody.FixtureList.Count; i++)
|
||||
{
|
||||
if (c.AnimController.Collider.FarseerBody.FixtureList[i].Shape.TestPoint(ref transform, ref mouseSimPos))
|
||||
{
|
||||
Console.WriteLine("Hit: " + i);
|
||||
closestCharacter = c;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
return closestCharacter;
|
||||
@@ -638,7 +620,7 @@ namespace Barotrauma
|
||||
|
||||
if (!enabled) { return; }
|
||||
|
||||
if (!IsDead && !IsIncapacitated)
|
||||
if (!IsIncapacitated)
|
||||
{
|
||||
if (soundTimer > 0)
|
||||
{
|
||||
@@ -649,7 +631,14 @@ namespace Barotrauma
|
||||
switch (enemyAI.State)
|
||||
{
|
||||
case AIState.Attack:
|
||||
PlaySound(CharacterSound.SoundType.Attack);
|
||||
if (Rand.Value() > 0.5f)
|
||||
{
|
||||
PlaySound(CharacterSound.SoundType.Attack);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaySound(CharacterSound.SoundType.Idle);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
var petBehavior = enemyAI.PetBehavior;
|
||||
@@ -660,7 +649,6 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
PlaySound(CharacterSound.SoundType.Idle);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -827,12 +815,12 @@ namespace Barotrauma
|
||||
GUI.DrawLine(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y),
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), Color.White * 0.1f, width: 4);
|
||||
}
|
||||
foreach (Pair<Item, float> item in debugInteractablesNearCursor)
|
||||
foreach ((Item item, float dist) in debugInteractablesNearCursor)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
cursorPos,
|
||||
new Vector2(item.First.DrawPosition.X, -item.First.DrawPosition.Y),
|
||||
ToolBox.GradientLerp(item.Second, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green), width: 2);
|
||||
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y),
|
||||
ToolBox.GradientLerp(dist, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green), width: 2);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -856,6 +844,7 @@ namespace Barotrauma
|
||||
|
||||
Vector2 nameSize = GUI.Font.MeasureString(name);
|
||||
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - nameSize * 0.5f / cam.Zoom;
|
||||
Color nameColor = GetNameColor();
|
||||
|
||||
Vector2 screenSize = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
Vector2 viewportSize = new Vector2(cam.WorldView.Width, cam.WorldView.Height);
|
||||
@@ -865,18 +854,6 @@ namespace Barotrauma
|
||||
namePos *= viewportSize / screenSize;
|
||||
namePos.X += cam.WorldView.X; namePos.Y -= cam.WorldView.Y;
|
||||
|
||||
Color nameColor = Color.White;
|
||||
if (Controlled != null && TeamID != Controlled.TeamID)
|
||||
{
|
||||
if (TeamID == CharacterTeamType.FriendlyNPC)
|
||||
{
|
||||
nameColor = UniqueNameColor ?? Color.SkyBlue;
|
||||
}
|
||||
else
|
||||
{
|
||||
nameColor = GUI.Style.Red;
|
||||
}
|
||||
}
|
||||
if (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
|
||||
{
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionBubble." + CampaignInteractionType);
|
||||
@@ -931,6 +908,40 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public Color GetNameColor()
|
||||
{
|
||||
CharacterTeamType team = teamID;
|
||||
if (Info?.IsDisguisedAsAnother != null)
|
||||
{
|
||||
var idCard = Inventory.GetItemInLimbSlot(InvSlotType.Card)?.GetComponent<IdCard>();
|
||||
if (idCard != null)
|
||||
{
|
||||
if (team == CharacterTeamType.Team2 && idCard.TeamID != CharacterTeamType.Team2)
|
||||
{
|
||||
team = CharacterTeamType.Team1;
|
||||
}
|
||||
else if (team == CharacterTeamType.Team1 && idCard.TeamID == CharacterTeamType.Team2)
|
||||
{
|
||||
team = CharacterTeamType.Team2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Color nameColor = GUI.Style.TextColor;
|
||||
if (Controlled != null && team != Controlled.TeamID)
|
||||
{
|
||||
if (TeamID == CharacterTeamType.FriendlyNPC)
|
||||
{
|
||||
nameColor = UniqueNameColor ?? Color.SkyBlue;
|
||||
}
|
||||
else
|
||||
{
|
||||
nameColor = GUI.Style.Red;
|
||||
}
|
||||
}
|
||||
return nameColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a progress bar that's "linked" to the specified object (or updates an existing one if there's one already linked to the object)
|
||||
/// The progress bar will automatically fade out after 1 sec if the method hasn't been called during that time
|
||||
@@ -958,12 +969,13 @@ namespace Barotrauma
|
||||
|
||||
private readonly List<CharacterSound> matchingSounds = new List<CharacterSound>();
|
||||
private SoundChannel soundChannel;
|
||||
public void PlaySound(CharacterSound.SoundType soundType, float soundIntervalFactor = 1.0f)
|
||||
public void PlaySound(CharacterSound.SoundType soundType, float soundIntervalFactor = 1.0f, float maxInterval = 0)
|
||||
{
|
||||
if (sounds == null || sounds.Count == 0) { return; }
|
||||
if (soundChannel != null && soundChannel.IsPlaying) { return; }
|
||||
if (GameMain.SoundManager?.Disabled ?? true) { return; }
|
||||
if (soundTimer > soundInterval * soundIntervalFactor) { return; }
|
||||
if (soundTimer > Params.SoundInterval * soundIntervalFactor) { return; }
|
||||
if (Params.SoundInterval - soundTimer < maxInterval) { return; }
|
||||
matchingSounds.Clear();
|
||||
foreach (var s in sounds)
|
||||
{
|
||||
@@ -975,7 +987,7 @@ namespace Barotrauma
|
||||
var selectedSound = matchingSounds.GetRandom();
|
||||
if (selectedSound?.Sound == null) { return; }
|
||||
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, AnimController.WorldPosition, selectedSound.Volume, selectedSound.Range, hullGuess: CurrentHull, ignoreMuffling: selectedSound.IgnoreMuffling);
|
||||
soundTimer = soundInterval;
|
||||
soundTimer = Params.SoundInterval;
|
||||
}
|
||||
|
||||
public void AddActiveObjectiveEntity(Entity entity, Sprite sprite, Color? color = null)
|
||||
@@ -1028,5 +1040,20 @@ namespace Barotrauma
|
||||
Rand.Range(50.0f, 500.0f), null);
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnMoneyChanged(int prevAmount, int newAmount)
|
||||
{
|
||||
if (newAmount > prevAmount)
|
||||
{
|
||||
int increase = newAmount - prevAmount;
|
||||
GUI.AddMessage(
|
||||
"+" + TextManager.GetWithVariable("currencyformat", "[credits]", increase.ToString()),
|
||||
GUI.Style.Yellow,
|
||||
Position + Vector2.UnitY * 150.0f,
|
||||
Vector2.UnitY * 10.0f,
|
||||
playSound: true,
|
||||
subId: Submarine?.ID ?? -1);;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,7 +391,26 @@ namespace Barotrauma
|
||||
if (npc.CampaignInteractionType == CampaignMode.InteractionType.None || npc.Submarine != character.Submarine || npc.IsDead || npc.IsIncapacitated) { continue; }
|
||||
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionIcon." + npc.CampaignInteractionType);
|
||||
GUI.DrawIndicator(spriteBatch, npc.WorldPosition, cam, npc.CurrentHull == character.CurrentHull ? 500.0f : 100.0f, iconStyle.GetDefaultSprite(), iconStyle.Color);
|
||||
Range<float> visibleRange = new Range<float>(npc.CurrentHull == Character.Controlled.CurrentHull ? 500.0f : 100.0f, float.PositiveInfinity);
|
||||
if (npc.CampaignInteractionType == CampaignMode.InteractionType.Examine)
|
||||
{
|
||||
//TODO: we could probably do better than just hardcoding
|
||||
//a check for InteractionType.Examine here.
|
||||
|
||||
if (Vector2.DistanceSquared(character.Position, npc.Position) > 500f * 500f) { continue; }
|
||||
|
||||
var body = Submarine.CheckVisibility(character.SimPosition, npc.SimPosition, ignoreLevel: true);
|
||||
if (body != null && body.UserData as Character != npc) { continue; }
|
||||
|
||||
visibleRange = new Range<float>(-100f, 500f);
|
||||
}
|
||||
GUI.DrawIndicator(
|
||||
spriteBatch,
|
||||
npc.WorldPosition,
|
||||
cam,
|
||||
visibleRange,
|
||||
iconStyle.GetDefaultSprite(),
|
||||
iconStyle.Color);
|
||||
}
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
@@ -400,7 +419,7 @@ namespace Barotrauma
|
||||
if (Vector2.DistanceSquared(character.Position, item.Position) > 500f*500f) { continue; }
|
||||
var body = Submarine.CheckVisibility(character.SimPosition, item.SimPosition, ignoreLevel: true);
|
||||
if (body != null && body.UserData as Item != item) { continue; }
|
||||
GUI.DrawIndicator(spriteBatch, item.WorldPosition + new Vector2(0f, item.RectHeight * 0.65f), cam, new Vector2(-100f, 500.0f), item.IconStyle.GetDefaultSprite(), item.IconStyle.Color, createOffset: false);
|
||||
GUI.DrawIndicator(spriteBatch, item.WorldPosition + new Vector2(0f, item.RectHeight * 0.65f), cam, new Range<float>(-100f, 500.0f), item.IconStyle.GetDefaultSprite(), item.IconStyle.Color, createOffset: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,12 +544,7 @@ namespace Barotrauma
|
||||
|
||||
textPos -= new Vector2(textSize.X / 2, textSize.Y);
|
||||
|
||||
Color nameColor = GUI.Style.TextColor;
|
||||
if (character.TeamID != character.FocusedCharacter.TeamID)
|
||||
{
|
||||
nameColor = character.FocusedCharacter.TeamID == CharacterTeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
|
||||
}
|
||||
|
||||
Color nameColor = character.FocusedCharacter.GetNameColor();
|
||||
GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2, GUI.SubHeadingFont);
|
||||
textPos.X += 10.0f * GUI.Scale;
|
||||
textPos.Y += GUI.SubHeadingFont.MeasureString(focusName).Y;
|
||||
@@ -544,11 +558,14 @@ namespace Barotrauma
|
||||
|
||||
if (character.FocusedCharacter.CanBeDragged)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBindText(InputType.Grab)),
|
||||
string text = character.CanEat ? "EatHint" : "GrabHint";
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText(text, GameMain.Config.KeyBindText(InputType.Grab)),
|
||||
GUI.Style.Green, Color.Black, 2, GUI.SmallFont);
|
||||
textPos.Y += largeTextSize.Y;
|
||||
}
|
||||
|
||||
if (!character.DisableHealthWindow &&
|
||||
character.IsFriendly(character.FocusedCharacter) &&
|
||||
character.FocusedCharacter.CharacterHealth.UseHealthWindow &&
|
||||
character.CanInteractWith(character.FocusedCharacter, 160f, false))
|
||||
{
|
||||
|
||||
@@ -170,15 +170,37 @@ namespace Barotrauma
|
||||
if (TeamID == CharacterTeamType.FriendlyNPC) { return; }
|
||||
if (Character.Controlled != null && Character.Controlled.TeamID != TeamID) { return; }
|
||||
|
||||
// if we increased by more than 1 in one increase, then display special color (for talents)
|
||||
bool specialIncrease = Math.Abs(newLevel - prevLevel) >= 1.0f;
|
||||
|
||||
if ((int)newLevel > (int)prevLevel)
|
||||
{
|
||||
int increase = Math.Max((int)newLevel - (int)prevLevel, 1);
|
||||
GUI.AddMessage(
|
||||
string.Format("+{0} {1}", increase, TextManager.Get("SkillName." + skillIdentifier)),
|
||||
GUI.Style.Green,
|
||||
string.Format("+{0} {1}", increase, TextManager.Get("SkillName." + skillIdentifier)),
|
||||
specialIncrease ? GUI.Style.Orange : GUI.Style.Green,
|
||||
textPopupPos,
|
||||
Vector2.UnitY * 10.0f,
|
||||
playSound: false,
|
||||
playSound: specialIncrease,
|
||||
subId: Character?.Submarine?.ID ?? -1);
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnExperienceChanged(int prevAmount, int newAmount, Vector2 textPopupPos)
|
||||
{
|
||||
if (Character.Controlled != null && Character.Controlled.TeamID != TeamID) { return; }
|
||||
|
||||
GameSession.TabMenuInstance?.OnExperienceChanged(Character);
|
||||
|
||||
if (newAmount > prevAmount)
|
||||
{
|
||||
int increase = newAmount - prevAmount;
|
||||
GUI.AddMessage(
|
||||
string.Format("+{0} {1}", increase, TextManager.Get("experienceshort")),
|
||||
GUI.Style.Blue,
|
||||
textPopupPos,
|
||||
Vector2.UnitY * 10.0f,
|
||||
playSound: true,
|
||||
subId: Character?.Submarine?.ID ?? -1);
|
||||
}
|
||||
}
|
||||
@@ -591,6 +613,17 @@ namespace Barotrauma
|
||||
}
|
||||
ch.Job.Skills.RemoveAll(s => !skillLevels.ContainsKey(s.Identifier));
|
||||
}
|
||||
|
||||
byte savedStatValueCount = inc.ReadByte();
|
||||
for (int i = 0; i < savedStatValueCount; i++)
|
||||
{
|
||||
int statType = inc.ReadByte();
|
||||
string statIdentifier = inc.ReadString();
|
||||
float statValue = inc.ReadSingle();
|
||||
bool removeOnDeath = inc.ReadBoolean();
|
||||
ch.ChangeSavedStatValue((StatTypes)statType, statValue, statIdentifier, removeOnDeath);
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,15 +119,23 @@ namespace Barotrauma
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
msg.WriteRangedInteger(0, 0, 3);
|
||||
msg.WriteRangedInteger(0, 0, 4);
|
||||
Inventory.ClientWrite(msg, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.Treatment:
|
||||
msg.WriteRangedInteger(1, 0, 3);
|
||||
msg.WriteRangedInteger(1, 0, 4);
|
||||
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
|
||||
break;
|
||||
case NetEntityEvent.Type.Status:
|
||||
msg.WriteRangedInteger(2, 0, 3);
|
||||
msg.WriteRangedInteger(2, 0, 4);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateTalents:
|
||||
msg.WriteRangedInteger(3, 0, 4);
|
||||
msg.Write((ushort)characterTalents.Count);
|
||||
foreach (var unlockedTalent in characterTalents)
|
||||
{
|
||||
msg.Write(unlockedTalent.Prefab.UIntIdentifier);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -258,7 +266,7 @@ namespace Barotrauma
|
||||
if (readStatus)
|
||||
{
|
||||
ReadStatus(msg);
|
||||
(AIController as EnemyAIController)?.PetBehavior?.ClientRead(msg);
|
||||
AIController?.ClientRead(msg);
|
||||
}
|
||||
|
||||
msg.ReadPadBits();
|
||||
@@ -291,7 +299,7 @@ namespace Barotrauma
|
||||
|
||||
break;
|
||||
case ServerNetObject.ENTITY_EVENT:
|
||||
int eventType = msg.ReadRangedInteger(0, 9);
|
||||
int eventType = msg.ReadRangedInteger(0, 12);
|
||||
switch (eventType)
|
||||
{
|
||||
case 0: //NetEntityEvent.Type.InventoryState
|
||||
@@ -387,6 +395,7 @@ namespace Barotrauma
|
||||
if (eventType == 4)
|
||||
{
|
||||
SetAttackTarget(attackLimb, targetEntity, targetSimPos);
|
||||
PlaySound(CharacterSound.SoundType.Attack, maxInterval: 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -450,6 +459,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 10: //NetEntityEvent.Type.UpdateExperience
|
||||
int experienceAmount = msg.ReadInt32();
|
||||
info?.SetExperience(experienceAmount);
|
||||
break;
|
||||
case 11: //NetEntityEvent.Type.UpdateTalents:
|
||||
ushort talentCount = msg.ReadUInt16();
|
||||
for (int i = 0; i < talentCount; i++)
|
||||
{
|
||||
UInt32 talentIdentifier = msg.ReadUInt32();
|
||||
GiveTalent(talentIdentifier);
|
||||
}
|
||||
break;
|
||||
case 12: //NetEntityEvent.Type.UpdateMoney:
|
||||
int moneyAmount = msg.ReadInt32();
|
||||
SetMoney(moneyAmount);
|
||||
break;
|
||||
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
break;
|
||||
|
||||
@@ -543,7 +543,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
var causeOfDeath = GetCauseOfDeath();
|
||||
Character.Controlled.Kill(causeOfDeath.First, causeOfDeath.Second);
|
||||
Character.Controlled.Kill(causeOfDeath.type, causeOfDeath.affliction);
|
||||
Character.Controlled = null;
|
||||
}
|
||||
}
|
||||
@@ -683,19 +683,33 @@ namespace Barotrauma
|
||||
float particleMaxScale = emitter?.Prefab.Properties.ScaleMax ?? 1;
|
||||
float severity = Math.Min(affliction.Strength / affliction.Prefab.MaxStrength * Character.Params.BleedParticleMultiplier, 1);
|
||||
float bloodParticleSize = MathHelper.Lerp(particleMinScale, particleMaxScale, severity);
|
||||
|
||||
Vector2 velocity = Rand.Vector(affliction.Strength * 0.1f);
|
||||
if (!inWater)
|
||||
{
|
||||
bloodParticleSize *= 2.0f;
|
||||
velocity = targetLimb.LinearVelocity * 100.0f;
|
||||
}
|
||||
|
||||
// TODO: use the blood emitter?
|
||||
var blood = GameMain.ParticleManager.CreateParticle(
|
||||
inWater ? Character.Params.BleedParticleWater : Character.Params.BleedParticleAir,
|
||||
targetLimb.WorldPosition, Rand.Vector(affliction.Strength), 0.0f, Character.AnimController.CurrentHull);
|
||||
targetLimb.WorldPosition, velocity, 0.0f, Character.AnimController.CurrentHull);
|
||||
|
||||
if (blood != null)
|
||||
if (blood != null && !inWater)
|
||||
{
|
||||
blood.Size *= bloodParticleSize;
|
||||
if (!string.IsNullOrEmpty(Character.BloodDecalName) && Rand.Range(0.0f, 1.0f) < 0.05f)
|
||||
{
|
||||
blood.OnCollision += (Vector2 pos, Hull hull) =>
|
||||
{
|
||||
var decal = hull?.AddDecal(Character.BloodDecalName, pos, Rand.Range(1.0f, 2.0f), isNetworkEvent: true);
|
||||
if (decal != null)
|
||||
{
|
||||
decal.FadeTimer = decal.LifeTime - decal.FadeOutTime * 2;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
bloodParticleTimer = MathHelper.Lerp(2, 0.5f, severity);
|
||||
}
|
||||
@@ -1968,9 +1982,9 @@ namespace Barotrauma
|
||||
healthBarHolder.Visible = value;
|
||||
}
|
||||
|
||||
private readonly List<Pair<AfflictionPrefab, float>> newAfflictions = new List<Pair<AfflictionPrefab, float>>();
|
||||
private readonly List<Triplet<LimbHealth, AfflictionPrefab, float>> newLimbAfflictions = new List<Triplet<LimbHealth, AfflictionPrefab, float>>();
|
||||
private readonly List<Pair<AfflictionPrefab.PeriodicEffect, float>> newPeriodicEffects = new List<Pair<AfflictionPrefab.PeriodicEffect, float>>();
|
||||
private readonly List<(AfflictionPrefab afflictionPrefab, float strength)> newAfflictions = new List<(AfflictionPrefab afflictionPrefab, float strength)>();
|
||||
private readonly List<(LimbHealth limb, AfflictionPrefab afflictionPrefab, float strength)> newLimbAfflictions = new List<(LimbHealth limb, AfflictionPrefab afflictionPrefab, float strength)>();
|
||||
private readonly List<(AfflictionPrefab.PeriodicEffect effect, float timer)> newPeriodicEffects = new List<(AfflictionPrefab.PeriodicEffect effect, float timer)>();
|
||||
|
||||
public void ClientRead(IReadMessage inc)
|
||||
{
|
||||
@@ -1997,41 +2011,41 @@ namespace Barotrauma
|
||||
for (int j = 0; j < periodicAfflictionCount; j++)
|
||||
{
|
||||
float periodicAfflictionTimer = inc.ReadRangedSingle(afflictionPrefab.PeriodicEffects[j].MinInterval, afflictionPrefab.PeriodicEffects[j].MaxInterval, 8);
|
||||
newPeriodicEffects.Add(new Pair<AfflictionPrefab.PeriodicEffect, float>(afflictionPrefab.PeriodicEffects[j], periodicAfflictionTimer));
|
||||
newPeriodicEffects.Add((afflictionPrefab.PeriodicEffects[j], periodicAfflictionTimer));
|
||||
}
|
||||
newAfflictions.Add(new Pair<AfflictionPrefab, float>(afflictionPrefab, afflictionStrength));
|
||||
newAfflictions.Add((afflictionPrefab, afflictionStrength));
|
||||
}
|
||||
|
||||
foreach (Affliction affliction in afflictions)
|
||||
{
|
||||
//deactivate afflictions that weren't included in the network message
|
||||
if (!newAfflictions.Any(a => a.First == affliction.Prefab))
|
||||
if (!newAfflictions.Any(a => a.afflictionPrefab == affliction.Prefab))
|
||||
{
|
||||
affliction.Strength = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Pair<AfflictionPrefab, float> newAffliction in newAfflictions)
|
||||
foreach (var (afflictionPrefab, strength) in newAfflictions)
|
||||
{
|
||||
Affliction existingAffliction = afflictions.Find(a => a.Prefab == newAffliction.First);
|
||||
Affliction existingAffliction = afflictions.Find(a => a.Prefab == afflictionPrefab);
|
||||
if (existingAffliction == null)
|
||||
{
|
||||
existingAffliction = newAffliction.First.Instantiate(newAffliction.Second);
|
||||
existingAffliction = afflictionPrefab.Instantiate(strength);
|
||||
afflictions.Add(existingAffliction);
|
||||
}
|
||||
existingAffliction.SetStrength(newAffliction.Second);
|
||||
existingAffliction.SetStrength(strength);
|
||||
if (existingAffliction == stunAffliction)
|
||||
{
|
||||
Character.SetStun(existingAffliction.Strength, true, true);
|
||||
}
|
||||
foreach (var periodicEffect in newPeriodicEffects)
|
||||
{
|
||||
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.First)) { continue; }
|
||||
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) { continue; }
|
||||
//timer has wrapped around, apply the effect
|
||||
if (periodicEffect.Second - existingAffliction.PeriodicEffectTimers[periodicEffect.First] > periodicEffect.First.MinInterval / 2)
|
||||
if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
|
||||
{
|
||||
existingAffliction.PeriodicEffectTimers[periodicEffect.First] = periodicEffect.Second;
|
||||
foreach (StatusEffect effect in periodicEffect.First.StatusEffects)
|
||||
existingAffliction.PeriodicEffectTimers[periodicEffect.effect] = periodicEffect.timer;
|
||||
foreach (StatusEffect effect in periodicEffect.effect.StatusEffects)
|
||||
{
|
||||
existingAffliction.ApplyStatusEffect(ActionType.OnActive, effect, deltaTime: 1.0f, this, targetLimb: null);
|
||||
}
|
||||
@@ -2063,9 +2077,9 @@ namespace Barotrauma
|
||||
for (int j = 0; j < periodicAfflictionCount; j++)
|
||||
{
|
||||
float periodicAfflictionTimer = inc.ReadRangedSingle(afflictionPrefab.PeriodicEffects[j].MinInterval, afflictionPrefab.PeriodicEffects[j].MaxInterval, 8);
|
||||
newPeriodicEffects.Add(new Pair<AfflictionPrefab.PeriodicEffect, float>(afflictionPrefab.PeriodicEffects[j], periodicAfflictionTimer));
|
||||
newPeriodicEffects.Add((afflictionPrefab.PeriodicEffects[j], periodicAfflictionTimer));
|
||||
}
|
||||
newLimbAfflictions.Add(new Triplet<LimbHealth, AfflictionPrefab, float>(limbHealths[limbIndex], afflictionPrefab, afflictionStrength));
|
||||
newLimbAfflictions.Add((limbHealths[limbIndex], afflictionPrefab, afflictionStrength));
|
||||
}
|
||||
|
||||
foreach (LimbHealth limbHealth in limbHealths)
|
||||
@@ -2073,33 +2087,33 @@ namespace Barotrauma
|
||||
foreach (Affliction affliction in limbHealth.Afflictions)
|
||||
{
|
||||
//deactivate afflictions that weren't included in the network message
|
||||
if (!newLimbAfflictions.Any(a => a.First == limbHealth && a.Second == affliction.Prefab))
|
||||
if (!newLimbAfflictions.Any(a => a.limb == limbHealth && a.afflictionPrefab == affliction.Prefab))
|
||||
{
|
||||
affliction.Strength = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Triplet<LimbHealth, AfflictionPrefab, float> newAffliction in newLimbAfflictions)
|
||||
foreach (var (limb, afflictionPrefab, strength) in newLimbAfflictions)
|
||||
{
|
||||
if (newAffliction.First != limbHealth) { continue; }
|
||||
Affliction existingAffliction = limbHealth.Afflictions.Find(a => a.Prefab == newAffliction.Second);
|
||||
if (limb != limbHealth) { continue; }
|
||||
Affliction existingAffliction = limbHealth.Afflictions.Find(a => a.Prefab == afflictionPrefab);
|
||||
if (existingAffliction == null)
|
||||
{
|
||||
existingAffliction = newAffliction.Second.Instantiate(newAffliction.Third);
|
||||
existingAffliction = afflictionPrefab.Instantiate(strength);
|
||||
limbHealth.Afflictions.Add(existingAffliction);
|
||||
}
|
||||
existingAffliction.SetStrength(newAffliction.Third);
|
||||
existingAffliction.SetStrength(strength);
|
||||
|
||||
foreach (var periodicEffect in newPeriodicEffects)
|
||||
{
|
||||
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.First)) { continue; }
|
||||
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) { continue; }
|
||||
//timer has wrapped around, apply the effect
|
||||
if (periodicEffect.Second - existingAffliction.PeriodicEffectTimers[periodicEffect.First] > periodicEffect.First.MinInterval / 2)
|
||||
if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
|
||||
{
|
||||
existingAffliction.PeriodicEffectTimers[periodicEffect.First] = periodicEffect.Second;
|
||||
foreach (StatusEffect effect in periodicEffect.First.StatusEffects)
|
||||
existingAffliction.PeriodicEffectTimers[periodicEffect.effect] = periodicEffect.timer;
|
||||
foreach (StatusEffect effect in periodicEffect.effect.StatusEffects)
|
||||
{
|
||||
Limb targetLimb = Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == limbHealths.IndexOf(newAffliction.First));
|
||||
Limb targetLimb = Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == limbHealths.IndexOf(limb));
|
||||
existingAffliction.ApplyStatusEffect(ActionType.OnActive, effect, deltaTime: 1.0f, this, targetLimb: targetLimb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,14 +418,14 @@ namespace Barotrauma
|
||||
ShowQuestionPrompt("The automatic hull generation may not work correctly if your submarine uses curved walls. Do you want to continue? Y/N",
|
||||
(option2) =>
|
||||
{
|
||||
if (option2.ToLower() == "y") { GameMain.SubEditorScreen.AutoHull(); }
|
||||
if (option2.ToLowerInvariant() == "y") { GameMain.SubEditorScreen.AutoHull(); }
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowQuestionPrompt("The automatic hull generation may not work correctly if your submarine uses curved walls. Do you want to continue? Y/N",
|
||||
(option) => { if (option.ToLower() == "y") GameMain.SubEditorScreen.AutoHull(); });
|
||||
(option) => { if (option.ToLowerInvariant() == "y") GameMain.SubEditorScreen.AutoHull(); });
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -608,7 +608,7 @@ namespace Barotrauma
|
||||
ShowQuestionPrompt($"Some keybinds may render the game unusable, are you sure you want to make these keybinds persistent? ({Keybinds.Count} keybind(s) assigned) Y/N",
|
||||
(option2) =>
|
||||
{
|
||||
if (option2.ToLower() != "y")
|
||||
if (option2.ToLowerInvariant() != "y")
|
||||
{
|
||||
NewMessage("Aborted.", GUI.Style.Red);
|
||||
return;
|
||||
@@ -689,6 +689,9 @@ namespace Barotrauma
|
||||
AssignRelayToServer("setskill", true);
|
||||
AssignRelayToServer("readycheck", true);
|
||||
|
||||
AssignRelayToServer("givetalent", true);
|
||||
AssignRelayToServer("giveexperience", true);
|
||||
|
||||
AssignOnExecute("control", (string[] args) =>
|
||||
{
|
||||
if (args.Length < 1) return;
|
||||
|
||||
@@ -163,6 +163,7 @@ namespace Barotrauma
|
||||
public static ScalableFont SubHeadingFont => Style?.SubHeadingFont;
|
||||
public static ScalableFont DigitalFont => Style?.DigitalFont;
|
||||
public static ScalableFont HotkeyFont => Style?.HotkeyFont;
|
||||
public static ScalableFont MonospacedFont => Style?.MonospacedFont;
|
||||
|
||||
public static ScalableFont CJKFont { get; private set; }
|
||||
|
||||
@@ -306,7 +307,7 @@ namespace Barotrauma
|
||||
});
|
||||
|
||||
SubmarineIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(452, 385, 182, 81), new Vector2(0.5f, 0.5f));
|
||||
arrow = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(392, 393, 49, 45), new Vector2(0.5f, 0.5f));
|
||||
arrow = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(393, 393, 49, 45), new Vector2(0.5f, 0.5f));
|
||||
SpeechBubbleIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(385, 449, 66, 60), new Vector2(0.5f, 0.5f));
|
||||
BrokenIcon = new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(898, 386, 123, 123), new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
@@ -672,6 +673,12 @@ namespace Barotrauma
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable);
|
||||
|
||||
if (GameMain.GameSession?.CrewManager is { DraggedOrder: { SymbolSprite: { } orderSprite, Color: var color }, DragOrder: true })
|
||||
{
|
||||
float spriteSize = Math.Max(orderSprite.size.X, orderSprite.size.Y);
|
||||
orderSprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, color, orderSprite.size / 2f, scale: 32f / spriteSize * Scale);
|
||||
}
|
||||
|
||||
var sprite = MouseCursorSprites[(int)MouseCursor] ?? MouseCursorSprites[(int)CursorState.Default];
|
||||
sprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, Color.White, sprite.Origin, 0f, Scale / 1.5f);
|
||||
|
||||
@@ -927,13 +934,14 @@ namespace Barotrauma
|
||||
GUIComponent prevMouseOn = MouseOn;
|
||||
MouseOn = null;
|
||||
int inventoryIndex = -1;
|
||||
|
||||
if (Inventory.IsMouseOnInventory())
|
||||
|
||||
Inventory.RefreshMouseOnInventory();
|
||||
if (Inventory.IsMouseOnInventory)
|
||||
{
|
||||
inventoryIndex = updateList.IndexOf(CharacterHUD.HUDFrame);
|
||||
}
|
||||
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked())
|
||||
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || prevMouseOn == null)
|
||||
{
|
||||
for (var i = updateList.Count - 1; i > inventoryIndex; i--)
|
||||
{
|
||||
@@ -941,10 +949,9 @@ namespace Barotrauma
|
||||
if (!c.CanBeFocused) { continue; }
|
||||
if (c.MouseRect.Contains(PlayerInput.MousePosition))
|
||||
{
|
||||
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || c == prevMouseOn)
|
||||
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || c == prevMouseOn || prevMouseOn == null)
|
||||
{
|
||||
MouseOn = c;
|
||||
var sakdjfnsjkd = c.MouseRect;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -958,7 +965,6 @@ namespace Barotrauma
|
||||
MouseCursor = UpdateMouseCursorState(MouseOn);
|
||||
return MouseOn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static CursorState UpdateMouseCursorState(GUIComponent c)
|
||||
@@ -1050,7 +1056,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (listBox.DraggedElement != null) { return CursorState.Dragging; }
|
||||
if (listBox.CanDragElements) { return CursorState.Move; }
|
||||
|
||||
|
||||
var hoverParent = c;
|
||||
while (true)
|
||||
{
|
||||
@@ -1059,14 +1065,14 @@ namespace Barotrauma
|
||||
hoverParent = hoverParent.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (parent != null && parent.CanBeFocused)
|
||||
{
|
||||
if (!parent.Rect.Equals(monitorRect)) { return parent.HoverCursor; }
|
||||
}
|
||||
}
|
||||
|
||||
if (Inventory.IsMouseOnInventory()) { return Inventory.GetInventoryMouseCursor(); }
|
||||
|
||||
if (Inventory.IsMouseOnInventory) { return Inventory.GetInventoryMouseCursor(); }
|
||||
|
||||
var character = Character.Controlled;
|
||||
// ReSharper disable once InvertIf
|
||||
@@ -1343,7 +1349,7 @@ namespace Barotrauma
|
||||
|
||||
/// <param name="createOffset">Should the indicator move based on the camera position?</param>
|
||||
/// <param name="overrideAlpha">Override the distance-based alpha value with the specified alpha value</param>
|
||||
public static void DrawIndicator(SpriteBatch spriteBatch, in Vector2 worldPosition, Camera cam, in Vector2 visibleRange, Sprite sprite, in Color color,
|
||||
public static void DrawIndicator(SpriteBatch spriteBatch, in Vector2 worldPosition, Camera cam, in Range<float> visibleRange, Sprite sprite, in Color color,
|
||||
bool createOffset = true, float scaleMultiplier = 1.0f, float? overrideAlpha = null)
|
||||
{
|
||||
Vector2 diff = worldPosition - cam.WorldViewCenter;
|
||||
@@ -1351,9 +1357,9 @@ namespace Barotrauma
|
||||
|
||||
float symbolScale = Math.Min(64.0f / sprite.size.X, 1.0f) * scaleMultiplier * Scale;
|
||||
|
||||
if (overrideAlpha.HasValue || (dist > visibleRange.X && dist < visibleRange.Y))
|
||||
if (overrideAlpha.HasValue || (dist > visibleRange.Start && dist < visibleRange.End))
|
||||
{
|
||||
float alpha = overrideAlpha ?? MathUtils.Min((dist - visibleRange.X) / 100.0f, 1.0f - ((dist - visibleRange.Y + 100f) / 100.0f), 1.0f);
|
||||
float alpha = overrideAlpha ?? MathUtils.Min((dist - visibleRange.Start) / 100.0f, 1.0f - ((dist - visibleRange.End + 100f) / 100.0f), 1.0f);
|
||||
Vector2 targetScreenPos = cam.WorldToScreen(worldPosition);
|
||||
|
||||
if (!createOffset)
|
||||
@@ -1417,7 +1423,7 @@ namespace Barotrauma
|
||||
public static void DrawIndicator(SpriteBatch spriteBatch, Vector2 worldPosition, Camera cam, float hideDist, Sprite sprite, Color color,
|
||||
bool createOffset = true, float scaleMultiplier = 1.0f, float? overrideAlpha = null)
|
||||
{
|
||||
DrawIndicator(spriteBatch, worldPosition, cam, new Vector2(hideDist, float.PositiveInfinity), sprite, color, createOffset, scaleMultiplier, overrideAlpha);
|
||||
DrawIndicator(spriteBatch, worldPosition, cam, new Range<float>(hideDist, float.PositiveInfinity), sprite, color, createOffset, scaleMultiplier, overrideAlpha);
|
||||
}
|
||||
|
||||
public static void DrawLine(SpriteBatch sb, Vector2 start, Vector2 end, Color clr, float depth = 0.0f, float width = 1)
|
||||
@@ -1520,6 +1526,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawFilledRectangle(SpriteBatch sb, RectangleF rect, Color clr, float depth = 0.0f)
|
||||
{
|
||||
DrawFilledRectangle(sb, rect.Location, rect.Size, clr, depth);
|
||||
}
|
||||
|
||||
public static void DrawFilledRectangle(SpriteBatch sb, Vector2 start, Vector2 size, Color clr, float depth = 0.0f)
|
||||
{
|
||||
if (size.X < 0)
|
||||
|
||||
@@ -52,13 +52,13 @@ namespace Barotrauma
|
||||
|
||||
public GUIComponent GetChild(int index)
|
||||
{
|
||||
if (index < 0 || index >= CountChildren) return null;
|
||||
if (index < 0 || index >= CountChildren) { return null; }
|
||||
return RectTransform.GetChild(index).GUIComponent;
|
||||
}
|
||||
|
||||
public int GetChildIndex(GUIComponent child)
|
||||
{
|
||||
if (child == null) return -1;
|
||||
if (child == null) { return -1; }
|
||||
return RectTransform.GetChildIndex(child.RectTransform);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (GUIComponent child in Children)
|
||||
{
|
||||
if (child.UserData == obj || (child.userData != null && child.userData.Equals(obj))) return child;
|
||||
if (child.UserData == obj || (child.userData != null && child.userData.Equals(obj))) { return child; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -175,6 +175,8 @@ namespace Barotrauma
|
||||
|
||||
public bool GlowOnSelect { get; set; }
|
||||
|
||||
public Vector2 UVOffset { get; set; }
|
||||
|
||||
private CoroutineHandle pulsateCoroutine;
|
||||
|
||||
protected Color flashColor;
|
||||
@@ -256,9 +258,9 @@ namespace Barotrauma
|
||||
|
||||
protected Rectangle ClampRect(Rectangle r)
|
||||
{
|
||||
if (Parent == null || !ClampMouseRectToParent) return r;
|
||||
if (Parent == null || !ClampMouseRectToParent) { return r; }
|
||||
Rectangle parentRect = Parent.ClampRect(Parent.Rect);
|
||||
if (parentRect.Width <= 0 || parentRect.Height <= 0) return Rectangle.Empty;
|
||||
if (parentRect.Width <= 0 || parentRect.Height <= 0) { return Rectangle.Empty; }
|
||||
if (parentRect.X > r.X)
|
||||
{
|
||||
int diff = parentRect.X - r.X;
|
||||
@@ -281,7 +283,7 @@ namespace Barotrauma
|
||||
int diff = (r.Y + r.Height) - (parentRect.Y + parentRect.Height);
|
||||
r.Height -= diff;
|
||||
}
|
||||
if (r.Width <= 0 || r.Height <= 0) return Rectangle.Empty;
|
||||
if (r.Width <= 0 || r.Height <= 0) { return Rectangle.Empty; }
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -295,7 +297,7 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!CanBeFocused) return Rectangle.Empty;
|
||||
if (!CanBeFocused) { return Rectangle.Empty; }
|
||||
return ClampMouseRectToParent ? ClampRect(Rect) : Rect;
|
||||
}
|
||||
}
|
||||
@@ -431,7 +433,7 @@ namespace Barotrauma
|
||||
#region Updating
|
||||
public virtual void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
|
||||
UpdateOrder = order;
|
||||
GUI.AddToUpdateList(this);
|
||||
@@ -463,7 +465,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public void UpdateManually(float deltaTime, bool alsoChildren = false, bool recursive = true)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
|
||||
AutoUpdate = false;
|
||||
Update(deltaTime);
|
||||
@@ -475,7 +477,7 @@ namespace Barotrauma
|
||||
|
||||
protected virtual void Update(float deltaTime)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
|
||||
if (CanBeFocused && OnSecondaryClicked != null)
|
||||
{
|
||||
@@ -555,7 +557,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public virtual void DrawManually(SpriteBatch spriteBatch, bool alsoChildren = false, bool recursive = true)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
|
||||
AutoDraw = false;
|
||||
Draw(spriteBatch);
|
||||
@@ -598,7 +600,7 @@ namespace Barotrauma
|
||||
|
||||
protected virtual void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
var rect = Rect;
|
||||
|
||||
GetBlendedColor(GetColor(State), ref _currentColor);
|
||||
@@ -653,7 +655,7 @@ namespace Barotrauma
|
||||
? MathUtils.InverseLerp(0, SpriteCrossFadeTime, ToolBox.GetEasing(uiSprite.TransitionMode, spriteFadeTimer)) : 0;
|
||||
if (alphaMultiplier > 0)
|
||||
{
|
||||
uiSprite.Draw(spriteBatch, rect, previousColor * alphaMultiplier, SpriteEffects);
|
||||
uiSprite.Draw(spriteBatch, rect, previousColor * alphaMultiplier, SpriteEffects, uvOffset: UVOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -667,7 +669,11 @@ namespace Barotrauma
|
||||
? MathUtils.InverseLerp(SpriteCrossFadeTime, 0, ToolBox.GetEasing(uiSprite.TransitionMode, spriteFadeTimer)) : (_currentColor.A / 255.0f);
|
||||
if (alphaMultiplier > 0)
|
||||
{
|
||||
uiSprite.Draw(spriteBatch, rect, _currentColor * alphaMultiplier, SpriteEffects);
|
||||
// * (rect.Location.Y - PlayerInput.MousePosition.Y) / rect.Height
|
||||
Vector2 offset = new Vector2(
|
||||
MathUtils.PositiveModulo((int)-UVOffset.X, uiSprite.Sprite.SourceRect.Width),
|
||||
MathUtils.PositiveModulo((int)-UVOffset.Y, uiSprite.Sprite.SourceRect.Height));
|
||||
uiSprite.Draw(spriteBatch, rect, _currentColor * alphaMultiplier, SpriteEffects, uvOffset: offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -708,7 +714,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public void DrawToolTip(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!Visible) return;
|
||||
if (!Visible) { return; }
|
||||
DrawToolTip(spriteBatch, ToolTip, GUI.MouseOn.Rect, TooltipRichTextData);
|
||||
}
|
||||
|
||||
@@ -1048,7 +1054,7 @@ namespace Barotrauma
|
||||
{
|
||||
case "language":
|
||||
string[] languages = element.GetAttributeStringArray(attribute.Name.ToString(), new string[0]);
|
||||
if (!languages.Any(l => GameMain.Config.Language.ToLower() == l.ToLower())) { return false; }
|
||||
if (!languages.Any(l => GameMain.Config.Language.Equals(l, StringComparison.OrdinalIgnoreCase))) { return false; }
|
||||
break;
|
||||
case "gameversion":
|
||||
var version = new Version(attribute.Value);
|
||||
@@ -1213,8 +1219,7 @@ namespace Barotrauma
|
||||
|
||||
private static GUIImage LoadGUIImage(XElement element, RectTransform parent)
|
||||
{
|
||||
Sprite sprite = null;
|
||||
|
||||
Sprite sprite;
|
||||
string url = element.GetAttributeString("url", "");
|
||||
if (!string.IsNullOrEmpty(url))
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Barotrauma
|
||||
|
||||
if (OutlineColor != Color.Transparent)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, Rect, OutlineColor * (OutlineColor.A/255.0f), false, thickness: OutlineThickness);
|
||||
GUI.DrawRectangle(spriteBatch, Rect, OutlineColor, false, thickness: OutlineThickness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Barotrauma
|
||||
public GUIFrame Content { get; private set; }
|
||||
public GUIScrollBar ScrollBar { get; private set; }
|
||||
|
||||
private Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
|
||||
private readonly Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
|
||||
|
||||
private int totalSize;
|
||||
private bool childrenNeedsRecalculation;
|
||||
@@ -224,7 +224,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (value == false && canDragElements && draggedElement != null)
|
||||
{
|
||||
draggedElement = null;
|
||||
DraggedElement = null;
|
||||
}
|
||||
canDragElements = value;
|
||||
}
|
||||
@@ -233,8 +233,21 @@ namespace Barotrauma
|
||||
private GUIComponent draggedElement;
|
||||
private Rectangle draggedReferenceRectangle;
|
||||
private Point draggedReferenceOffset;
|
||||
public bool HasDraggedElementIndexChanged { get; private set; }
|
||||
|
||||
public GUIComponent DraggedElement => draggedElement;
|
||||
public GUIComponent DraggedElement
|
||||
{
|
||||
get
|
||||
{
|
||||
return draggedElement;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == draggedElement) { return; }
|
||||
draggedElement = value;
|
||||
HasDraggedElementIndexChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly bool isHorizontal;
|
||||
|
||||
@@ -472,7 +485,7 @@ namespace Barotrauma
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
OnRearranged?.Invoke(this, draggedElement.UserData);
|
||||
draggedElement = null;
|
||||
DraggedElement = null;
|
||||
RepositionChildren();
|
||||
}
|
||||
else
|
||||
@@ -518,6 +531,7 @@ namespace Barotrauma
|
||||
if (currIndex != index)
|
||||
{
|
||||
draggedElement.RectTransform.RepositionChildInHierarchy(currIndex);
|
||||
HasDraggedElementIndexChanged = true;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -577,7 +591,7 @@ namespace Barotrauma
|
||||
|
||||
if (CanDragElements && PlayerInput.PrimaryMouseButtonDown() && GUI.MouseOn == child)
|
||||
{
|
||||
draggedElement = child;
|
||||
DraggedElement = child;
|
||||
draggedReferenceRectangle = child.Rect;
|
||||
draggedReferenceOffset = child.RectTransform.AbsoluteOffset;
|
||||
}
|
||||
@@ -750,7 +764,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if ((GUI.IsMouseOn(this) || GUI.IsMouseOn(ScrollBar)) && AllowMouseWheelScroll && PlayerInput.ScrollWheelSpeed != 0)
|
||||
if (PlayerInput.ScrollWheelSpeed != 0 && AllowMouseWheelScroll && (FindScrollableParentListBox(GUI.MouseOn) == this || GUI.IsMouseOn(ScrollBar)))
|
||||
{
|
||||
if (SmoothScroll)
|
||||
{
|
||||
@@ -773,7 +787,6 @@ namespace Barotrauma
|
||||
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ScrollBar.Enabled = ScrollBarEnabled && BarSize < 1.0f;
|
||||
if (AutoHideScrollBar)
|
||||
@@ -785,6 +798,13 @@ namespace Barotrauma
|
||||
UpdateDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
private static GUIListBox FindScrollableParentListBox(GUIComponent target)
|
||||
{
|
||||
if (target is GUIListBox listBox && listBox.ScrollBarEnabled && listBox.BarSize < 1.0f) { return listBox; }
|
||||
if (target?.Parent == null) { return null; }
|
||||
return FindScrollableParentListBox(target.Parent);
|
||||
}
|
||||
|
||||
public void SelectNext(bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
{
|
||||
@@ -982,7 +1002,7 @@ namespace Barotrauma
|
||||
if (child == null) { return; }
|
||||
child.RectTransform.Parent = null;
|
||||
if (selected.Contains(child)) { selected.Remove(child); }
|
||||
if (draggedElement == child) { draggedElement = null; }
|
||||
if (draggedElement == child) { DraggedElement = null; }
|
||||
UpdateScrollBarSize();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class GUIScissorComponent: GUIComponent
|
||||
{
|
||||
public GUIComponent Content;
|
||||
|
||||
public GUIScissorComponent(RectTransform rectT) : base(null, rectT)
|
||||
{
|
||||
Content = new GUIFrame(new RectTransform(Vector2.One, rectT), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
foreach (GUIComponent child in Children)
|
||||
{
|
||||
if (child == Content) { continue; }
|
||||
throw new InvalidOperationException($"Children were found in {nameof(GUIScissorComponent)}, Add them to {nameof(GUIScissorComponent)}.{nameof(Content)} instead.");
|
||||
}
|
||||
|
||||
ClampChildMouseRects(Content);
|
||||
}
|
||||
|
||||
protected override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!Visible) { return; }
|
||||
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
RasterizerState prevRasterizerState = spriteBatch.GraphicsDevice.RasterizerState;
|
||||
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, Rect);
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
|
||||
foreach (GUIComponent child in Content.Children)
|
||||
{
|
||||
if (!child.Visible) { continue; }
|
||||
child.DrawManually(spriteBatch, alsoChildren: true, recursive: true);
|
||||
}
|
||||
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: prevRasterizerState);
|
||||
}
|
||||
|
||||
private void ClampChildMouseRects(GUIComponent child)
|
||||
{
|
||||
child.ClampMouseRectToParent = true;
|
||||
|
||||
if (child is GUIListBox) { return; }
|
||||
|
||||
foreach (GUIComponent grandChild in child.Children)
|
||||
{
|
||||
ClampChildMouseRects(grandChild);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
|
||||
{
|
||||
if (!Visible) { return; }
|
||||
|
||||
UpdateOrder = order;
|
||||
GUI.AddToUpdateList(this);
|
||||
|
||||
if (ignoreChildren)
|
||||
{
|
||||
OnAddedToGUIUpdateList?.Invoke(this);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (GUIComponent child in Content.Children)
|
||||
{
|
||||
if (!child.Visible) { continue; }
|
||||
child.AddToGUIUpdateList(false, order);
|
||||
}
|
||||
OnAddedToGUIUpdateList?.Invoke(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ namespace Barotrauma
|
||||
public ScalableFont SubHeadingFont { get; private set; }
|
||||
public ScalableFont DigitalFont { get; private set; }
|
||||
public ScalableFont HotkeyFont { get; private set; }
|
||||
public ScalableFont MonospacedFont { get; private set; }
|
||||
|
||||
public Dictionary<ScalableFont, bool> ForceFontUpperCase
|
||||
{
|
||||
@@ -40,11 +41,16 @@ namespace Barotrauma
|
||||
public SpriteSheet SavingIndicator { get; private set; }
|
||||
|
||||
public UISprite UIGlow { get; private set; }
|
||||
|
||||
public UISprite PingCircle { get; private set; }
|
||||
|
||||
public UISprite UIGlowCircular { get; private set; }
|
||||
|
||||
public UISprite ButtonPulse { get; private set; }
|
||||
|
||||
public SpriteSheet FocusIndicator { get; private set; }
|
||||
|
||||
public UISprite IconOverflowIndicator { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// General green color used for elements whose colors are set from code
|
||||
@@ -235,6 +241,9 @@ namespace Barotrauma
|
||||
case "uiglow":
|
||||
UIGlow = new UISprite(subElement);
|
||||
break;
|
||||
case "pingcircle":
|
||||
PingCircle = new UISprite(subElement);
|
||||
break;
|
||||
case "radiation":
|
||||
RadiationSprite = new UISprite(subElement);
|
||||
break;
|
||||
@@ -247,6 +256,9 @@ namespace Barotrauma
|
||||
case "endroundbuttonpulse":
|
||||
ButtonPulse = new UISprite(subElement);
|
||||
break;
|
||||
case "iconoverflowindicator":
|
||||
IconOverflowIndicator = new UISprite(subElement);
|
||||
break;
|
||||
case "focusindicator":
|
||||
FocusIndicator = new SpriteSheet(subElement);
|
||||
break;
|
||||
@@ -277,6 +289,10 @@ namespace Barotrauma
|
||||
DigitalFont = LoadFont(subElement, graphicsDevice);
|
||||
ForceFontUpperCase[DigitalFont] = subElement.GetAttributeBool("forceuppercase", false);
|
||||
break;
|
||||
case "monospacedfont":
|
||||
MonospacedFont = LoadFont(subElement, graphicsDevice);
|
||||
ForceFontUpperCase[MonospacedFont] = subElement.GetAttributeBool("forceuppercase", false);
|
||||
break;
|
||||
case "hotkeyfont":
|
||||
HotkeyFont = LoadFont(subElement, graphicsDevice);
|
||||
ForceFontUpperCase[HotkeyFont] = subElement.GetAttributeBool("forceuppercase", false);
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace Barotrauma
|
||||
if (GUI.MouseOn != null) { return false; }
|
||||
|
||||
//don't close when hovering over an inventory element
|
||||
if (Inventory.IsMouseOnInventory()) { return false; }
|
||||
if (Inventory.IsMouseOnInventory) { return false; }
|
||||
|
||||
bool input = PlayerInput.PrimaryMouseButtonDown() || PlayerInput.SecondaryMouseButtonClicked();
|
||||
return input && !rect.Contains(PlayerInput.MousePosition);
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace Barotrauma
|
||||
if (LoadState == 100.0f)
|
||||
{
|
||||
#if DEBUG
|
||||
if (GameMain.Config.AutomaticQuickStartEnabled || GameMain.Config.AutomaticCampaignLoadEnabled && GameMain.FirstLoad)
|
||||
if (GameMain.Config.AutomaticQuickStartEnabled || GameMain.Config.AutomaticCampaignLoadEnabled || GameMain.Config.TestScreenEnabled && GameMain.FirstLoad)
|
||||
{
|
||||
loadText = "QUICKSTARTING ...";
|
||||
}
|
||||
|
||||
@@ -55,14 +55,47 @@ namespace Barotrauma
|
||||
var texture = GetTexture(spriteBatch);
|
||||
|
||||
for (var i = 0; i < points.Count - 1; i++)
|
||||
DrawPolygonEdge(spriteBatch, texture, points[i] + offset, points[i + 1] + offset, color, thickness);
|
||||
DrawPolygonEdge(spriteBatch, points[i] + offset, points[i + 1] + offset, color, thickness);
|
||||
|
||||
DrawPolygonEdge(spriteBatch, texture, points[points.Count - 1] + offset, points[0] + offset, color,
|
||||
DrawPolygonEdge(spriteBatch, points[points.Count - 1] + offset, points[0] + offset, color,
|
||||
thickness);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a closed polygon from an array of points
|
||||
/// </summary>
|
||||
public static void DrawPolygonInner(this SpriteBatch spriteBatch, Vector2 offset, IReadOnlyList<Vector2> points, Color color, float thickness = 1f)
|
||||
{
|
||||
if (points.Count == 0) { return; }
|
||||
|
||||
private static void DrawPolygonEdge(SpriteBatch spriteBatch, Texture2D texture, Vector2 point1, Vector2 point2,
|
||||
Color color, float thickness)
|
||||
if (points.Count == 1)
|
||||
{
|
||||
DrawPoint(spriteBatch, points[0], color, (int)thickness);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < points.Count - 1; i++)
|
||||
{
|
||||
Vector2 point1 = points[i] + offset,
|
||||
point2 = points[i + 1] + offset;
|
||||
|
||||
DrawPolygonEdgeInner(spriteBatch, point1, point2, color, thickness);
|
||||
}
|
||||
|
||||
DrawPolygonEdgeInner(spriteBatch, points[^1] + offset, points[0] + offset, color, thickness);
|
||||
}
|
||||
|
||||
private static void DrawPolygonEdgeInner(SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color, float thickness)
|
||||
{
|
||||
var length = Vector2.Distance(point1, point2) + thickness;
|
||||
var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
|
||||
var scale = new Vector2(length, thickness);
|
||||
Vector2 middle = new Vector2((point1.X + point2.X) / 2f, (point1.Y + point2.Y) / 2f);
|
||||
Texture2D tex = GetTexture(spriteBatch);
|
||||
spriteBatch.Draw(GetTexture(spriteBatch), middle, null, color, angle, new Vector2(tex.Width / 2f, tex.Height / 2f), scale, SpriteEffects.None, 0);
|
||||
}
|
||||
|
||||
private static void DrawPolygonEdge(SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color, float thickness)
|
||||
{
|
||||
var length = Vector2.Distance(point1, point2);
|
||||
var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Barotrauma
|
||||
private Color storeSpecialColor;
|
||||
|
||||
private GUIListBox shoppingCrateBuyList, shoppingCrateSellList, shoppingCrateSellFromSubList;
|
||||
private GUITextBlock shoppingCrateTotal;
|
||||
private GUITextBlock relevantBalanceName, shoppingCrateTotal;
|
||||
private GUIButton clearAllButton, confirmButton;
|
||||
|
||||
private bool needsRefresh, needsBuyingRefresh, needsSellingRefresh, needsItemsToSellRefresh, needsSellingFromSubRefresh, needsItemsToSellFromSubRefresh;
|
||||
@@ -58,7 +58,6 @@ namespace Barotrauma
|
||||
StoreTab.SellFromSub => false,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
private bool IsSelling => !IsBuying;
|
||||
private GUIListBox ActiveShoppingCrateList => activeTab switch
|
||||
{
|
||||
StoreTab.Buy => shoppingCrateBuyList,
|
||||
@@ -222,16 +221,8 @@ namespace Barotrauma
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () =>
|
||||
{
|
||||
if (CurrentLocation != null)
|
||||
{
|
||||
merchantBalanceBlock.TextColor = CurrentLocation.BalanceColor;
|
||||
return GetCurrencyFormatted(CurrentLocation.StoreCurrentBalance);
|
||||
}
|
||||
else
|
||||
{
|
||||
merchantBalanceBlock.TextColor = Color.Red;
|
||||
return GetCurrencyFormatted(0);
|
||||
}
|
||||
merchantBalanceBlock.TextColor = CurrentLocation?.BalanceColor ?? Color.Red;
|
||||
return GetMerchantBalanceText();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -375,28 +366,37 @@ namespace Barotrauma
|
||||
//don't show categories with no buyable items
|
||||
itemCategories.RemoveAll(c => !ItemPrefab.Prefabs.Any(ep => ep.Category.HasFlag(c) && ep.CanBeBought));
|
||||
itemCategoryButtons.Clear();
|
||||
var categoryButton = new GUIButton(new RectTransform(new Point(categoryButtonContainer.Rect.Width, categoryButtonContainer.Rect.Width), categoryButtonContainer.RectTransform), style: "CategoryButton.All")
|
||||
{
|
||||
ToolTip = TextManager.Get("MapEntityCategory.All"),
|
||||
OnClicked = OnClickedCategoryButton
|
||||
};
|
||||
itemCategoryButtons.Add(categoryButton);
|
||||
foreach (MapEntityCategory category in itemCategories)
|
||||
{
|
||||
var categoryButton = new GUIButton(new RectTransform(new Point(categoryButtonContainer.Rect.Width, categoryButtonContainer.Rect.Width), categoryButtonContainer.RectTransform),
|
||||
categoryButton = new GUIButton(new RectTransform(new Point(categoryButtonContainer.Rect.Width, categoryButtonContainer.Rect.Width), categoryButtonContainer.RectTransform),
|
||||
style: "CategoryButton." + category)
|
||||
{
|
||||
ToolTip = TextManager.Get("MapEntityCategory." + category),
|
||||
UserData = category,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
MapEntityCategory? newCategory = !btn.Selected ? (MapEntityCategory?)userdata : null;
|
||||
if (newCategory.HasValue) { searchBox.Text = ""; }
|
||||
if (newCategory != selectedItemCategory) { tabLists[activeTab].ScrollBar.BarScroll = 0f; }
|
||||
FilterStoreItems(newCategory, searchBox.Text);
|
||||
return true;
|
||||
}
|
||||
OnClicked = OnClickedCategoryButton
|
||||
};
|
||||
itemCategoryButtons.Add(categoryButton);
|
||||
categoryButton.RectTransform.SizeChanged += () =>
|
||||
}
|
||||
bool OnClickedCategoryButton(GUIButton button, object userData)
|
||||
{
|
||||
MapEntityCategory? newCategory = !button.Selected ? (MapEntityCategory?)userData : null;
|
||||
if (newCategory.HasValue) { searchBox.Text = ""; }
|
||||
if (newCategory != selectedItemCategory) { tabLists[activeTab].ScrollBar.BarScroll = 0f; }
|
||||
FilterStoreItems(newCategory, searchBox.Text);
|
||||
return true;
|
||||
}
|
||||
foreach (var btn in itemCategoryButtons)
|
||||
{
|
||||
btn.RectTransform.SizeChanged += () =>
|
||||
{
|
||||
var sprite = categoryButton.Frame.sprites[GUIComponent.ComponentState.None].First();
|
||||
categoryButton.RectTransform.NonScaledSize =
|
||||
new Point(categoryButton.Rect.Width, (int)(categoryButton.Rect.Width * ((float)sprite.Sprite.SourceRect.Height / sprite.Sprite.SourceRect.Width)));
|
||||
var sprite = btn.Frame.sprites[GUIComponent.ComponentState.None].First();
|
||||
btn.RectTransform.NonScaledSize = new Point(btn.Rect.Width, (int)(btn.Rect.Width * ((float)sprite.Sprite.SourceRect.Height / sprite.Sprite.SourceRect.Width)));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -503,11 +503,11 @@ namespace Barotrauma
|
||||
ForceUpperCase = true
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
|
||||
"", font: GUI.SubHeadingFont, textAlignment: Alignment.TopRight)
|
||||
"", textColor: Color.White, font: GUI.SubHeadingFont, textAlignment: Alignment.TopRight)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () => GetCurrencyFormatted(PlayerMoney)
|
||||
TextGetter = GetPlayerBalanceText
|
||||
};
|
||||
|
||||
// Divider ------------------------------------------------
|
||||
@@ -523,7 +523,7 @@ namespace Barotrauma
|
||||
RelativeSpacing = 0.015f,
|
||||
Stretch = true
|
||||
};
|
||||
var shoppingCrateListContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.85f), shoppingCrateInventoryContainer.RectTransform), style: null);
|
||||
var shoppingCrateListContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.8f), shoppingCrateInventoryContainer.RectTransform), style: null);
|
||||
shoppingCrateBuyList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
shoppingCrateSellList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
if (GameMain.IsSingleplayer)
|
||||
@@ -531,6 +531,21 @@ namespace Barotrauma
|
||||
shoppingCrateSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
|
||||
}
|
||||
|
||||
var relevantBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), shoppingCrateInventoryContainer.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
relevantBalanceName = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), relevantBalanceContainer.RectTransform), "", font: GUI.Font)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), relevantBalanceContainer.RectTransform), "", textColor: Color.White, font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () => IsBuying ? GetPlayerBalanceText() : GetMerchantBalanceText()
|
||||
};
|
||||
|
||||
var totalContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), shoppingCrateInventoryContainer.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true
|
||||
@@ -576,6 +591,10 @@ namespace Barotrauma
|
||||
resolutionWhenCreated = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
}
|
||||
|
||||
private string GetMerchantBalanceText() => GetCurrencyFormatted(CurrentLocation?.StoreCurrentBalance ?? 0);
|
||||
|
||||
private string GetPlayerBalanceText() => GetCurrencyFormatted(PlayerMoney);
|
||||
|
||||
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList)
|
||||
{
|
||||
var elementHeight = (int)(GUI.yScale * 80);
|
||||
@@ -604,17 +623,14 @@ namespace Barotrauma
|
||||
{
|
||||
prevLocation.Reputation.OnReputationValueChanged = null;
|
||||
}
|
||||
|
||||
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
|
||||
if (ItemPrefab.Prefabs.Any(p => p.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo _)))
|
||||
{
|
||||
if (itemPrefab.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo _))
|
||||
selectedItemCategory = null;
|
||||
searchBox.Text = "";
|
||||
ChangeStoreTab(StoreTab.Buy);
|
||||
if (newLocation?.Reputation != null)
|
||||
{
|
||||
ChangeStoreTab(StoreTab.Buy);
|
||||
if (newLocation?.Reputation != null)
|
||||
{
|
||||
newLocation.Reputation.OnReputationValueChanged += () => { needsRefresh = true; };
|
||||
}
|
||||
return;
|
||||
newLocation.Reputation.OnReputationValueChanged += () => { needsRefresh = true; };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -628,6 +644,7 @@ namespace Barotrauma
|
||||
tabButton.Selected = (StoreTab)tabButton.UserData == activeTab;
|
||||
}
|
||||
sortingDropDown.SelectItem(tabSortingMethods[tab]);
|
||||
relevantBalanceName.Text = IsBuying ? TextManager.Get("campaignstore.balance") : TextManager.Get("campaignstore.storebalance");
|
||||
SetShoppingCrateTotalText();
|
||||
SetClearAllButtonStatus();
|
||||
SetConfirmButtonBehavior();
|
||||
@@ -697,7 +714,7 @@ namespace Barotrauma
|
||||
}
|
||||
foreach (GUIButton btn in itemCategoryButtons)
|
||||
{
|
||||
btn.Selected = category.HasValue && (MapEntityCategory)btn.UserData == selectedItemCategory;
|
||||
btn.Selected = (MapEntityCategory?)btn.UserData == selectedItemCategory;
|
||||
}
|
||||
list.UpdateScrollBarSize();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Barotrauma
|
||||
private static UISprite spectateIcon, disconnectedIcon;
|
||||
private static Sprite ownerIcon, moderatorIcon;
|
||||
|
||||
private enum InfoFrameTab { Crew, Mission, Reputation, MyCharacter, Traitor, Submarine };
|
||||
private enum InfoFrameTab { Crew, Mission, Reputation, MyCharacter, Traitor, Submarine, Talents };
|
||||
private static InfoFrameTab selectedTab;
|
||||
private GUIFrame infoFrame, contentFrame;
|
||||
|
||||
@@ -258,6 +258,8 @@ namespace Barotrauma
|
||||
{
|
||||
var myCharacterButton = createTabButton(InfoFrameTab.MyCharacter, "tabmenu.character");
|
||||
}
|
||||
|
||||
var talentsButton = createTabButton(InfoFrameTab.Talents, "tabmenu.talents");
|
||||
}
|
||||
|
||||
private bool SelectInfoFrameTab(GUIButton button, object userData)
|
||||
@@ -296,6 +298,9 @@ namespace Barotrauma
|
||||
case InfoFrameTab.Submarine:
|
||||
CreateSubmarineInfo(infoFrameHolder, Submarine.MainSub);
|
||||
break;
|
||||
case InfoFrameTab.Talents:
|
||||
CreateTalentInfo(infoFrameHolder);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1159,5 +1164,319 @@ namespace Barotrauma
|
||||
sub.Info.CreateSpecsWindow(specsListBox, GUI.Font, includeTitle: false, includeClass: false, includeDescription: true);
|
||||
}
|
||||
}
|
||||
private Color unselectedColor = new Color(240, 255, 255, 225);
|
||||
private Color selectedColor = new Color(220, 255, 220, 225);
|
||||
private Color ownedColor = new Color(140, 180, 140, 225);
|
||||
private Color unselectableColor = new Color(100, 100, 100, 225);
|
||||
private Color pressedColor = new Color(60, 60, 60, 225);
|
||||
|
||||
private readonly List<(GUIButton button, GUIImage background, GUIImage icon)> talentButtons = new List<(GUIButton button, GUIImage background, GUIImage icon)>();
|
||||
private List<string> selectedTalents = new List<string>();
|
||||
private GUITextBlock talentTitleText;
|
||||
private GUITextBlock talentDescriptionText;
|
||||
private GUITextBlock talentPointsText;
|
||||
|
||||
private GUITextBlock experienceText;
|
||||
private Color experienceBackgroundColor = new Color(255, 255, 255, 155);
|
||||
|
||||
private GUIProgressBar experienceBar;
|
||||
|
||||
private void CreateTalentInfo(GUIFrame infoFrame)
|
||||
{
|
||||
infoFrame.ClearChildren();
|
||||
talentButtons.Clear();
|
||||
|
||||
GUIFrame talentFrameBackground = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
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);
|
||||
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
|
||||
if (controlledCharacter.Info == null)
|
||||
{
|
||||
DebugConsole.ThrowError("No character info found for talent UI");
|
||||
return;
|
||||
}
|
||||
|
||||
selectedTalents = controlledCharacter.Info.UnlockedTalents.ToList();
|
||||
|
||||
GUILayoutGroup talentFrameLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), talentFrameContent.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(5)
|
||||
};
|
||||
|
||||
GUILayoutGroup talentInfoLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.325f), talentFrameLayoutGroup.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter);
|
||||
|
||||
GUIFrame talentTitleFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.25f), talentInfoLayoutGroup.RectTransform, Anchor.TopCenter), style: null);
|
||||
|
||||
talentTitleText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), talentTitleFrame.RectTransform, Anchor.TopLeft), "", font: GUI.LargeFont);
|
||||
talentPointsText = new GUITextBlock(new RectTransform(new Vector2(0.25f, 1.0f), talentTitleFrame.RectTransform, Anchor.TopRight), "", font: GUI.Font, textAlignment: Alignment.Center);
|
||||
|
||||
GUIFrame talentDescriptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.4f), talentInfoLayoutGroup.RectTransform, Anchor.TopCenter), style: null);
|
||||
|
||||
talentDescriptionText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), talentDescriptionFrame.RectTransform, Anchor.TopLeft), "", font: GUI.Font, textAlignment: Alignment.TopLeft, wrap: true);
|
||||
|
||||
GUIFrame characterInfoFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.3f), talentInfoLayoutGroup.RectTransform, Anchor.TopLeft), style: null);
|
||||
GUILayoutGroup characterInfoColumn = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), characterInfoFrame.RectTransform, anchor: Anchor.TopLeft), childAnchor: Anchor.TopLeft, isHorizontal: true);
|
||||
|
||||
CreateCharacterSheet(characterInfoColumn);
|
||||
|
||||
if (!TalentTree.JobTalentTrees.TryGetValue(controlledCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
||||
|
||||
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.6f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
||||
|
||||
int spacing = GUI.IntScale(5);
|
||||
|
||||
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);
|
||||
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: "SubtreeHeader");
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), subtreeTitleFrame.RectTransform, anchor: Anchor.TopCenter), subTree.Identifier, font: GUI.LargeFont, textAlignment: Alignment.Center);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
GUIFrame talentOptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.222f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: "TalentOptionFrame");
|
||||
GUIImage talentBackground = new GUIImage(new RectTransform(Vector2.One, talentOptionFrame.RectTransform, anchor: Anchor.Center), style: "TalentBackground")
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Color = unselectableColor,
|
||||
};
|
||||
|
||||
if (subTree.TalentOptionStages.Count > i)
|
||||
{
|
||||
TalentOption talentOption = subTree.TalentOptionStages[i];
|
||||
|
||||
GUILayoutGroup talentOptionLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), talentOptionFrame.RectTransform, Anchor.CenterLeft), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
Stretch = true,
|
||||
};
|
||||
|
||||
foreach (Talent talent in talentOption.Talents)
|
||||
{
|
||||
int optionPadding = GUI.IntScale(10);
|
||||
GUIFrame talentFrame = new GUIFrame(new RectTransform(new Point(talentOptionFrame.Rect.Width, talentOptionFrame.Rect.Height - optionPadding), talentOptionLayoutGroup.RectTransform), style: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
};
|
||||
new GUIImage(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center), style: "TalentFrameBackground")
|
||||
{
|
||||
CanBeFocused = false,
|
||||
};
|
||||
GUIImage iconImage = null;
|
||||
|
||||
GUIButton talentButton = new GUIButton(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center), style: "TalentFrame")
|
||||
{
|
||||
ToolTip = $"{TextManager.Get("talentname." + talent.Identifier, returnNull: true) ?? talent.Identifier} \n\n{TextManager.Get("talentdescription." + talent.Identifier, returnNull: true) ?? string.Empty}",
|
||||
UserData = talent.Identifier,
|
||||
PressedColor = pressedColor,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
talentTitleText.Text = TextManager.Get("talentname." + talent.Identifier, returnNull: true) ?? string.Empty;
|
||||
talentDescriptionText.Text = TextManager.Get("talentdescription." + talent.Identifier, returnNull: true) ?? string.Empty;
|
||||
|
||||
// deselect other buttons in tier by removing their selected talents from pool
|
||||
foreach (GUIButton guiButton in talentOptionLayoutGroup.GetAllChildren<GUIButton>())
|
||||
{
|
||||
if (guiButton.UserData is string otherTalentIdentifier && guiButton != button)
|
||||
{
|
||||
if (!controlledCharacter.HasTalent(otherTalentIdentifier))
|
||||
{
|
||||
selectedTalents.Remove(otherTalentIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
string talentIdentifier = userData as string;
|
||||
|
||||
if (TalentTree.IsViableTalentForCharacter(controlledCharacter, talentIdentifier, selectedTalents))
|
||||
{
|
||||
if (!selectedTalents.Contains(talentIdentifier))
|
||||
{
|
||||
selectedTalents.Add(talentIdentifier);
|
||||
}
|
||||
}
|
||||
else if (!controlledCharacter.HasTalent(talentIdentifier))
|
||||
{
|
||||
selectedTalents.Remove(talentIdentifier);
|
||||
}
|
||||
|
||||
UpdateTalentButtons();
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
int iconPadding = GUI.IntScale(15);
|
||||
iconImage = new GUIImage(new RectTransform(new Point(talentFrame.Rect.Width - iconPadding, talentFrame.Rect.Height - iconPadding), talentFrame.RectTransform, anchor: Anchor.Center), sprite: talent.Icon, scaleToFit: true)
|
||||
{
|
||||
PressedColor = unselectableColor,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
|
||||
talentButtons.Add((talentButton, talentBackground, iconImage));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUIFrame talentBottomFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.07f), talentFrameLayoutGroup.RectTransform, Anchor.TopCenter), style: null);
|
||||
|
||||
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(0.775f, 0.75f), talentBottomFrame.RectTransform, Anchor.TopCenter), style: null);
|
||||
|
||||
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
||||
barSize: controlledCharacter.Info.GetProgressTowardsNextLevel(), color: Color.White, style: "ExperienceBar")
|
||||
{
|
||||
IsHorizontal = true
|
||||
};
|
||||
|
||||
GUIImage experienceTextBackground = new GUIImage(new RectTransform(new Vector2(0.2f, 0.475f), experienceBarFrame.RectTransform, anchor: Anchor.Center), style: "ExperienceTextBackground");
|
||||
|
||||
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceTextBackground.RectTransform, anchor: Anchor.Center), "", font: GUI.Font, textColor: Color.White, textAlignment: Alignment.Center);
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 0.3f), talentBottomFrame.RectTransform, anchor: Anchor.TopRight), text: TextManager.Get("applysettingsbutton"))
|
||||
{
|
||||
OnClicked = ApplyTalentSelection,
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 0.3f), talentBottomFrame.RectTransform, anchor: Anchor.TopLeft), text: TextManager.Get("reset"))
|
||||
{
|
||||
OnClicked = ResetTalentSelection,
|
||||
};
|
||||
|
||||
UpdateTalentButtons();
|
||||
}
|
||||
|
||||
private void UpdateTalentButtons()
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
|
||||
talentPointsText.Text = $"{TextManager.Get("talentpointsleft")}{controlledCharacter.Info.GetAvailableTalentPoints()}";
|
||||
experienceText.Text = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
|
||||
experienceBar.BarSize = controlledCharacter.Info.GetProgressTowardsNextLevel();
|
||||
//experienceBar.ToolTip = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
|
||||
|
||||
selectedTalents = TalentTree.CheckTalentSelection(controlledCharacter, selectedTalents);
|
||||
|
||||
foreach (var talentButton in talentButtons)
|
||||
{
|
||||
talentButton.background.Color = unselectableColor;
|
||||
}
|
||||
|
||||
foreach (var talentButton in talentButtons)
|
||||
{
|
||||
string talentIdentifier = talentButton.button.UserData as string;
|
||||
bool unselectable = !TalentTree.IsViableTalentForCharacter(controlledCharacter, talentIdentifier, selectedTalents) || controlledCharacter.HasTalent(talentIdentifier);
|
||||
Color newTalentColor = unselectable ? unselectableColor : unselectedColor;
|
||||
|
||||
if (controlledCharacter.HasTalent(talentIdentifier))
|
||||
{
|
||||
newTalentColor = ownedColor;
|
||||
}
|
||||
else if (selectedTalents.Contains(talentIdentifier))
|
||||
{
|
||||
newTalentColor = selectedColor;
|
||||
}
|
||||
|
||||
talentButton.button.Color = newTalentColor;
|
||||
talentButton.button.SelectedColor = newTalentColor;
|
||||
talentButton.button.HoverColor = newTalentColor;
|
||||
talentButton.button.DisabledColor = newTalentColor;
|
||||
|
||||
talentButton.icon.Color = newTalentColor;
|
||||
|
||||
// update background color as well, if not defined yet
|
||||
if (talentButton.background.Color == unselectableColor)
|
||||
{
|
||||
talentButton.background.Color = newTalentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ApplyTalents(Character controlledCharacter)
|
||||
{
|
||||
selectedTalents = TalentTree.CheckTalentSelection(controlledCharacter, selectedTalents);
|
||||
foreach (string talent in selectedTalents)
|
||||
{
|
||||
controlledCharacter.GiveTalent(talent);
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
GameMain.Client.CreateEntityEvent(controlledCharacter, new object[] { NetEntityEvent.Type.UpdateTalents });
|
||||
}
|
||||
}
|
||||
UpdateTalentButtons();
|
||||
}
|
||||
|
||||
private bool ApplyTalentSelection(GUIButton guiButton, object userData)
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
ApplyTalents(controlledCharacter);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ResetTalentSelection(GUIButton guiButton, object userData)
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
selectedTalents = controlledCharacter.Info.UnlockedTalents.ToList();
|
||||
UpdateTalentButtons();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnExperienceChanged(Character character)
|
||||
{
|
||||
if (character != Character.Controlled) { return; }
|
||||
UpdateTalentButtons();
|
||||
}
|
||||
|
||||
private readonly StatTypes[] basicStats = new StatTypes[]
|
||||
{
|
||||
StatTypes.MaximumHealthMultiplier,
|
||||
StatTypes.MovementSpeed,
|
||||
StatTypes.SwimmingSpeed,
|
||||
StatTypes.RepairSpeed,
|
||||
};
|
||||
|
||||
private readonly StatTypes[] combatStats = new StatTypes[]
|
||||
{
|
||||
StatTypes.MaximumHealthMultiplier,
|
||||
StatTypes.MovementSpeed,
|
||||
StatTypes.SwimmingSpeed,
|
||||
StatTypes.RepairSpeed,
|
||||
};
|
||||
|
||||
private readonly StatTypes[] miscStats = new StatTypes[]
|
||||
{
|
||||
StatTypes.ReputationGainMultiplier,
|
||||
StatTypes.MissionMoneyGainMultiplier,
|
||||
StatTypes.ExperienceGainMultiplier,
|
||||
StatTypes.MissionExperienceGainMultiplier,
|
||||
};
|
||||
|
||||
private void CreateCharacterSheet(GUILayoutGroup characterInfoColumn)
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
|
||||
CreateRow(basicStats);
|
||||
CreateRow(combatStats);
|
||||
CreateRow(miscStats);
|
||||
|
||||
void CreateRow(StatTypes[] statTypes)
|
||||
{
|
||||
GUILayoutGroup characterInfoRow = new GUILayoutGroup(new RectTransform(new Vector2(0.33f, 1.0f), characterInfoColumn.RectTransform, anchor: Anchor.TopLeft), childAnchor: Anchor.TopCenter);
|
||||
foreach (StatTypes statType in statTypes)
|
||||
{
|
||||
ShowStat(statType, characterInfoRow);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowStat(StatTypes statType, GUILayoutGroup characterInfoRow)
|
||||
{
|
||||
GUIFrame textInfoFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.33f), characterInfoRow.RectTransform, Anchor.TopCenter), style: null);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1f, 1f), textInfoFrame.RectTransform, Anchor.TopLeft), statType.ToString(), font: GUI.SmallFont, textAlignment: Alignment.TopLeft);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1f, 1f), textInfoFrame.RectTransform, Anchor.TopLeft), (int)(100f * (1 + controlledCharacter.GetStatValue(statType))) + "%", font: GUI.Font, textAlignment: Alignment.TopRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +115,9 @@ namespace Barotrauma
|
||||
return MathHelper.Clamp(Math.Min(Math.Min(scale.X, scale.Y), GUI.SlicedSpriteScale), minBorderScale, maxBorderScale);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Rectangle rect, Color color, SpriteEffects spriteEffects = SpriteEffects.None)
|
||||
public void Draw(SpriteBatch spriteBatch, Rectangle rect, Color color, SpriteEffects spriteEffects = SpriteEffects.None, Vector2? uvOffset = null)
|
||||
{
|
||||
uvOffset ??= Vector2.Zero;
|
||||
if (Sprite.Texture == null)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, rect, Color.Magenta);
|
||||
@@ -157,7 +158,7 @@ namespace Barotrauma
|
||||
else if (Tile)
|
||||
{
|
||||
Vector2 startPos = new Vector2(rect.X, rect.Y);
|
||||
Sprite.DrawTiled(spriteBatch, startPos, new Vector2(rect.Width, rect.Height), color);
|
||||
Sprite.DrawTiled(spriteBatch, startPos, new Vector2(rect.Width, rect.Height), color, startOffset: uvOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace Barotrauma
|
||||
public static SteamWorkshopScreen SteamWorkshopScreen;
|
||||
|
||||
public static SubEditorScreen SubEditorScreen;
|
||||
public static TestScreen TestScreen;
|
||||
public static ParticleEditorScreen ParticleEditorScreen;
|
||||
public static LevelEditorScreen LevelEditorScreen;
|
||||
public static SpriteEditorScreen SpriteEditorScreen;
|
||||
@@ -89,7 +90,16 @@ namespace Barotrauma
|
||||
public static ParticleManager ParticleManager;
|
||||
public static DecalManager DecalManager;
|
||||
|
||||
public static World World;
|
||||
private static World world;
|
||||
public static World World
|
||||
{
|
||||
get
|
||||
{
|
||||
if (world == null) { world = new World(new Vector2(0, -9.82f)); }
|
||||
return world;
|
||||
}
|
||||
set { world = value; }
|
||||
}
|
||||
|
||||
public static LoadingScreen TitleScreen;
|
||||
private bool loadingScreenOpen;
|
||||
@@ -239,7 +249,6 @@ namespace Barotrauma
|
||||
GameMain.ResetFrameTime();
|
||||
fixedTime = new GameTime();
|
||||
|
||||
World = new World(new Vector2(0, -9.82f));
|
||||
FarseerPhysics.Settings.AllowSleep = true;
|
||||
FarseerPhysics.Settings.ContinuousPhysics = false;
|
||||
FarseerPhysics.Settings.VelocityIterations = 1;
|
||||
@@ -567,6 +576,8 @@ namespace Barotrauma
|
||||
ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
|
||||
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
|
||||
SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings));
|
||||
TalentPrefab.LoadAll(GetFilesOfType(ContentType.Talents));
|
||||
TalentTree.LoadAll(GetFilesOfType(ContentType.TalentTrees));
|
||||
Order.Init();
|
||||
EventManagerSettings.Init();
|
||||
BallastFloraPrefab.LoadAll(GetFilesOfType(ContentType.MapCreature));
|
||||
@@ -620,6 +631,7 @@ namespace Barotrauma
|
||||
#endif
|
||||
|
||||
SubEditorScreen = new SubEditorScreen();
|
||||
TestScreen = new TestScreen();
|
||||
|
||||
TitleScreen.LoadState = 75.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
@@ -792,12 +804,16 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (Config.AutomaticQuickStartEnabled || Config.AutomaticCampaignLoadEnabled) && FirstLoad && !PlayerInput.KeyDown(Keys.LeftShift))
|
||||
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen && (Config.AutomaticQuickStartEnabled || Config.AutomaticCampaignLoadEnabled || Config.TestScreenEnabled) && FirstLoad && !PlayerInput.KeyDown(Keys.LeftShift))
|
||||
{
|
||||
loadingScreenOpen = false;
|
||||
FirstLoad = false;
|
||||
|
||||
if (Config.AutomaticQuickStartEnabled)
|
||||
if (Config.TestScreenEnabled)
|
||||
{
|
||||
TestScreen.Select();
|
||||
}
|
||||
else if (Config.AutomaticQuickStartEnabled)
|
||||
{
|
||||
MainMenuScreen.QuickStart();
|
||||
}
|
||||
|
||||
@@ -48,11 +48,7 @@ namespace Barotrauma
|
||||
var equipmentSlots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.InnerClothes, InvSlotType.OuterClothes, InvSlotType.Headset, InvSlotType.Card };
|
||||
return character.Inventory.FindAllItems(item =>
|
||||
{
|
||||
if (item.SpawnedInOutpost) { return false; }
|
||||
if (!item.Prefab.AllowSellingWhenBroken && item.ConditionPercentage < 90.0f) { return false; }
|
||||
if (confirmedSoldEntities.Any(it => it.Item == item)) { return false; }
|
||||
// There must be no contained items or the contained items must be confirmed as sold
|
||||
if (!item.ContainedItems.All(it => confirmedSoldEntities.Any(se => se.Item == it))) { return false; }
|
||||
if (!IsItemSellable(item, confirmedSoldEntities)) { return false; }
|
||||
// Item must be in a non-equipment slot if possible
|
||||
if (!item.AllowedSlots.All(s => equipmentSlots.Contains(s)) && IsInEquipmentSlot(item)) { return false; }
|
||||
// Item must not be contained inside an item in an equipment slot
|
||||
@@ -76,15 +72,10 @@ namespace Barotrauma
|
||||
var confirmedSoldEntities = GetConfirmedSoldEntities();
|
||||
return Submarine.MainSub.GetItems(true).FindAll(item =>
|
||||
{
|
||||
if (!item.Prefab.CanBeSold) { return false; }
|
||||
if (item.SpawnedInOutpost) { return false; }
|
||||
if (!item.Prefab.AllowSellingWhenBroken && item.ConditionPercentage < 90.0f) { return false; }
|
||||
if (!IsItemSellable(item, confirmedSoldEntities)) { return false; }
|
||||
if (!item.Components.All(c => !(c is Holdable h) || !h.Attachable || !h.Attached)) { return false; }
|
||||
if (!item.Components.All(c => !(c is Wire w) || w.Connections.All(c => c == null))) { return false; }
|
||||
if (!ItemAndAllContainersInteractable(item)) { return false; }
|
||||
if (confirmedSoldEntities.Any(it => it.Item == item)) { return false; }
|
||||
// There must be no contained items or the contained items must be confirmed as sold
|
||||
if (!item.ContainedItems.All(it => confirmedSoldEntities.Any(se => se.Item == it))) { return false; }
|
||||
return true;
|
||||
}).Distinct();
|
||||
|
||||
@@ -107,6 +98,24 @@ namespace Barotrauma
|
||||
return SoldEntities.Where(se => se.Status != SoldEntity.SellStatus.Unconfirmed);
|
||||
}
|
||||
|
||||
private bool IsItemSellable(Item item, IEnumerable<SoldEntity> confirmedSoldEntities)
|
||||
{
|
||||
if (!item.Prefab.CanBeSold) { return false; }
|
||||
if (item.SpawnedInOutpost) { return false; }
|
||||
if (!item.Prefab.AllowSellingWhenBroken && item.ConditionPercentage < 90.0f) { return false; }
|
||||
if (confirmedSoldEntities.Any(it => it.Item == item)) { return false; }
|
||||
if (item.OwnInventory?.Container is ItemContainer itemContainer)
|
||||
{
|
||||
var containedItems = item.ContainedItems;
|
||||
if (containedItems.None()) { return true; }
|
||||
// Allow selling the item if contained items are unsellable and set to be removed on deconstruct
|
||||
if (itemContainer.RemoveContainedItemsOnDeconstruct && containedItems.All(it => !it.Prefab.CanBeSold)) { return true; }
|
||||
// Otherwise there must be no contained items or the contained items must be confirmed as sold
|
||||
if (!containedItems.All(it => confirmedSoldEntities.Any(se => se.Item == it))) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetItemsInBuyCrate(List<PurchasedItem> items)
|
||||
{
|
||||
ItemsInBuyCrate.Clear();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -761,7 +761,7 @@ namespace Barotrauma
|
||||
Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase));
|
||||
if (faction?.Reputation != null)
|
||||
{
|
||||
faction.Reputation.Value = rep;
|
||||
faction.Reputation.SetReputation(rep);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -771,7 +771,7 @@ namespace Barotrauma
|
||||
|
||||
if (reputation.HasValue)
|
||||
{
|
||||
campaign.Map.CurrentLocation.Reputation.Value = reputation.Value;
|
||||
campaign.Map.CurrentLocation.Reputation.SetReputation(reputation.Value);
|
||||
campaign?.CampaignUI?.UpgradeStore?.RefreshAll();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Barotrauma
|
||||
if (GameMain.NetLobbyScreen.HeadSelectionList != null) { GameMain.NetLobbyScreen.HeadSelectionList.Visible = false; }
|
||||
if (GameMain.NetLobbyScreen.JobSelectionFrame != null) { GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false; }
|
||||
}
|
||||
if (tabMenu == null && GameMode is TutorialMode == false)
|
||||
if (tabMenu == null && !(GameMode is TutorialMode) && !ConversationAction.IsDialogOpen)
|
||||
{
|
||||
tabMenu = new TabMenu();
|
||||
HintManager.OnShowTabMenu();
|
||||
@@ -34,7 +34,6 @@ namespace Barotrauma
|
||||
tabMenu = null;
|
||||
NetLobbyScreen.JobInfoFrame = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -44,7 +43,7 @@ namespace Barotrauma
|
||||
private GUIComponent respawnInfoFrame, respawnButtonContainer;
|
||||
private GUITextBlock respawnInfoText;
|
||||
private GUITickBox respawnTickBox;
|
||||
private GUILayoutGroup TopLeftButtonGroup;
|
||||
|
||||
private void CreateTopLeftButtons()
|
||||
{
|
||||
if (topLeftButtonGroup != null)
|
||||
|
||||
@@ -1518,6 +1518,12 @@ namespace Barotrauma
|
||||
"Automatic quickstart enabled",
|
||||
"Will the game automatically move on to Quickstart when the game is launched");
|
||||
|
||||
addDebugTickBox(
|
||||
TestScreenEnabled,
|
||||
(b) => TestScreenEnabled = b,
|
||||
"Test screen enabled",
|
||||
"Will the game automatically move on to a test screen when the game is launched");
|
||||
|
||||
addDebugTickBox(
|
||||
AutomaticCampaignLoadEnabled,
|
||||
(b) => AutomaticCampaignLoadEnabled = b,
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace Barotrauma
|
||||
|
||||
public override void CreateSlots()
|
||||
{
|
||||
if (visualSlots == null) { visualSlots = new VisualSlot[capacity]; }
|
||||
visualSlots ??= new VisualSlot[capacity];
|
||||
|
||||
float multiplier = !GUI.IsFourByThree() ? UIScale : UIScale * 0.925f;
|
||||
|
||||
@@ -359,7 +359,8 @@ namespace Barotrauma
|
||||
int personalSlotX = HUDLayoutSettings.InventoryAreaLower.Right - SlotSize.X - Spacing;
|
||||
for (int i = 0; i < visualSlots.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (HideSlot(i)) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
//upperX -= slotSize.X + spacing;
|
||||
@@ -371,10 +372,18 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
int lowerX = x;
|
||||
int handSlotX = x;
|
||||
int personalSlotY = GameMain.GraphicsHeight - bottomOffset * 2 - Spacing * 2 - (int)(!GUI.IsFourByThree() ? UnequippedIndicator.size.Y * UIScale * IndicatorScaleAdjustment : UnequippedIndicator.size.Y * UIScale * IndicatorScaleAdjustment * 2f);
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand)
|
||||
{
|
||||
SlotPositions[i] = new Vector2(handSlotX, personalSlotY);
|
||||
handSlotX += visualSlots[i].Rect.Width + Spacing;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HideSlot(i)) { continue; }
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
|
||||
@@ -390,7 +399,8 @@ namespace Barotrauma
|
||||
x = lowerX;
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (!HideSlot(i)) continue;
|
||||
if (!HideSlot(i)) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
|
||||
x -= visualSlots[i].Rect.Width + Spacing;
|
||||
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
|
||||
}
|
||||
@@ -404,7 +414,8 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (HideSlot(i)) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
|
||||
if (PersonalSlots.HasFlag(SlotTypes[i]))
|
||||
{
|
||||
SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
|
||||
@@ -416,9 +427,16 @@ namespace Barotrauma
|
||||
x += visualSlots[i].Rect.Width + Spacing;
|
||||
}
|
||||
}
|
||||
int handSlotX = x - visualSlots[0].Rect.Width - Spacing;
|
||||
for (int i = 0; i < SlotPositions.Length; i++)
|
||||
{
|
||||
if (!HideSlot(i)) continue;
|
||||
if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand)
|
||||
{
|
||||
bool rightSlot = SlotTypes[i] == InvSlotType.RightHand;
|
||||
SlotPositions[i] = new Vector2(rightSlot ? handSlotX : handSlotX - visualSlots[0].Rect.Width - Spacing, personalSlotY);
|
||||
continue;
|
||||
}
|
||||
if (!HideSlot(i)) { continue; }
|
||||
SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
|
||||
x += visualSlots[i].Rect.Width + Spacing;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Sounds;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -18,7 +19,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
protected float currentCrossHairScale, currentCrossHairPointerScale;
|
||||
|
||||
private RoundSound chargeSound;
|
||||
private SoundChannel chargeSoundChannel;
|
||||
|
||||
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
private readonly List<ParticleEmitter> particleEmitterCharges = new List<ParticleEmitter>();
|
||||
|
||||
[Serialize(1.0f, false, description: "The scale of the crosshair sprite (if there is one).")]
|
||||
public float CrossHairScale
|
||||
@@ -48,6 +53,12 @@ namespace Barotrauma.Items.Components
|
||||
case "particleemitter":
|
||||
particleEmitters.Add(new ParticleEmitter(subElement));
|
||||
break;
|
||||
case "particleemittercharge":
|
||||
particleEmitterCharges.Add(new ParticleEmitter(subElement));
|
||||
break;
|
||||
case "chargesound":
|
||||
chargeSound = Submarine.LoadRoundSound(subElement, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,6 +95,51 @@ namespace Barotrauma.Items.Components
|
||||
crosshairPointerPos = PlayerInput.MousePosition;
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
float chargeRatio = currentChargeTime / MaxChargeTime;
|
||||
|
||||
switch (currentChargingState)
|
||||
{
|
||||
case ChargingState.WindingUp:
|
||||
case ChargingState.WindingDown:
|
||||
Vector2 particlePos = item.WorldPosition + ConvertUnits.ToDisplayUnits(TransformedBarrelPos);
|
||||
float sizeMultiplier = Math.Clamp(chargeRatio, 0.1f, 1f);
|
||||
foreach (ParticleEmitter emitter in particleEmitterCharges)
|
||||
{
|
||||
emitter.Emit(deltaTime, particlePos, hullGuess: null, sizeMultiplier: sizeMultiplier, colorMultiplier: emitter.Prefab.Properties.ColorMultiplier);
|
||||
}
|
||||
|
||||
if (chargeSoundChannel == null || !chargeSoundChannel.IsPlaying)
|
||||
{
|
||||
if (chargeSound != null)
|
||||
{
|
||||
chargeSoundChannel = SoundPlayer.PlaySound(chargeSound.Sound, item.WorldPosition, chargeSound.Volume, chargeSound.Range, ignoreMuffling: chargeSound.IgnoreMuffling);
|
||||
if (chargeSoundChannel != null) chargeSoundChannel.Looping = true;
|
||||
}
|
||||
}
|
||||
else if (chargeSoundChannel != null)
|
||||
{
|
||||
chargeSoundChannel.FrequencyMultiplier = MathHelper.Lerp(0.5f, 1.5f, chargeRatio);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (chargeSoundChannel != null)
|
||||
{
|
||||
if (chargeSoundChannel.IsPlaying)
|
||||
{
|
||||
chargeSoundChannel.FadeOutAndDispose();
|
||||
chargeSoundChannel.Looping = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
chargeSoundChannel = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
if (character == null || !character.IsKeyDown(InputType.Aim)) { return; }
|
||||
@@ -92,7 +148,7 @@ namespace Barotrauma.Items.Components
|
||||
if (character.ViewTarget != null && (character.ViewTarget is Item item) && item.Prefab.FocusOnSelected) { return; }
|
||||
|
||||
GUI.HideCursor = (crosshairSprite != null || crosshairPointerSprite != null) &&
|
||||
GUI.MouseOn == null && !Inventory.IsMouseOnInventory() && !GameMain.Instance.Paused;
|
||||
GUI.MouseOn == null && !Inventory.IsMouseOnInventory && !GameMain.Instance.Paused;
|
||||
if (GUI.HideCursor)
|
||||
{
|
||||
crosshairSprite?.Draw(spriteBatch, crosshairPos, Color.White, 0, currentCrossHairScale);
|
||||
|
||||
@@ -246,6 +246,7 @@ namespace Barotrauma.Items.Components
|
||||
public void PlaySound(ActionType type, Character user = null)
|
||||
{
|
||||
if (!hasSoundsOfType[(int)type]) { return; }
|
||||
if (GameMain.Client?.MidRoundSyncing ?? false) { return; }
|
||||
|
||||
if (loopingSound != null)
|
||||
{
|
||||
@@ -429,7 +430,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
foreach (ItemComponent component in item.Components)
|
||||
{
|
||||
if (component.name.ToLower() == LinkUIToComponent.ToLower())
|
||||
if (component.name.Equals(LinkUIToComponent, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
linkToUIComponent = component;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,8 @@ namespace Barotrauma.Items.Components
|
||||
private void DrawOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
|
||||
{
|
||||
overlayComponent.RectTransform.SetAsLastChild();
|
||||
var lastSlot = inputContainer.Inventory.visualSlots.Last();
|
||||
if (!(inputContainer?.Inventory?.visualSlots is { } visualSlots)) { return; }
|
||||
var lastSlot = visualSlots.Last();
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(
|
||||
|
||||
@@ -255,12 +255,15 @@ namespace Barotrauma.Items.Components
|
||||
var item1 = c1.GUIComponent.UserData as FabricationRecipe;
|
||||
var item2 = c2.GUIComponent.UserData as FabricationRecipe;
|
||||
|
||||
bool hasSkills1 = FabricationDegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f;
|
||||
bool hasSkills2 = FabricationDegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f;
|
||||
int itemPlacement1 = FabricationDegreeOfSuccess(character, item1.RequiredSkills) >= 0.5f ? 0 : -1;
|
||||
int itemPlacement2 = FabricationDegreeOfSuccess(character, item2.RequiredSkills) >= 0.5f ? 0 : -1;
|
||||
|
||||
if (hasSkills1 != hasSkills2)
|
||||
itemPlacement1 += item1.RequiresRecipe && !character.HasRecipeForItem(item1.TargetItem.Identifier) ? -2 : 0;
|
||||
itemPlacement2 += item2.RequiresRecipe && !character.HasRecipeForItem(item2.TargetItem.Identifier) ? -2 : 0;
|
||||
|
||||
if (itemPlacement1 != itemPlacement2)
|
||||
{
|
||||
return hasSkills1 ? -1 : 1;
|
||||
return itemPlacement1 > itemPlacement2 ? -1 : 1;
|
||||
}
|
||||
|
||||
return string.Compare(item1.DisplayName, item2.DisplayName);
|
||||
@@ -285,6 +288,18 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
insufficientSkillsText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstinSufficient.RectTransform));
|
||||
}
|
||||
|
||||
var requiresRecipeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
||||
TextManager.Get("fabricatorrequiresrecipe", returnNull: true) ?? "Requires recipe to fabricate", textColor: Color.Red, font: GUI.SubHeadingFont)
|
||||
{
|
||||
AutoScaleHorizontal = true,
|
||||
CanBeFocused = false
|
||||
};
|
||||
var firstRequiresRecipe = itemList.Content.Children.FirstOrDefault(c => c.UserData is FabricationRecipe fabricableItem && (fabricableItem.RequiresRecipe && !character.HasRecipeForItem(fabricableItem.TargetItem.Identifier)));
|
||||
if (firstRequiresRecipe != null)
|
||||
{
|
||||
requiresRecipeText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstRequiresRecipe.RectTransform));
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawInputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
|
||||
@@ -297,6 +312,7 @@ namespace Barotrauma.Items.Components
|
||||
int slotIndex = 0;
|
||||
|
||||
var missingItems = new List<FabricationRecipe.RequiredItem>();
|
||||
|
||||
foreach (FabricationRecipe.RequiredItem requiredItem in targetItem.RequiredItems)
|
||||
{
|
||||
for (int i = 0; i < requiredItem.Amount; i++)
|
||||
@@ -308,6 +324,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
missingItems.Remove(missingItems.FirstOrDefault(mi => mi.ItemPrefabs.Contains(item.prefab)));
|
||||
}
|
||||
var missingCounts = missingItems.GroupBy(missingItem => missingItem).ToDictionary(x => x.Key, x => x.Count());
|
||||
missingItems = missingItems.Distinct().ToList();
|
||||
|
||||
var availableIngredients = GetAvailableIngredients();
|
||||
|
||||
@@ -318,30 +336,30 @@ namespace Barotrauma.Items.Components
|
||||
slotIndex++;
|
||||
}
|
||||
|
||||
//highlight suitable ingredients in linked inventories
|
||||
foreach (Item item in availableIngredients)
|
||||
{
|
||||
if (item.ParentInventory != inputContainer.Inventory && IsItemValidIngredient(item, requiredItem))
|
||||
{
|
||||
int availableSlotIndex = item.ParentInventory.FindIndex(item);
|
||||
//slots are null if the inventory has never been displayed
|
||||
//(linked item, but the UI is not set to be displayed at the same time)
|
||||
if (item.ParentInventory.visualSlots != null)
|
||||
{
|
||||
if (item.ParentInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
|
||||
{
|
||||
item.ParentInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
if (slotIndex < inputContainer.Capacity)
|
||||
requiredItem.ItemPrefabs
|
||||
.Where(requiredPrefab => availableIngredients.ContainsKey(requiredPrefab.Identifier))
|
||||
.ForEach(requiredPrefab => {
|
||||
var availablePrefabs = availableIngredients[requiredPrefab.Identifier];
|
||||
|
||||
availablePrefabs
|
||||
.Where(availablePrefab => availablePrefab.ParentInventory != inputContainer.Inventory)
|
||||
.Where(availablePrefab => availablePrefab.ParentInventory.visualSlots != null) //slots are null if the inventory has never been displayed
|
||||
.ForEach(availablePrefab => { //(linked item, but the UI is not set to be displayed at the same time)
|
||||
int availableSlotIndex = availablePrefab.ParentInventory.FindIndex(availablePrefab);
|
||||
|
||||
if (availablePrefab.ParentInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
|
||||
{
|
||||
inputContainer.Inventory.visualSlots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
availablePrefab.ParentInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
if (slotIndex < inputContainer.Capacity)
|
||||
{
|
||||
inputContainer.Inventory.visualSlots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (slotIndex >= inputContainer.Capacity) { break; }
|
||||
|
||||
|
||||
var itemIcon = requiredItem.ItemPrefabs.First().InventoryIcon ?? requiredItem.ItemPrefabs.First().sprite;
|
||||
Rectangle slotRect = inputContainer.Inventory.visualSlots[slotIndex].Rect;
|
||||
itemIcon.Draw(
|
||||
@@ -350,6 +368,16 @@ namespace Barotrauma.Items.Components
|
||||
color: requiredItem.ItemPrefabs.First().InventoryIconColor * 0.3f,
|
||||
scale: Math.Min(slotRect.Width / itemIcon.size.X, slotRect.Height / itemIcon.size.Y));
|
||||
|
||||
|
||||
if (missingCounts[requiredItem] > 1)
|
||||
{
|
||||
Vector2 stackCountPos = new Vector2(slotRect.Right, slotRect.Bottom);
|
||||
string stackCountText = "x" + missingCounts[requiredItem];
|
||||
stackCountPos -= GUI.SmallFont.MeasureString(stackCountText) + new Vector2(4, 2);
|
||||
GUI.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos + Vector2.One, Color.Black);
|
||||
GUI.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos, Color.White);
|
||||
}
|
||||
|
||||
if (requiredItem.UseCondition && requiredItem.MinCondition < 1.0f)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(slotRect.X, slotRect.Bottom - 8, slotRect.Width, 8), Color.Black * 0.8f, true);
|
||||
@@ -601,7 +629,7 @@ namespace Barotrauma.Items.Components
|
||||
var itemPrefab = child.UserData as FabricationRecipe;
|
||||
if (itemPrefab == null) continue;
|
||||
|
||||
bool canBeFabricated = CanBeFabricated(itemPrefab, availableIngredients);
|
||||
bool canBeFabricated = CanBeFabricated(itemPrefab, availableIngredients, character);
|
||||
if (itemPrefab == selectedItem)
|
||||
{
|
||||
activateButton.Enabled = canBeFabricated;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -142,6 +142,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
float rotationRad = MathHelper.ToRadians(item.Rotation);
|
||||
if (FlowPercentage < 0.0f)
|
||||
{
|
||||
foreach (var (position, emitter) in pumpOutEmitters)
|
||||
@@ -149,12 +150,13 @@ namespace Barotrauma.Items.Components
|
||||
if (item.CurrentHull != null && item.CurrentHull.Surface < item.Rect.Location.Y + position.Y) { continue; }
|
||||
|
||||
//only emit "pump out" particles when underwater
|
||||
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
|
||||
float angle = 0.0f;
|
||||
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
|
||||
relativeParticlePos = MathUtils.RotatePoint(relativeParticlePos, item.FlippedX ? rotationRad : -rotationRad);
|
||||
float angle = -rotationRad;
|
||||
if (item.FlippedX)
|
||||
{
|
||||
relativeParticlePos.X = -relativeParticlePos.X;
|
||||
angle = MathHelper.Pi;
|
||||
angle += MathHelper.Pi;
|
||||
}
|
||||
if (item.FlippedY)
|
||||
{
|
||||
@@ -170,11 +172,12 @@ namespace Barotrauma.Items.Components
|
||||
foreach (var (position, emitter) in pumpInEmitters)
|
||||
{
|
||||
Vector2 relativeParticlePos = (item.WorldRect.Location.ToVector2() + position * item.Scale) - item.WorldPosition;
|
||||
float angle = 0.0f;
|
||||
relativeParticlePos = MathUtils.RotatePoint(relativeParticlePos, item.FlippedX ? rotationRad : -rotationRad);
|
||||
float angle = -rotationRad;
|
||||
if (item.FlippedX)
|
||||
{
|
||||
relativeParticlePos.X = -relativeParticlePos.X;
|
||||
angle = MathHelper.Pi;
|
||||
angle += MathHelper.Pi;
|
||||
}
|
||||
if (item.FlippedY)
|
||||
{
|
||||
|
||||
@@ -888,6 +888,7 @@ namespace Barotrauma.Items.Components
|
||||
maintainPosOriginIndicator?.Remove();
|
||||
steeringIndicator?.Remove();
|
||||
enterOutpostPrompt?.Close();
|
||||
pathFinder = null;
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Barotrauma.Items.Components
|
||||
var chargeText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1), textArea.RectTransform, Anchor.CenterRight),
|
||||
"", textColor: GUI.Style.TextColor, font: GUI.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
TextGetter = () => $"{(int)charge}/{(int)capacity} {kWmin} ({((int)MathUtils.Percentage(charge, capacity)).ToString()} %)"
|
||||
TextGetter = () => $"{(int)Math.Round(charge)}/{(int)capacity} {kWmin} ({(int)Math.Round(MathUtils.Percentage(charge, capacity))} %)"
|
||||
};
|
||||
if (chargeText.TextSize.X > chargeText.Rect.Width) { chargeText.Font = GUI.SmallFont; }
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public GUIButton SabotageButton { get; private set; }
|
||||
|
||||
public GUIButton TinkerButton { get; private set; }
|
||||
|
||||
private GUIProgressBar progressBar;
|
||||
|
||||
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
@@ -25,6 +27,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private string repairButtonText, repairingText;
|
||||
private string sabotageButtonText, sabotagingText;
|
||||
private string tinkerButtonText, tinkeringText;
|
||||
|
||||
private FixActions requestStartFixAction;
|
||||
|
||||
@@ -46,7 +49,7 @@ namespace Barotrauma.Items.Components
|
||||
public override bool ShouldDrawHUD(Character character)
|
||||
{
|
||||
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) return false;
|
||||
return item.ConditionPercentage < RepairThreshold || character.IsTraitor && item.ConditionPercentage > MinSabotageCondition || (CurrentFixer == character && (!item.IsFullCondition || (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition)));
|
||||
return item.ConditionPercentage < RepairThreshold || character.IsTraitor && item.ConditionPercentage > MinSabotageCondition || (CurrentFixer == character && (!item.IsFullCondition || (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition))) || CanTinker(character);
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
@@ -148,6 +151,20 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
tinkerButtonText = "Tinker";
|
||||
tinkeringText = "Tinkering";
|
||||
TinkerButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), tinkerButtonText, style: "GUIButtonSmall")
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
Visible = false,
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
requestStartFixAction = FixActions.Tinker;
|
||||
item.CreateClientEvent(this);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
@@ -176,6 +193,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
case FixActions.Repair:
|
||||
case FixActions.Sabotage:
|
||||
case FixActions.Tinker:
|
||||
StartRepairing(Character.Controlled, requestStartFixAction);
|
||||
requestStartFixAction = FixActions.None;
|
||||
break;
|
||||
@@ -226,6 +244,13 @@ namespace Barotrauma.Items.Components
|
||||
sabotageButtonText :
|
||||
sabotagingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
||||
|
||||
TinkerButton.Visible = CanTinker(character);
|
||||
TinkerButton.IgnoreLayoutGroups = !TinkerButton.Visible;
|
||||
TinkerButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Tinker)) && CanTinker(character);
|
||||
TinkerButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Tinker && CanTinker(character)) ?
|
||||
tinkerButtonText :
|
||||
tinkeringText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
||||
|
||||
System.Diagnostics.Debug.Assert(GuiFrame.GetChild(0) is GUILayoutGroup, "Repair UI hierarchy has changed, could not find skill texts");
|
||||
foreach (GUIComponent c in GuiFrame.GetChild(0).Children)
|
||||
{
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace Barotrauma.Items.Components
|
||||
GUITextBlock newBlock = new GUITextBlock(
|
||||
new RectTransform(new Vector2(1, 0), historyBox.Content.RectTransform, anchor: Anchor.TopCenter),
|
||||
"> " + input,
|
||||
textColor: Color.LimeGreen, wrap: true)
|
||||
textColor: Color.LimeGreen, wrap: true, font: UseMonospaceFont ? GUI.MonospacedFont : GUI.GlobalFont)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
@@ -534,20 +534,20 @@ namespace Barotrauma.Items.Components
|
||||
minRotationWidget.Draw(spriteBatch, (float)Timing.Step);
|
||||
maxRotationWidget.Draw(spriteBatch, (float)Timing.Step);
|
||||
|
||||
Vector2 GetDrawPos()
|
||||
{
|
||||
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
|
||||
if (item.Submarine != null) { drawPos += item.Submarine.DrawPosition; }
|
||||
drawPos.Y = -drawPos.Y;
|
||||
return drawPos;
|
||||
}
|
||||
|
||||
void UpdateBarrel()
|
||||
{
|
||||
rotation = (minRotation + maxRotation) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 GetDrawPos()
|
||||
{
|
||||
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
|
||||
if (item.Submarine != null) { drawPos += item.Submarine.DrawPosition; }
|
||||
drawPos.Y = -drawPos.Y;
|
||||
return drawPos;
|
||||
}
|
||||
|
||||
private Widget GetWidget(string id, SpriteBatch spriteBatch, int size = 5, float thickness = 1f, Action<Widget> initMethod = null)
|
||||
{
|
||||
Vector2 offset = new Vector2(size / 2 + 5, -10);
|
||||
|
||||
@@ -478,7 +478,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
if (container == null) { return false; }
|
||||
return owner.SelectedCharacter != null|| (!(owner is Character character)) || !container.KeepOpenWhenEquippedBy(character) || !owner.HasEquippedItem(container.Item);
|
||||
return owner.SelectedCharacter != null|| (!(owner is Character character)) || !container.KeepOpenWhenEquippedBy(character) || !owner.HasEquippedItem(container.Item);
|
||||
}
|
||||
|
||||
protected virtual bool HideSlot(int i)
|
||||
@@ -667,6 +667,10 @@ namespace Barotrauma
|
||||
if (subInventory.visualSlots == null) { subInventory.CreateSlots(); }
|
||||
|
||||
canMove = container.MovableFrame && !subInventory.IsInventoryHoverAvailable(Owner as Character, container) && subInventory.originalPos != Point.Zero;
|
||||
if (this is CharacterInventory characterInventory && characterInventory.CurrentLayout != CharacterInventory.Layout.Default)
|
||||
{
|
||||
canMove = false;
|
||||
}
|
||||
|
||||
if (canMove)
|
||||
{
|
||||
@@ -826,11 +830,23 @@ namespace Barotrauma
|
||||
return rect.Contains(PlayerInput.MousePosition);
|
||||
}
|
||||
|
||||
public static bool IsMouseOnInventory
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh the value of IsMouseOnInventory
|
||||
/// </summary>
|
||||
public static void RefreshMouseOnInventory()
|
||||
{
|
||||
IsMouseOnInventory = DetermineMouseOnInventory();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the mouse on any inventory element (slot, equip button, subinventory...)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool IsMouseOnInventory(bool ignoreDraggedItem = false)
|
||||
private static bool DetermineMouseOnInventory(bool ignoreDraggedItem = false)
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign != null &&
|
||||
(GameMain.GameSession.Campaign.ShowCampaignUI || GameMain.GameSession.Campaign.ForceMapUI))
|
||||
@@ -1112,7 +1128,7 @@ namespace Barotrauma
|
||||
{
|
||||
Character.Controlled.ClearInputs();
|
||||
|
||||
if (!IsMouseOnInventory(ignoreDraggedItem: true) &&
|
||||
if (!DetermineMouseOnInventory(ignoreDraggedItem: true) &&
|
||||
CharacterHealth.OpenHealthWindow != null)
|
||||
{
|
||||
bool dropSuccessful = false;
|
||||
@@ -1306,7 +1322,9 @@ namespace Barotrauma
|
||||
protected static Rectangle GetSubInventoryHoverArea(SlotReference subSlot)
|
||||
{
|
||||
Rectangle hoverArea;
|
||||
if (!subSlot.Inventory.Movable() || Character.Controlled?.Inventory == subSlot.ParentInventory && !Character.Controlled.HasEquippedItem(subSlot.Item))
|
||||
if (!subSlot.Inventory.Movable() ||
|
||||
(Character.Controlled?.Inventory == subSlot.ParentInventory && !Character.Controlled.HasEquippedItem(subSlot.Item)) ||
|
||||
(subSlot.ParentInventory is CharacterInventory characterInventory && characterInventory.CurrentLayout != CharacterInventory.Layout.Default))
|
||||
{
|
||||
hoverArea = subSlot.Slot.Rect;
|
||||
hoverArea.Location += subSlot.Slot.DrawOffset.ToPoint();
|
||||
|
||||
@@ -332,7 +332,7 @@ namespace Barotrauma
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, flippedX && Prefab.CanSpriteFlipX ? rotationRad : -rotationRad) * Scale;
|
||||
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
||||
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
||||
decorativeSprite.Sprite.DrawTiled(spriteBatch,
|
||||
@@ -368,7 +368,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
float rot = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, flippedX && Prefab.CanSpriteFlipX ? rotationRad : -rotationRad) * Scale;
|
||||
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
||||
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
|
||||
@@ -1623,6 +1623,10 @@ namespace Barotrauma
|
||||
{
|
||||
wifiComponent.TeamID = (CharacterTeamType)teamID;
|
||||
}
|
||||
foreach (IdCard idCard in item.GetComponents<IdCard>())
|
||||
{
|
||||
idCard.TeamID = (CharacterTeamType)teamID;
|
||||
}
|
||||
if (descriptionChanged) { item.Description = itemDesc; }
|
||||
if (tagsChanged) { item.Tags = tags; }
|
||||
var nameTag = item.GetComponent<NameTag>();
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace Barotrauma
|
||||
{
|
||||
partial void ExplodeProjSpecific(Vector2 worldPosition, Hull hull)
|
||||
{
|
||||
if (GameMain.Client?.MidRoundSyncing ?? false) { return; }
|
||||
|
||||
if (shockwave)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle("shockwave", worldPosition,
|
||||
|
||||
@@ -676,7 +676,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
remoteBackgroundSections.Add(new BackgroundSection(new Rectangle(0, 0, 1, 1), i, colorStrength, color, 0));
|
||||
remoteBackgroundSections.Add(new BackgroundSection(new Rectangle(0, 0, 1, 1), (ushort)i, colorStrength, color, 0));
|
||||
}
|
||||
}
|
||||
paintAmount = BackgroundSections.Sum(s => s.ColorStrength);
|
||||
|
||||
@@ -238,13 +238,13 @@ namespace Barotrauma.Lights
|
||||
//draw a black rectangle on hulls to hide background lights behind subs
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
if (backgroundObstructor != null)
|
||||
/*if (backgroundObstructor != null)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
|
||||
spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
|
||||
(int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.Black);
|
||||
spriteBatch.End();
|
||||
}
|
||||
}*/
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
|
||||
Dictionary<Hull, Rectangle> visibleHulls = GetVisibleHulls(cam);
|
||||
@@ -258,7 +258,7 @@ namespace Barotrauma.Lights
|
||||
spriteBatch.End();
|
||||
|
||||
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidColor"];
|
||||
SolidColorEffect.Parameters["color"].SetValue(AmbientLight.ToVector4());
|
||||
SolidColorEffect.Parameters["color"].SetValue(AmbientLight.Opaque().ToVector4());
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform, effect: SolidColorEffect);
|
||||
Submarine.DrawDamageable(spriteBatch, null);
|
||||
spriteBatch.End();
|
||||
|
||||
@@ -7,6 +7,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
@@ -403,6 +404,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
// TODO remove
|
||||
[Obsolete("Use MiniMap.CreateMiniMap()")]
|
||||
public void CreateMiniMap(GUIComponent parent, IEnumerable<Entity> pointsOfInterest = null, bool ignoreOutpost = false)
|
||||
{
|
||||
Rectangle worldBorders = GetDockedBorders();
|
||||
@@ -417,24 +420,125 @@ namespace Barotrauma
|
||||
GUIFrame hullContainer = new GUIFrame(new RectTransform(
|
||||
(parentAspectRatio > aspectRatio ? new Vector2(aspectRatio / parentAspectRatio, 1.0f) : new Vector2(1.0f, parentAspectRatio / aspectRatio)) * scale,
|
||||
parent.RectTransform, Anchor.Center),
|
||||
style: null);
|
||||
style: null)
|
||||
{
|
||||
UserData = "hullcontainer"
|
||||
};
|
||||
|
||||
var connectedSubs = GetConnectedSubs();
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull.Submarine != this && !connectedSubs.Contains(hull.Submarine)) { continue; }
|
||||
if (ignoreOutpost && !IsEntityFoundOnThisSub(hull, true)) { continue; }
|
||||
|
||||
HashSet<Hull> hullList = Hull.hullList.Where(hull => hull.Submarine == this || connectedSubs.Contains(hull.Submarine)).Where(hull => !ignoreOutpost || IsEntityFoundOnThisSub(hull, true)).ToHashSet();
|
||||
|
||||
Dictionary<Hull, HashSet<Hull>> combinedHulls = new Dictionary<Hull, HashSet<Hull>>();
|
||||
|
||||
foreach (Hull hull in hullList)
|
||||
{
|
||||
if (combinedHulls.ContainsKey(hull) || combinedHulls.Values.Any(hh => hh.Contains(hull))) { continue; }
|
||||
|
||||
List<Hull> linkedHulls = new List<Hull>();
|
||||
MiniMap.GetLinkedHulls(hull, linkedHulls);
|
||||
|
||||
linkedHulls.Remove(hull);
|
||||
|
||||
foreach (Hull linkedHull in linkedHulls)
|
||||
{
|
||||
if (!combinedHulls.ContainsKey(hull))
|
||||
{
|
||||
combinedHulls.Add(hull, new HashSet<Hull>());
|
||||
}
|
||||
|
||||
combinedHulls[hull].Add(linkedHull);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Hull hull in hullList)
|
||||
{
|
||||
Vector2 relativeHullPos = new Vector2(
|
||||
(hull.WorldRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
(worldBorders.Y - hull.WorldRect.Y) / (float)worldBorders.Height);
|
||||
Vector2 relativeHullSize = new Vector2(hull.Rect.Width / (float)worldBorders.Width, hull.Rect.Height / (float)worldBorders.Height);
|
||||
|
||||
var hullFrame = new GUIFrame(new RectTransform(relativeHullSize, hullContainer.RectTransform) { RelativeOffset = relativeHullPos }, style: "MiniMapRoom", color: Color.DarkCyan * 0.8f)
|
||||
bool hideHull = combinedHulls.ContainsKey(hull) || combinedHulls.Values.Any(hh => hh.Contains(hull));
|
||||
|
||||
if (hideHull) { continue; }
|
||||
|
||||
Color color = Color.DarkCyan * 0.8f;
|
||||
|
||||
var hullFrame = new GUIFrame(new RectTransform(relativeHullSize, hullContainer.RectTransform) { RelativeOffset = relativeHullPos }, style: "MiniMapRoom", color: color)
|
||||
{
|
||||
UserData = hull
|
||||
};
|
||||
new GUIFrame(new RectTransform(Vector2.One, hullFrame.RectTransform), style: "ScanLines", color: Color.DarkCyan * 0.8f);
|
||||
|
||||
new GUIFrame(new RectTransform(Vector2.One, hullFrame.RectTransform), style: "ScanLines", color: color);
|
||||
}
|
||||
|
||||
foreach (var (mainHull, linkedHulls) in combinedHulls)
|
||||
{
|
||||
MiniMapHullData data = ConstructLinkedHulls(mainHull, linkedHulls, hullContainer, worldBorders);
|
||||
|
||||
Vector2 relativeHullPos = new Vector2(
|
||||
(data.Bounds.X - worldBorders.X) / worldBorders.Width,
|
||||
(worldBorders.Y - data.Bounds.Y) / worldBorders.Height);
|
||||
|
||||
Vector2 relativeHullSize = new Vector2(data.Bounds.Width / worldBorders.Width, data.Bounds.Height / worldBorders.Height);
|
||||
|
||||
Color color = Color.DarkCyan * 0.8f;
|
||||
|
||||
float highestY = 0f,
|
||||
highestX = 0f;
|
||||
|
||||
foreach (var (r, _) in data.RectDatas)
|
||||
{
|
||||
float y = r.Y - -r.Height,
|
||||
x = r.X;
|
||||
|
||||
if (y > highestY) { highestY = y; }
|
||||
if (x > highestX) { highestX = x; }
|
||||
}
|
||||
|
||||
HashSet<GUIFrame> frames = new HashSet<GUIFrame>();
|
||||
|
||||
foreach (var (snappredRect, hull) in data.RectDatas)
|
||||
{
|
||||
RectangleF rect = snappredRect;
|
||||
rect.Height = -rect.Height;
|
||||
rect.Y -= rect.Height;
|
||||
|
||||
var (parentW, parentH) = hullContainer.Rect.Size.ToVector2();
|
||||
Vector2 size = new Vector2(rect.Width / parentW, rect.Height / parentH);
|
||||
// TODO this won't be required if we some day switch RectTransform to use RectangleF
|
||||
const float padding = 0.001f;
|
||||
size.X += padding;
|
||||
size.Y += padding;
|
||||
Vector2 pos = new Vector2(rect.X / parentW, rect.Y / parentH);
|
||||
|
||||
GUIFrame hullFrame = new GUIFrame(new RectTransform(size, hullContainer.RectTransform) { RelativeOffset = pos }, style: "ScanLinesSeamless", color: color)
|
||||
{
|
||||
UserData = hull,
|
||||
UVOffset = new Vector2(highestX - rect.X, highestY - rect.Y)
|
||||
};
|
||||
|
||||
frames.Add(hullFrame);
|
||||
}
|
||||
|
||||
new GUICustomComponent(new RectTransform(relativeHullSize, hullContainer.RectTransform) { RelativeOffset = relativeHullPos }, (spriteBatch, component) =>
|
||||
{
|
||||
foreach (List<Vector2> list in data.Polygon)
|
||||
{
|
||||
spriteBatch.DrawPolygonInner(hullContainer.Rect.Location.ToVector2(), list, component.Color, 2f);
|
||||
}
|
||||
}, (deltaTime, component) =>
|
||||
{
|
||||
if (component.Parent.Rect.Size != data.ParentSize)
|
||||
{
|
||||
data = ConstructLinkedHulls(mainHull, linkedHulls, hullContainer, worldBorders);
|
||||
}
|
||||
})
|
||||
{
|
||||
UserData = frames,
|
||||
Color = color,
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
if (pointsOfInterest != null)
|
||||
@@ -453,6 +557,64 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static MiniMapHullData ConstructLinkedHulls(Hull mainHull, HashSet<Hull> linkedHulls, GUIComponent parent, Rectangle worldBorders)
|
||||
{
|
||||
Rectangle parentRect = parent.Rect;
|
||||
|
||||
Dictionary<Hull, Rectangle> rects = new Dictionary<Hull, Rectangle>();
|
||||
Rectangle worldRect = mainHull.WorldRect;
|
||||
worldRect.Y = -worldRect.Y;
|
||||
|
||||
rects.Add(mainHull, worldRect);
|
||||
|
||||
foreach (Hull hull in linkedHulls)
|
||||
{
|
||||
Rectangle rect = hull.WorldRect;
|
||||
rect.Y = -rect.Y;
|
||||
|
||||
worldRect = Rectangle.Union(worldRect, rect);
|
||||
rects.Add(hull, rect);
|
||||
}
|
||||
|
||||
worldRect.Y = -worldRect.Y;
|
||||
|
||||
List<RectangleF> normalizedRects = new List<RectangleF>();
|
||||
List<Hull> hullRefs = new List<Hull>();
|
||||
foreach (var (hull, rect) in rects)
|
||||
{
|
||||
Rectangle wRect = rect;
|
||||
wRect.Y = -wRect.Y;
|
||||
|
||||
var (posX, posY) = new Vector2(
|
||||
(wRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
(worldBorders.Y - wRect.Y) / (float)worldBorders.Height);
|
||||
|
||||
var (scaleX, scaleY) = new Vector2(wRect.Width / (float)worldBorders.Width, wRect.Height / (float)worldBorders.Height);
|
||||
|
||||
RectangleF newRect = new RectangleF(posX * parentRect.Width, posY * parentRect.Height, scaleX * parentRect.Width, scaleY * parentRect.Height);
|
||||
|
||||
normalizedRects.Add(newRect);
|
||||
hullRefs.Add(hull);
|
||||
}
|
||||
|
||||
ImmutableArray<RectangleF> snappedRectangles = ToolBox.SnapRectangles(normalizedRects, treshold: 1);
|
||||
|
||||
List<List<Vector2>> polygon = ToolBox.CombineRectanglesIntoShape(snappedRectangles);
|
||||
|
||||
List<List<Vector2>> scaledPolygon = new List<List<Vector2>>();
|
||||
|
||||
foreach (List<Vector2> list in polygon)
|
||||
{
|
||||
var (polySizeX, polySizeY) = ToolBox.GetPolygonBoundingBoxSize(list);
|
||||
float sizeX = polySizeX - 1f,
|
||||
sizeY = polySizeY - 1f;
|
||||
|
||||
scaledPolygon.Add(ToolBox.ScalePolygon(list, new Vector2(sizeX / polySizeX, sizeY / polySizeY)));
|
||||
}
|
||||
|
||||
return new MiniMapHullData(scaledPolygon, worldRect, parentRect.Size, snappedRectangles, hullRefs.ToImmutableArray());
|
||||
}
|
||||
|
||||
public void CheckForErrors()
|
||||
{
|
||||
List<string> errorMsgs = new List<string>();
|
||||
|
||||
@@ -64,7 +64,10 @@ namespace Barotrauma.Networking
|
||||
string orderOption = orderMessageInfo.OrderOption;
|
||||
orderOption ??= orderMessageInfo.OrderOptionIndex.HasValue && orderMessageInfo.OrderOptionIndex >= 0 && orderMessageInfo.OrderOptionIndex < orderPrefab.Options.Length ?
|
||||
orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value] : "";
|
||||
txt = orderPrefab.GetChatMessage(orderMessageInfo.TargetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: orderMessageInfo.TargetCharacter == senderCharacter, orderOption: orderOption);
|
||||
txt = orderPrefab.GetChatMessage(orderMessageInfo.TargetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName,
|
||||
givingOrderToSelf: orderMessageInfo.TargetCharacter == senderCharacter,
|
||||
orderOption: orderOption,
|
||||
priority: orderMessageInfo.Priority);
|
||||
|
||||
if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
|
||||
@@ -550,6 +550,13 @@ namespace Barotrauma.Networking
|
||||
okButton.OnClicked += msgBox.Close;
|
||||
var cancelButton = msgBox.Buttons[1];
|
||||
cancelButton.OnClicked += msgBox.Close;
|
||||
passwordBox.OnEnterPressed += (GUITextBox textBox, string text) =>
|
||||
{
|
||||
msgBox.Close();
|
||||
clientPeer?.SendPassword(passwordBox.Text);
|
||||
requiresPw = false;
|
||||
return true;
|
||||
};
|
||||
|
||||
okButton.OnClicked += (GUIButton button, object obj) =>
|
||||
{
|
||||
@@ -565,6 +572,8 @@ namespace Barotrauma.Networking
|
||||
GameMain.ServerListScreen.Select();
|
||||
return true;
|
||||
};
|
||||
yield return CoroutineStatus.Running;
|
||||
passwordBox.Select();
|
||||
|
||||
while (GUIMessageBox.MessageBoxes.Contains(msgBox))
|
||||
{
|
||||
|
||||
@@ -110,12 +110,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (frame == null) { return; }
|
||||
|
||||
var previewContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.98f), frame.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var title = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), previewContainer.RectTransform, Anchor.CenterLeft), ServerName, font: GUI.LargeFont)
|
||||
var title = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), frame.RectTransform), ServerName, font: GUI.LargeFont)
|
||||
{
|
||||
ToolTip = ServerName
|
||||
};
|
||||
@@ -141,41 +136,30 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), previewContainer.RectTransform),
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), frame.RectTransform),
|
||||
TextManager.AddPunctuation(':', TextManager.Get("ServerListVersion"), string.IsNullOrEmpty(GameVersion) ? TextManager.Get("Unknown") : GameVersion));
|
||||
|
||||
bool hidePlaystyleBanner = previewContainer.Rect.Height < 380 || !PlayStyle.HasValue;
|
||||
bool hidePlaystyleBanner = !PlayStyle.HasValue;
|
||||
if (!hidePlaystyleBanner)
|
||||
{
|
||||
PlayStyle playStyle = PlayStyle ?? Networking.PlayStyle.Serious;
|
||||
Sprite playStyleBannerSprite = ServerListScreen.PlayStyleBanners[(int)playStyle];
|
||||
float playStyleBannerAspectRatio = playStyleBannerSprite.SourceRect.Width / playStyleBannerSprite.SourceRect.Height;
|
||||
var playStyleBanner = new GUIImage(new RectTransform(new Point(previewContainer.Rect.Width, (int)(previewContainer.Rect.Width / playStyleBannerAspectRatio)), previewContainer.RectTransform),
|
||||
var playStyleBanner = new GUIImage(new RectTransform(new Point(frame.Rect.Width, (int)(frame.Rect.Width / playStyleBannerAspectRatio)), frame.RectTransform),
|
||||
playStyleBannerSprite, null, true);
|
||||
|
||||
var playStyleName = new GUITextBlock(new RectTransform(new Vector2(0.15f, 0.0f), playStyleBanner.RectTransform) { RelativeOffset = new Vector2(0.01f, 0.06f) },
|
||||
var playStyleName = new GUITextBlock(new RectTransform(new Vector2(0.15f, 0.0f), playStyleBanner.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.06f) },
|
||||
TextManager.AddPunctuation(':', TextManager.Get("serverplaystyle"), TextManager.Get("servertag."+ playStyle)), textColor: Color.White,
|
||||
font: GUI.SmallFont, textAlignment: Alignment.Center,
|
||||
color: ServerListScreen.PlayStyleColors[(int)playStyle], style: "GUISlopedHeader");
|
||||
playStyleName.RectTransform.NonScaledSize = (playStyleName.Font.MeasureString(playStyleName.Text) + new Vector2(20, 5) * GUI.Scale).ToPoint();
|
||||
playStyleName.RectTransform.IsFixedSize = true;
|
||||
|
||||
var serverTypeContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.2f), playStyleBanner.RectTransform, Anchor.BottomLeft, Pivot.BottomLeft),
|
||||
"MainMenuNotifBackground", Color.Black)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
};
|
||||
|
||||
var serverType = new GUITextBlock(new RectTransform(Vector2.One, serverTypeContainer.RectTransform, Anchor.CenterLeft),
|
||||
TextManager.Get((OwnerID != 0 || LobbyID != 0) ? "SteamP2PServer" : "DedicatedServer"), textAlignment: Alignment.CenterLeft);
|
||||
}
|
||||
else
|
||||
{
|
||||
var serverType = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), previewContainer.RectTransform, Anchor.CenterLeft),
|
||||
TextManager.Get((OwnerID != 0 || LobbyID != 0) ? "SteamP2PServer" : "DedicatedServer"), textAlignment: Alignment.CenterLeft);
|
||||
}
|
||||
var serverType = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), frame.RectTransform),
|
||||
TextManager.Get((OwnerID != 0 || LobbyID != 0) ? "SteamP2PServer" : "DedicatedServer"), textAlignment: Alignment.TopLeft);
|
||||
serverType.RectTransform.MinSize = new Point(0, (int)(serverType.Rect.Height * 1.5f));
|
||||
|
||||
var content = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), previewContainer.RectTransform))
|
||||
var content = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), frame.RectTransform))
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
@@ -285,7 +269,6 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
usingWhiteList.Selected = UsingWhiteList.Value;
|
||||
|
||||
|
||||
content.RectTransform.SizeChanged += () =>
|
||||
{
|
||||
GUITextBlock.AutoScaleAndNormalize(allowSpectating.TextBlock, allowRespawn.TextBlock, usingWhiteList.TextBlock);
|
||||
@@ -294,7 +277,7 @@ namespace Barotrauma.Networking
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform),
|
||||
TextManager.Get("ServerListContentPackages"), textAlignment: Alignment.Center, font: GUI.SubHeadingFont);
|
||||
|
||||
var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.2f), content.RectTransform)) { ScrollBarVisible = true };
|
||||
var contentPackageList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.3f), frame.RectTransform)) { ScrollBarVisible = true };
|
||||
if (ContentPackageNames.Count == 0)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(Vector2.One, contentPackageList.Content.RectTransform), TextManager.Get("Unknown"), textAlignment: Alignment.Center)
|
||||
@@ -309,7 +292,7 @@ namespace Barotrauma.Networking
|
||||
var packageText = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.15f), contentPackageList.Content.RectTransform) { MinSize = new Point(0, 15) },
|
||||
ContentPackageNames[i])
|
||||
{
|
||||
Enabled = false
|
||||
CanBeFocused = false
|
||||
};
|
||||
if (i < ContentPackageHashes.Count)
|
||||
{
|
||||
@@ -322,7 +305,7 @@ namespace Barotrauma.Networking
|
||||
//workshop download link found
|
||||
if (i < ContentPackageWorkshopIds.Count && ContentPackageWorkshopIds[i] != 0)
|
||||
{
|
||||
packageText.TextColor = Color.Yellow;
|
||||
packageText.TextColor = GUI.Style.Yellow;
|
||||
packageText.ToolTip = TextManager.GetWithVariable("ServerListIncompatibleContentPackageWorkshopAvailable", "[contentpackage]", ContentPackageNames[i]);
|
||||
}
|
||||
else //no package or workshop download link found, tough luck
|
||||
|
||||
@@ -1207,7 +1207,7 @@ namespace Barotrauma.Steam
|
||||
foreach (string file in allPackageFiles)
|
||||
{
|
||||
if (file == metaDataFilePath) { continue; }
|
||||
string relativePath = UpdaterUtil.GetRelativePath(file, item.Directory);
|
||||
string relativePath = Path.GetRelativePath(item.Directory, file);
|
||||
string fullPath = Path.GetFullPath(relativePath);
|
||||
if (contentPackage.Files.Any(f => { string fp = Path.GetFullPath(f.Path); return fp == fullPath; })) { continue; }
|
||||
nonContentFiles.Add(relativePath);
|
||||
|
||||
@@ -3,7 +3,6 @@ using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Barotrauma.Particles
|
||||
{
|
||||
@@ -16,6 +15,8 @@ namespace Barotrauma.Particles
|
||||
public delegate void OnChangeHullHandler(Vector2 position, Hull currentHull);
|
||||
public OnChangeHullHandler OnChangeHull;
|
||||
|
||||
public OnChangeHullHandler OnCollision;
|
||||
|
||||
private Vector2 position;
|
||||
private Vector2 prevPosition;
|
||||
|
||||
@@ -166,6 +167,7 @@ namespace Barotrauma.Particles
|
||||
HighQualityCollisionDetection = false;
|
||||
|
||||
OnChangeHull = null;
|
||||
OnCollision = null;
|
||||
|
||||
subEmitters.Clear();
|
||||
hasSubEmitters = false;
|
||||
@@ -340,12 +342,20 @@ namespace Barotrauma.Particles
|
||||
Vector2 collisionNormal = Vector2.Zero;
|
||||
if (velocity.Y < 0.0f && position.Y - prefab.CollisionRadius * size.Y < hullRect.Y - hullRect.Height)
|
||||
{
|
||||
if (prefab.DeleteOnCollision) { return UpdateResult.Delete; }
|
||||
if (prefab.DeleteOnCollision)
|
||||
{
|
||||
OnCollision?.Invoke(position, currentHull);
|
||||
return UpdateResult.Delete;
|
||||
}
|
||||
collisionNormal = new Vector2(0.0f, 1.0f);
|
||||
}
|
||||
else if (velocity.Y > 0.0f && position.Y + prefab.CollisionRadius * size.Y > hullRect.Y)
|
||||
{
|
||||
if (prefab.DeleteOnCollision) { return UpdateResult.Delete; }
|
||||
if (prefab.DeleteOnCollision)
|
||||
{
|
||||
OnCollision?.Invoke(position, currentHull);
|
||||
return UpdateResult.Delete;
|
||||
}
|
||||
collisionNormal = new Vector2(0.0f, -1.0f);
|
||||
}
|
||||
|
||||
@@ -487,6 +497,8 @@ namespace Barotrauma.Particles
|
||||
velocity.Y = Math.Sign(collisionNormal.Y) * Math.Abs(velocity.Y) * prefab.Restitution;
|
||||
}
|
||||
|
||||
OnCollision?.Invoke(position, currentHull);
|
||||
|
||||
velocity += subVel;
|
||||
}
|
||||
|
||||
@@ -523,6 +535,8 @@ namespace Barotrauma.Particles
|
||||
velocity.Y *= (1.0f - prefab.Friction);
|
||||
}
|
||||
|
||||
OnCollision?.Invoke(position, currentHull);
|
||||
|
||||
velocity *= prefab.Restitution;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,6 +138,8 @@ namespace Barotrauma.Particles
|
||||
|
||||
public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||
{
|
||||
if (GameMain.Client?.MidRoundSyncing ?? false) { return; }
|
||||
|
||||
if (initialDelay < Prefab.Properties.InitialDelay)
|
||||
{
|
||||
initialDelay += deltaTime;
|
||||
|
||||
@@ -133,22 +133,41 @@ namespace Barotrauma.Particles
|
||||
|
||||
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)
|
||||
{
|
||||
if (particleCount >= MaxParticles || prefab == null || prefab.Sprites.Count == 0) { return null; }
|
||||
|
||||
// this should be optimized for tracers after prototyping
|
||||
if (tracerPoints == null)
|
||||
if (prefab == null || prefab.Sprites.Count == 0) { return null; }
|
||||
|
||||
if (particleCount >= MaxParticles)
|
||||
{
|
||||
Vector2 particleEndPos = prefab.CalculateEndPosition(position, velocity);
|
||||
|
||||
Vector2 minPos = new Vector2(Math.Min(position.X, particleEndPos.X), Math.Min(position.Y, particleEndPos.Y));
|
||||
Vector2 maxPos = new Vector2(Math.Max(position.X, particleEndPos.X), Math.Max(position.Y, particleEndPos.Y));
|
||||
|
||||
Rectangle expandedViewRect = MathUtils.ExpandRect(cam.WorldView, MaxOutOfViewDist);
|
||||
|
||||
if (minPos.X > expandedViewRect.Right || maxPos.X < expandedViewRect.X) { return null; }
|
||||
if (minPos.Y > expandedViewRect.Y || maxPos.Y < expandedViewRect.Y - expandedViewRect.Height) { return null; }
|
||||
for (int i = 0; i < particleCount; i++)
|
||||
{
|
||||
if (particles[i].Prefab.Priority < prefab.Priority)
|
||||
{
|
||||
RemoveParticle(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (particleCount >= MaxParticles) { return null; }
|
||||
}
|
||||
|
||||
Vector2 particleEndPos = prefab.CalculateEndPosition(position, velocity);
|
||||
|
||||
Vector2 minPos = new Vector2(Math.Min(position.X, particleEndPos.X), Math.Min(position.Y, particleEndPos.Y));
|
||||
Vector2 maxPos = new Vector2(Math.Max(position.X, particleEndPos.X), Math.Max(position.Y, particleEndPos.Y));
|
||||
|
||||
if (tracerPoints != null)
|
||||
{
|
||||
minPos = new Vector2(
|
||||
Math.Min(Math.Min(minPos.X, tracerPoints.Item1.X), tracerPoints.Item2.X),
|
||||
Math.Min(Math.Min(minPos.Y, tracerPoints.Item1.Y), tracerPoints.Item2.Y));
|
||||
maxPos = new Vector2(
|
||||
Math.Max(Math.Max(maxPos.X, tracerPoints.Item1.X), tracerPoints.Item2.X),
|
||||
Math.Max(Math.Max(maxPos.Y, tracerPoints.Item1.Y), tracerPoints.Item2.Y));
|
||||
}
|
||||
|
||||
Rectangle expandedViewRect = MathUtils.ExpandRect(cam.WorldView, MaxOutOfViewDist);
|
||||
|
||||
if (minPos.X > expandedViewRect.Right || maxPos.X < expandedViewRect.X) { return null; }
|
||||
if (minPos.Y > expandedViewRect.Y || maxPos.Y < expandedViewRect.Y - expandedViewRect.Height) { return null; }
|
||||
|
||||
if (particles[particleCount] == null) particles[particleCount] = new Particle();
|
||||
|
||||
particles[particleCount].Init(prefab, position, velocity, rotation, hullGuess, drawOnTop, collisionIgnoreTimer, tracerPoints: tracerPoints);
|
||||
|
||||
@@ -180,16 +180,13 @@ namespace Barotrauma.Particles
|
||||
[Editable, Serialize("1.0,1.0", false, description: "The maximum initial size of the particle.")]
|
||||
public Vector2 StartSizeMax { get; private set; }
|
||||
|
||||
[Editable]
|
||||
[Serialize("0.0,0.0", false, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
|
||||
[Editable, Serialize("0.0,0.0", false, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
|
||||
public Vector2 SizeChangeMin { get; private set; }
|
||||
|
||||
[Editable]
|
||||
[Serialize("0.0,0.0", false, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
|
||||
[Editable, Serialize("0.0,0.0", false, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
|
||||
public Vector2 SizeChangeMax { get; private set; }
|
||||
|
||||
[Editable]
|
||||
[Serialize(0.0f, false, description: "How many seconds it takes for the particle to grow to it's initial size.")]
|
||||
[Editable, Serialize(0.0f, false, description: "How many seconds it takes for the particle to grow to it's initial size.")]
|
||||
public float GrowTime { get; private set; }
|
||||
|
||||
//rendering -----------------------------------------
|
||||
@@ -215,6 +212,9 @@ namespace Barotrauma.Particles
|
||||
[Editable, Serialize(ParticleBlendState.AlphaBlend, false, description: "The type of blending to use when rendering the particle.")]
|
||||
public ParticleBlendState BlendState { get; private set; }
|
||||
|
||||
[Editable, Serialize(0, false, description: "Particles with a higher priority can replace lower-priority ones if the maximum number of active particles has been reached.")]
|
||||
public int Priority { get; private set; }
|
||||
|
||||
//animation -----------------------------------------
|
||||
|
||||
[Editable(0.0f, float.MaxValue), Serialize(1.0f, false, description: "The duration of the particle's animation cycle (if it's animated).")]
|
||||
|
||||
@@ -54,9 +54,11 @@ namespace Barotrauma
|
||||
executableDir = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
|
||||
Directory.SetCurrentDirectory(executableDir);
|
||||
SteamManager.Initialize();
|
||||
EnableNvOptimus();
|
||||
Game = new GameMain(args);
|
||||
Game.Run();
|
||||
Game.Dispose();
|
||||
FreeNvOptimus();
|
||||
|
||||
CrossThread.ProcessTasks();
|
||||
}
|
||||
@@ -263,6 +265,27 @@ namespace Barotrauma
|
||||
" if you'd like to help fix this bug, you may post it on Barotrauma's GitHub issue tracker: https://github.com/Regalis11/Barotrauma/issues/", filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IntPtr nvApi64Dll = IntPtr.Zero;
|
||||
private static void EnableNvOptimus()
|
||||
{
|
||||
#if WINDOWS && X64
|
||||
// We force load nvapi64.dll so nvidia gives us the dedicated GPU on optimus laptops.
|
||||
// This is not a method for getting optimus that is documented by nvidia, but it works, so...
|
||||
if (NativeLibrary.TryLoad("nvapi64.dll", out nvApi64Dll))
|
||||
{
|
||||
DebugConsole.Log("Loaded nvapi64.dll successfully");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void FreeNvOptimus()
|
||||
{
|
||||
#warning TODO: determine if we can do this safely
|
||||
//NativeLibrary.Free(nvApi64Dll);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -466,7 +466,7 @@ namespace Barotrauma
|
||||
{
|
||||
var sub = child.UserData as SubmarineInfo;
|
||||
if (sub == null) { return; }
|
||||
child.Visible = string.IsNullOrEmpty(filter) ? true : sub.DisplayName.ToLower().Contains(filter.ToLower());
|
||||
child.Visible = string.IsNullOrEmpty(filter) || sub.DisplayName.ToLower().Contains(filter.ToLower());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -628,7 +628,7 @@ namespace Barotrauma
|
||||
{
|
||||
TextGetter = () =>
|
||||
{
|
||||
return TextManager.AddPunctuation(':', TextManager.Get("Missions"), $"{Campaign.NumberOfMissionsAtLocation(destination)}/{Campaign.Settings.MaxMissionCount}");
|
||||
return TextManager.AddPunctuation(':', TextManager.Get("Missions"), $"{Campaign.NumberOfMissionsAtLocation(destination)}/{Campaign.Settings.TotalMaxMissionCount}");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -735,7 +735,7 @@ namespace Barotrauma
|
||||
|
||||
private void UpdateMaxMissions(Location location)
|
||||
{
|
||||
hasMaxMissions = Campaign.NumberOfMissionsAtLocation(location) >= Campaign.Settings.MaxMissionCount;
|
||||
hasMaxMissions = Campaign.NumberOfMissionsAtLocation(location) >= Campaign.Settings.TotalMaxMissionCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ namespace Barotrauma.CharacterEditor
|
||||
{
|
||||
FileSelection.OnFileSelected = (file) =>
|
||||
{
|
||||
string relativePath = UpdaterUtil.GetRelativePath(Path.GetFullPath(file), Environment.CurrentDirectory);
|
||||
string relativePath = Path.GetRelativePath(Environment.CurrentDirectory, Path.GetFullPath(file));
|
||||
string destinationPath = relativePath;
|
||||
|
||||
//copy file to XML path if it's not located relative to the game's files
|
||||
|
||||
@@ -541,7 +541,7 @@ namespace Barotrauma
|
||||
|
||||
private XElement? ExportXML()
|
||||
{
|
||||
XElement mainElement = new XElement("ScriptedEvent", new XAttribute("identifier", projectName.RemoveWhitespace().ToLower()));
|
||||
XElement mainElement = new XElement("ScriptedEvent", new XAttribute("identifier", projectName.RemoveWhitespace().ToLowerInvariant()));
|
||||
EditorNode? startNode = null;
|
||||
foreach (EditorNode eventNode in nodeList.Where(node => node is EventNode || node is SpecialNode))
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace Barotrauma
|
||||
public Effect PostProcessEffect { get; private set; }
|
||||
public Effect GradientEffect { get; private set; }
|
||||
public Effect GrainEffect { get; private set; }
|
||||
public Effect BlueprintEffect { get; set; }
|
||||
|
||||
public GameScreen(GraphicsDevice graphics, ContentManager content)
|
||||
{
|
||||
@@ -43,12 +44,14 @@ namespace Barotrauma
|
||||
PostProcessEffect = content.Load<Effect>("Effects/postprocess_opengl");
|
||||
GradientEffect = content.Load<Effect>("Effects/gradientshader_opengl");
|
||||
GrainEffect = content.Load<Effect>("Effects/grainshader_opengl");
|
||||
BlueprintEffect = content.Load<Effect>("Effects/blueprintshader_opengl");
|
||||
#else
|
||||
//var blurEffect = content.Load<Effect>("Effects/blurshader");
|
||||
damageEffect = content.Load<Effect>("Effects/damageshader");
|
||||
PostProcessEffect = content.Load<Effect>("Effects/postprocess");
|
||||
GradientEffect = content.Load<Effect>("Effects/gradientshader");
|
||||
GrainEffect = content.Load<Effect>("Effects/grainshader");
|
||||
BlueprintEffect = content.Load<Effect>("Effects/blueprintshader");
|
||||
#endif
|
||||
|
||||
damageStencil = TextureLoader.FromFile("Content/Map/walldamage.png");
|
||||
|
||||
@@ -2020,7 +2020,8 @@ namespace Barotrauma
|
||||
var playerFrame = (GUITextBlock)PlayerList.Content.FindChild(client);
|
||||
if (playerFrame == null) { return; }
|
||||
playerFrame.Text = client.Name;
|
||||
|
||||
|
||||
playerFrame.ToolTip = "";
|
||||
Color color = Color.White;
|
||||
if (SelectedMode == GameModePreset.PvP)
|
||||
{
|
||||
@@ -2028,15 +2029,28 @@ namespace Barotrauma
|
||||
{
|
||||
case CharacterTeamType.Team1:
|
||||
color = new Color(0, 110, 150, 255);
|
||||
playerFrame.ToolTip = TextManager.GetWithVariable("teampreference", "[team]", TextManager.Get("teampreference.team1"));
|
||||
break;
|
||||
case CharacterTeamType.Team2:
|
||||
color = new Color(150, 110, 0, 255);
|
||||
playerFrame.ToolTip = TextManager.GetWithVariable("teampreference", "[team]", TextManager.Get("teampreference.team2"));
|
||||
break;
|
||||
default:
|
||||
playerFrame.ToolTip = TextManager.GetWithVariable("teampreference", "[team]", TextManager.Get("none"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (JobPrefab.Prefabs.ContainsKey(client.PreferredJob))
|
||||
else
|
||||
{
|
||||
color = JobPrefab.Prefabs[client.PreferredJob].UIColor;
|
||||
if (JobPrefab.Prefabs.ContainsKey(client.PreferredJob))
|
||||
{
|
||||
color = JobPrefab.Prefabs[client.PreferredJob].UIColor;
|
||||
playerFrame.ToolTip = TextManager.GetWithVariable("jobpreference", "[job]", JobPrefab.Prefabs[client.PreferredJob].Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
playerFrame.ToolTip = TextManager.GetWithVariable("jobpreference", "[job]", TextManager.Get("none"));
|
||||
}
|
||||
}
|
||||
playerFrame.Color = color * 0.4f;
|
||||
playerFrame.HoverColor = color * 0.6f;
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace Barotrauma
|
||||
private GUIFrame menu;
|
||||
|
||||
private GUIListBox serverList;
|
||||
private GUIFrame serverPreview;
|
||||
private GUIFrame serverPreviewContainer;
|
||||
private GUIListBox serverPreview;
|
||||
|
||||
private GUIButton joinButton;
|
||||
private ServerInfo selectedServer;
|
||||
@@ -340,11 +341,11 @@ namespace Barotrauma
|
||||
void RecalculateHolder()
|
||||
{
|
||||
float listContainerSubtract = filtersHolder.Visible ? sidebarWidth : 0.0f;
|
||||
listContainerSubtract += serverPreview.Visible ? sidebarWidth : 0.0f;
|
||||
listContainerSubtract += serverPreviewContainer.Visible ? sidebarWidth : 0.0f;
|
||||
|
||||
float toggleButtonsSubtract = 1.1f * filterToggle.Rect.Width / serverListHolder.Rect.Width;
|
||||
listContainerSubtract += filterToggle.Visible ? toggleButtonsSubtract : 0.0f;
|
||||
listContainerSubtract += serverPreviewToggleButton.Visible ? toggleButtonsSubtract : 0.0f;
|
||||
listContainerSubtract += serverPreviewContainer.Visible ? toggleButtonsSubtract : 0.0f;
|
||||
|
||||
serverListContainer.RectTransform.RelativeSize = new Vector2(1.0f - listContainerSubtract, 1.0f);
|
||||
serverListHolder.Recalculate();
|
||||
@@ -567,17 +568,17 @@ namespace Barotrauma
|
||||
{
|
||||
joinButton.Enabled = true;
|
||||
selectedServer = serverInfo;
|
||||
if (!serverPreview.Visible)
|
||||
if (!serverPreviewContainer.Visible)
|
||||
{
|
||||
serverPreview.RectTransform.RelativeSize = new Vector2(sidebarWidth, 1.0f);
|
||||
serverPreviewContainer.RectTransform.RelativeSize = new Vector2(sidebarWidth, 1.0f);
|
||||
serverPreviewToggleButton.Visible = true;
|
||||
serverPreviewToggleButton.IgnoreLayoutGroups = false;
|
||||
serverPreview.Visible = true;
|
||||
serverPreview.IgnoreLayoutGroups = false;
|
||||
serverPreviewContainer.Visible = true;
|
||||
serverPreviewContainer.IgnoreLayoutGroups = false;
|
||||
RecalculateHolder();
|
||||
}
|
||||
serverInfo.CreatePreviewWindow(serverPreview);
|
||||
btn.Children.ForEach(c => c.SpriteEffects = serverPreview.Visible ? SpriteEffects.None : SpriteEffects.FlipHorizontally);
|
||||
serverInfo.CreatePreviewWindow(serverPreview.Content);
|
||||
btn.Children.ForEach(c => c.SpriteEffects = serverPreviewContainer.Visible ? SpriteEffects.None : SpriteEffects.FlipHorizontally);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -592,24 +593,28 @@ namespace Barotrauma
|
||||
Visible = false,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
serverPreview.RectTransform.RelativeSize = new Vector2(0.2f, 1.0f);
|
||||
serverPreview.Visible = !serverPreview.Visible;
|
||||
serverPreview.IgnoreLayoutGroups = !serverPreview.Visible;
|
||||
serverPreviewContainer.RectTransform.RelativeSize = new Vector2(0.2f, 1.0f);
|
||||
serverPreviewContainer.Visible = !serverPreviewContainer.Visible;
|
||||
serverPreviewContainer.IgnoreLayoutGroups = !serverPreviewContainer.Visible;
|
||||
|
||||
RecalculateHolder();
|
||||
|
||||
btn.Children.ForEach(c => c.SpriteEffects = serverPreview.Visible ? SpriteEffects.None : SpriteEffects.FlipHorizontally);
|
||||
btn.Children.ForEach(c => c.SpriteEffects = serverPreviewContainer.Visible ? SpriteEffects.None : SpriteEffects.FlipHorizontally);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
serverPreview = new GUIFrame(new RectTransform(new Vector2(sidebarWidth, 1.0f), serverListHolder.RectTransform, Anchor.Center), style: null)
|
||||
serverPreviewContainer = new GUIFrame(new RectTransform(new Vector2(sidebarWidth, 1.0f), serverListHolder.RectTransform, Anchor.Center), style: null)
|
||||
{
|
||||
Color = new Color(12, 14, 15, 255) * 0.5f,
|
||||
OutlineColor = Color.Black,
|
||||
IgnoreLayoutGroups = true,
|
||||
Visible = false
|
||||
};
|
||||
serverPreview = new GUIListBox(new RectTransform(Vector2.One, serverPreviewContainer.RectTransform, Anchor.Center))
|
||||
{
|
||||
Padding = Vector4.One * 10 * GUI.Scale
|
||||
};
|
||||
|
||||
// Spacing
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), bottomRow.RectTransform), style: null);
|
||||
@@ -1697,7 +1702,7 @@ namespace Barotrauma
|
||||
UpdateFriendsList();
|
||||
|
||||
serverList.ClearChildren();
|
||||
serverPreview.ClearChildren();
|
||||
serverPreview.Content.ClearChildren();
|
||||
joinButton.Enabled = false;
|
||||
selectedServer = null;
|
||||
|
||||
|
||||
@@ -1604,7 +1604,7 @@ namespace Barotrauma
|
||||
if (string.IsNullOrEmpty(file) || !File.Exists(file)) { continue; }
|
||||
|
||||
string modFolder = Path.GetDirectoryName(itemContentPackage.Path);
|
||||
string filePathRelativeToModFolder = UpdaterUtil.GetRelativePath(file, Path.Combine(Environment.CurrentDirectory, modFolder));
|
||||
string filePathRelativeToModFolder = Path.GetRelativePath(Path.Combine(Environment.CurrentDirectory, modFolder), file);
|
||||
|
||||
//file is not inside the mod folder, we need to move it
|
||||
if (filePathRelativeToModFolder.StartsWith("..") ||
|
||||
|
||||
125
Barotrauma/BarotraumaClient/ClientSource/Screens/TestScreen.cs
Normal file
125
Barotrauma/BarotraumaClient/ClientSource/Screens/TestScreen.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
/*
|
||||
* This screen only exists because I'm going mental without access to EnC on Linux.
|
||||
* This is fucking stupid and horrible.
|
||||
* Remember to remove this crap eventually.
|
||||
* - Markus
|
||||
*/
|
||||
namespace Barotrauma
|
||||
{
|
||||
class TestScreen : EditorScreen
|
||||
{
|
||||
public override Camera Cam { get; }
|
||||
|
||||
private Item? miniMapItem;
|
||||
|
||||
private Submarine? submarine;
|
||||
private Character? dummyCharacter;
|
||||
public static Effect BlueprintEffect;
|
||||
|
||||
public TestScreen()
|
||||
{
|
||||
Cam = new Camera();
|
||||
BlueprintEffect = GameMain.GameScreen.BlueprintEffect;
|
||||
|
||||
new GUIButton(new RectTransform(new Point(256, 256), Frame.RectTransform), "Reload shader")
|
||||
{
|
||||
OnClicked = (button, o) =>
|
||||
{
|
||||
BlueprintEffect.Dispose();
|
||||
GameMain.Instance.Content.Unload();
|
||||
BlueprintEffect = GameMain.Instance.Content.Load<Effect>("Effects/blueprintshader_opengl");
|
||||
GameMain.GameScreen.BlueprintEffect = BlueprintEffect;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override void Select()
|
||||
{
|
||||
base.Select();
|
||||
|
||||
if (dummyCharacter is { Removed: false })
|
||||
{
|
||||
dummyCharacter?.Remove();
|
||||
}
|
||||
|
||||
// ????????
|
||||
submarine = new Submarine(SubmarineInfo.SavedSubmarines.FirstOrDefault(info => info.Name.Equals("Kastrull", StringComparison.OrdinalIgnoreCase)));
|
||||
miniMapItem = new Item(ItemPrefab.Find(null, "statusmonitor"), Vector2.Zero, submarine);
|
||||
MiniMap miniMap = miniMapItem.GetComponent<MiniMap>();
|
||||
miniMap.PowerConsumption = 0;
|
||||
|
||||
dummyCharacter = Character.Create(CharacterPrefab.HumanSpeciesName, Vector2.Zero, "", id: Entity.DummyID, hasAi: false);
|
||||
dummyCharacter.Info.Name = "Galldren";
|
||||
dummyCharacter.Inventory.CreateSlots();
|
||||
|
||||
Character.Controlled = dummyCharacter;
|
||||
GameMain.World.ProcessChanges();
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
Frame.AddToGUIUpdateList();
|
||||
CharacterHUD.AddToGUIUpdateList(dummyCharacter);
|
||||
dummyCharacter?.SelectedConstruction?.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (dummyCharacter is { } dummy && miniMapItem is { } item)
|
||||
{
|
||||
if (dummy.SelectedConstruction != item)
|
||||
{
|
||||
dummy.SelectedConstruction = item;
|
||||
}
|
||||
dummy.SelectedConstruction?.UpdateHUD(Cam, dummy, (float)deltaTime);
|
||||
Vector2 pos = FarseerPhysics.ConvertUnits.ToSimUnits(item.Position);
|
||||
foreach (Limb limb in dummy.AnimController.Limbs)
|
||||
{
|
||||
limb.body.SetTransform(pos, 0.0f);
|
||||
}
|
||||
|
||||
if (dummy.AnimController?.Collider is { } collider)
|
||||
{
|
||||
collider.SetTransform(pos, 0);
|
||||
}
|
||||
|
||||
dummy.ControlLocalPlayer((float)deltaTime, Cam, false);
|
||||
dummy.Control((float)deltaTime, Cam);
|
||||
dummy.Submarine = submarine;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
||||
{
|
||||
base.Draw(deltaTime, graphics, spriteBatch);
|
||||
graphics.Clear(BackgroundColor);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, transformMatrix: Cam.Transform);
|
||||
miniMapItem?.Draw(spriteBatch, false);
|
||||
if (dummyCharacter is { } dummy)
|
||||
{
|
||||
dummyCharacter.DrawFront(spriteBatch, Cam);
|
||||
dummyCharacter.Draw(spriteBatch, Cam);
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState);
|
||||
|
||||
GUI.Draw(Cam, spriteBatch);
|
||||
|
||||
dummyCharacter?.DrawHUD(spriteBatch, Cam, false);
|
||||
|
||||
spriteBatch.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ namespace Barotrauma
|
||||
public readonly string File;
|
||||
public readonly string Type;
|
||||
public readonly bool DuckVolume;
|
||||
public readonly float Volume;
|
||||
|
||||
public readonly Vector2 IntensityRange;
|
||||
|
||||
@@ -52,6 +53,7 @@ namespace Barotrauma
|
||||
this.Type = element.GetAttributeString("type", "").ToLowerInvariant();
|
||||
this.IntensityRange = element.GetAttributeVector2("intensityrange", new Vector2(0.0f, 100.0f));
|
||||
this.DuckVolume = element.GetAttributeBool("duckvolume", false);
|
||||
this.Volume = element.GetAttributeFloat("volume", 1.0f);
|
||||
this.ContinueFromPreviousTime = element.GetAttributeBool("continuefromprevioustime", false);
|
||||
this.Element = element;
|
||||
}
|
||||
@@ -816,6 +818,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
int noiseLoopIndex = 1;
|
||||
|
||||
updateMusicTimer -= deltaTime;
|
||||
if (updateMusicTimer <= 0.0f)
|
||||
{
|
||||
@@ -851,7 +855,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
int noiseLoopIndex = 1;
|
||||
if (Level.Loaded?.Type == LevelData.LevelType.LocationConnection)
|
||||
{
|
||||
// Find background noise loop for the current biome
|
||||
@@ -917,7 +920,7 @@ namespace Barotrauma
|
||||
{
|
||||
//mute the channel
|
||||
musicChannel[i].Gain = MathHelper.Lerp(musicChannel[i].Gain, 0.0f, MusicLerpSpeed * deltaTime);
|
||||
if (musicChannel[i].Gain < 0.01f) DisposeMusicChannel(i);
|
||||
if (musicChannel[i].Gain < 0.01f) { DisposeMusicChannel(i); }
|
||||
}
|
||||
}
|
||||
//something should be playing, but the targetMusic is invalid
|
||||
@@ -932,7 +935,7 @@ namespace Barotrauma
|
||||
if (musicChannel[i] != null && musicChannel[i].IsPlaying)
|
||||
{
|
||||
musicChannel[i].Gain = MathHelper.Lerp(musicChannel[i].Gain, 0.0f, MusicLerpSpeed * deltaTime);
|
||||
if (musicChannel[i].Gain < 0.01f) DisposeMusicChannel(i);
|
||||
if (musicChannel[i].Gain < 0.01f) { DisposeMusicChannel(i); }
|
||||
}
|
||||
//channel free now, start playing the correct clip
|
||||
if (currentMusic[i] == null || (musicChannel[i] == null || !musicChannel[i].IsPlaying))
|
||||
@@ -949,7 +952,7 @@ namespace Barotrauma
|
||||
targetMusic[i] = null;
|
||||
break;
|
||||
}
|
||||
musicChannel[i] = currentMusic[i].Play(0.0f, "music");
|
||||
musicChannel[i] = currentMusic[i].Play(0.0f, i == noiseLoopIndex ? "" : "music");
|
||||
if (targetMusic[i].ContinueFromPreviousTime)
|
||||
{
|
||||
musicChannel[i].StreamSeekPos = targetMusic[i].PreviousTime;
|
||||
@@ -963,13 +966,13 @@ namespace Barotrauma
|
||||
if (musicChannel[i] == null || !musicChannel[i].IsPlaying)
|
||||
{
|
||||
musicChannel[i]?.Dispose();
|
||||
musicChannel[i] = currentMusic[i].Play(0.0f, "music");
|
||||
musicChannel[i] = currentMusic[i].Play(0.0f, i == noiseLoopIndex ? "" : "music");
|
||||
musicChannel[i].Looping = true;
|
||||
}
|
||||
float targetGain = 1.0f;
|
||||
float targetGain = targetMusic[i].Volume;
|
||||
if (targetMusic[i].DuckVolume)
|
||||
{
|
||||
targetGain = (float)Math.Sqrt(1.0f / activeTrackCount);
|
||||
targetGain *= (float)Math.Sqrt(1.0f / activeTrackCount);
|
||||
}
|
||||
musicChannel[i].Gain = MathHelper.Lerp(musicChannel[i].Gain, targetGain, MusicLerpSpeed * deltaTime);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Color = Microsoft.Xna.Framework.Color;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -54,6 +55,225 @@ namespace Barotrauma
|
||||
|
||||
return isInside;
|
||||
}
|
||||
|
||||
public static Vector2 GetPolygonBoundingBoxSize(List<Vector2> verticess)
|
||||
{
|
||||
float minX = verticess[0].X;
|
||||
float maxX = verticess[0].X;
|
||||
float minY = verticess[0].Y;
|
||||
float maxY = verticess[0].Y;
|
||||
|
||||
foreach (var (vertX, vertY) in verticess)
|
||||
{
|
||||
minX = Math.Min(vertX, minX);
|
||||
maxX = Math.Max(vertX, maxX);
|
||||
minY = Math.Min(vertY, minY);
|
||||
maxY = Math.Max(vertY, maxY);
|
||||
}
|
||||
|
||||
return new Vector2(maxX - minX, maxY - minY);
|
||||
}
|
||||
|
||||
public static List<Vector2> ScalePolygon(List<Vector2> vertices, Vector2 scale)
|
||||
{
|
||||
List<Vector2> newVertices = new List<Vector2>();
|
||||
|
||||
Vector2 center = GetPolygonCentroid(vertices);
|
||||
|
||||
foreach (Vector2 vert in vertices)
|
||||
{
|
||||
Vector2 centerVector = vert - center;
|
||||
Vector2 centerVectorScale = centerVector * scale;
|
||||
Vector2 scaledVector = centerVectorScale + center;
|
||||
newVertices.Add(scaledVector);
|
||||
}
|
||||
|
||||
return newVertices;
|
||||
}
|
||||
|
||||
public static Vector2 GetPolygonCentroid(List<Vector2> poly)
|
||||
{
|
||||
float accumulatedArea = 0.0f;
|
||||
float centerX = 0.0f;
|
||||
float centerY = 0.0f;
|
||||
|
||||
for (int i = 0, j = poly.Count - 1; i < poly.Count; j = i++)
|
||||
{
|
||||
float temp = poly[i].X * poly[j].Y - poly[j].X * poly[i].Y;
|
||||
accumulatedArea += temp;
|
||||
centerX += (poly[i].X + poly[j].X) * temp;
|
||||
centerY += (poly[i].Y + poly[j].Y) * temp;
|
||||
}
|
||||
|
||||
if (Math.Abs(accumulatedArea) < 1E-7f) { return Vector2.Zero; } // Avoid division by zero
|
||||
|
||||
accumulatedArea *= 3f;
|
||||
return new Vector2(centerX / accumulatedArea, centerY / accumulatedArea);
|
||||
}
|
||||
|
||||
public static List<Vector2> SnapVertices(List<Vector2> points, int treshold = 1)
|
||||
{
|
||||
Stack<Vector2> toCheck = new Stack<Vector2>();
|
||||
List<Vector2> newPoints = new List<Vector2>();
|
||||
|
||||
foreach (Vector2 point in points)
|
||||
{
|
||||
toCheck.Push(point);
|
||||
}
|
||||
|
||||
while (toCheck.TryPop(out Vector2 point))
|
||||
{
|
||||
Vector2 newPoint = new Vector2(point.X, point.Y);
|
||||
foreach (Vector2 otherPoint in toCheck.Concat(newPoints))
|
||||
{
|
||||
float diffX = Math.Abs(newPoint.X - otherPoint.X),
|
||||
diffY = Math.Abs(newPoint.Y - otherPoint.Y);
|
||||
|
||||
if (diffX <= treshold)
|
||||
{
|
||||
newPoint.X = Math.Max(newPoint.X, otherPoint.X);
|
||||
}
|
||||
|
||||
if (diffY <= treshold)
|
||||
{
|
||||
newPoint.Y = Math.Max(newPoint.Y, otherPoint.Y);
|
||||
}
|
||||
}
|
||||
newPoints.Add(newPoint);
|
||||
}
|
||||
|
||||
return newPoints;
|
||||
}
|
||||
|
||||
public static ImmutableArray<RectangleF> SnapRectangles(IEnumerable<RectangleF> rects, int treshold = 1)
|
||||
{
|
||||
List<RectangleF> list = new List<RectangleF>();
|
||||
|
||||
List<Vector2> points = new List<Vector2>();
|
||||
|
||||
foreach (RectangleF rect in rects)
|
||||
{
|
||||
points.Add(new Vector2(rect.Left, rect.Top));
|
||||
points.Add(new Vector2(rect.Right, rect.Top));
|
||||
points.Add(new Vector2(rect.Right, rect.Bottom));
|
||||
points.Add(new Vector2(rect.Left, rect.Bottom));
|
||||
}
|
||||
|
||||
points = SnapVertices(points, treshold);
|
||||
|
||||
for (int i = 0; i < points.Count; i += 4)
|
||||
{
|
||||
Vector2 topLeft = points[i];
|
||||
Vector2 bottomRight = points[i + 2];
|
||||
|
||||
list.Add(new RectangleF(topLeft, bottomRight - topLeft));
|
||||
}
|
||||
|
||||
return list.ToImmutableArray();
|
||||
}
|
||||
|
||||
public static List<List<Vector2>> CombineRectanglesIntoShape(IEnumerable<RectangleF> rectangles)
|
||||
{
|
||||
List<Vector2> points =
|
||||
(from point in rectangles.SelectMany(RectangleToPoints)
|
||||
group point by point
|
||||
into g
|
||||
where g.Count() % 2 == 1
|
||||
select g.Key)
|
||||
.ToList();
|
||||
|
||||
List<Vector2> sortedY = points.OrderBy(p => p.Y).ThenByDescending(p => p.X).ToList();
|
||||
List<Vector2> sortedX = points.OrderBy(p => p.X).ThenByDescending(p => p.Y).ToList();
|
||||
|
||||
Dictionary<Vector2, Vector2> edgesH = new Dictionary<Vector2, Vector2>();
|
||||
Dictionary<Vector2, Vector2> edgesV = new Dictionary<Vector2, Vector2>();
|
||||
|
||||
int i = 0;
|
||||
while (i < points.Count)
|
||||
{
|
||||
float currY = sortedY[i].Y;
|
||||
|
||||
while (i < points.Count && Math.Abs(sortedY[i].Y - currY) < 0.01f)
|
||||
{
|
||||
edgesH[sortedY[i]] = sortedY[i + 1];
|
||||
edgesH[sortedY[i + 1]] = sortedY[i];
|
||||
i += 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < points.Count)
|
||||
{
|
||||
float currX = sortedX[i].X;
|
||||
while (i < points.Count && Math.Abs(sortedX[i].X - currX) < 0.01f)
|
||||
{
|
||||
edgesV[sortedX[i]] = sortedX[i + 1];
|
||||
edgesV[sortedX[i + 1]] = sortedX[i];
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
List<List<Vector2>> polygons = new List<List<Vector2>>();
|
||||
|
||||
while (edgesH.Any())
|
||||
{
|
||||
var (key, _) = edgesH.First();
|
||||
List<(Vector2 Point, int Direction)> polygon = new List<(Vector2 Point, int Direction)> { (key, 0) };
|
||||
edgesH.Remove(key);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var (curr, direction) = polygon[^1];
|
||||
|
||||
if (direction == 0)
|
||||
{
|
||||
Vector2 nextVertex = edgesV[curr];
|
||||
edgesV.Remove(curr);
|
||||
polygon.Add((nextVertex, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 nextVertex = edgesH[curr];
|
||||
edgesH.Remove(curr);
|
||||
polygon.Add((nextVertex, 0));
|
||||
}
|
||||
|
||||
if (polygon[^1] == polygon[0])
|
||||
{
|
||||
polygon.Remove(polygon[^1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
List<Vector2> poly = polygon.Select(t => t.Point).ToList();
|
||||
|
||||
foreach (Vector2 vertex in poly)
|
||||
{
|
||||
if (edgesH.ContainsKey(vertex))
|
||||
{
|
||||
edgesH.Remove(vertex);
|
||||
}
|
||||
|
||||
if (edgesV.ContainsKey(vertex))
|
||||
{
|
||||
edgesV.Remove(vertex);
|
||||
}
|
||||
}
|
||||
|
||||
polygons.Add(poly);
|
||||
}
|
||||
|
||||
return polygons;
|
||||
|
||||
static IEnumerable<Vector2> RectangleToPoints(RectangleF rect)
|
||||
{
|
||||
(float x1, float y1, float x2, float y2) = (rect.Left, rect.Top, rect.Right, rect.Bottom);
|
||||
Vector2[] pts = { new Vector2(x1, y1), new Vector2(x2, y1), new Vector2(x2, y2), new Vector2(x1, y2) };
|
||||
return pts;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an RGB value into an HLS value.
|
||||
public static Vector3 RgbToHLS(this Color color)
|
||||
|
||||
BIN
Barotrauma/BarotraumaClient/Content/Effects/blueprintshader.xnb
Normal file
BIN
Barotrauma/BarotraumaClient/Content/Effects/blueprintshader.xnb
Normal file
Binary file not shown.
Binary file not shown.
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.14.9.0</Version>
|
||||
<Version>0.1500.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.14.9.0</Version>
|
||||
<Version>0.1500.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -67,3 +67,9 @@
|
||||
/processorParam:DebugMode=Auto
|
||||
/build:grainshader.fx
|
||||
|
||||
#begin blueprintshader.fx
|
||||
/importer:EffectImporter
|
||||
/processor:EffectProcessor
|
||||
/processorParam:DebugMode=Auto
|
||||
/build:blueprintshader.fx
|
||||
|
||||
|
||||
@@ -67,3 +67,8 @@
|
||||
/processorParam:DebugMode=Auto
|
||||
/build:grainshader_opengl.fx
|
||||
|
||||
#begin blueprintshader_opengl.fx
|
||||
/importer:EffectImporter
|
||||
/processor:EffectProcessor
|
||||
/processorParam:DebugMode=Auto
|
||||
/build:blueprintshader_opengl.fx
|
||||
|
||||
48
Barotrauma/BarotraumaClient/Shaders/blueprintshader.fx
Normal file
48
Barotrauma/BarotraumaClient/Shaders/blueprintshader.fx
Normal file
@@ -0,0 +1,48 @@
|
||||
// vim:ft=hlsl
|
||||
sampler TextureSampler : register(s0);
|
||||
|
||||
float width;
|
||||
float height;
|
||||
|
||||
float3 sobel(float2 uv)
|
||||
{
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
|
||||
float w = 1.0 / width;
|
||||
float h = 1.0 / height;
|
||||
|
||||
x += tex2D(TextureSampler, uv + float2(-w, -h)) * -1.0;
|
||||
x += tex2D(TextureSampler, uv + float2(-w, 0)) * -2.0;
|
||||
x += tex2D(TextureSampler, uv + float2(-w, h)) * -1.0;
|
||||
|
||||
x += tex2D(TextureSampler, uv + float2( w, -h)) * 1.0;
|
||||
x += tex2D(TextureSampler, uv + float2( w, 0)) * 2.0;
|
||||
x += tex2D(TextureSampler, uv + float2( w, h)) * 1.0;
|
||||
|
||||
y += tex2D(TextureSampler, uv + float2(-w, -h)) * -1.0;
|
||||
y += tex2D(TextureSampler, uv + float2( 0, -h)) * -2.0;
|
||||
y += tex2D(TextureSampler, uv + float2( w, -h)) * -1.0;
|
||||
|
||||
y += tex2D(TextureSampler, uv + float2(-w, h)) * 1.0;
|
||||
y += tex2D(TextureSampler, uv + float2( 0, h)) * 2.0;
|
||||
y += tex2D(TextureSampler, uv + float2( w, h)) * 1.0;
|
||||
|
||||
return sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
float4 blueprint(float4 position : SV_POSITION, float4 clr : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
|
||||
{
|
||||
float3 s = sobel(texCoord);
|
||||
float a = tex2D(TextureSampler, texCoord).a;
|
||||
a *= clr.a;
|
||||
return float4(clr.r + s.r, clr.g + s.g, clr.b + s.b, a);
|
||||
}
|
||||
|
||||
technique Blueprint
|
||||
{
|
||||
pass Pass1
|
||||
{
|
||||
PixelShader = compile ps_4_0_level_9_1 blueprint();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// vim:ft=hlsl
|
||||
sampler TextureSampler : register(s0);
|
||||
|
||||
float width;
|
||||
float height;
|
||||
|
||||
float3 sobel(float2 uv)
|
||||
{
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
|
||||
float w = 1.0 / width;
|
||||
float h = 1.0 / height;
|
||||
|
||||
x += tex2D(TextureSampler, uv + float2(-w, -h)) * -1.0;
|
||||
x += tex2D(TextureSampler, uv + float2(-w, 0)) * -2.0;
|
||||
x += tex2D(TextureSampler, uv + float2(-w, h)) * -1.0;
|
||||
|
||||
x += tex2D(TextureSampler, uv + float2( w, -h)) * 1.0;
|
||||
x += tex2D(TextureSampler, uv + float2( w, 0)) * 2.0;
|
||||
x += tex2D(TextureSampler, uv + float2( w, h)) * 1.0;
|
||||
|
||||
y += tex2D(TextureSampler, uv + float2(-w, -h)) * -1.0;
|
||||
y += tex2D(TextureSampler, uv + float2( 0, -h)) * -2.0;
|
||||
y += tex2D(TextureSampler, uv + float2( w, -h)) * -1.0;
|
||||
|
||||
y += tex2D(TextureSampler, uv + float2(-w, h)) * 1.0;
|
||||
y += tex2D(TextureSampler, uv + float2( 0, h)) * 2.0;
|
||||
y += tex2D(TextureSampler, uv + float2( w, h)) * 1.0;
|
||||
|
||||
return sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
float4 blueprint(float4 position : SV_POSITION, float4 clr : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
|
||||
{
|
||||
float3 s = sobel(texCoord);
|
||||
float a = tex2D(TextureSampler, texCoord).a;
|
||||
a *= clr.a;
|
||||
return float4(clr.r + s.r, clr.g + s.g, clr.b + s.b, a);
|
||||
}
|
||||
|
||||
technique Blueprint
|
||||
{
|
||||
pass Pass1
|
||||
{
|
||||
PixelShader = compile ps_3_0 blueprint();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.14.9.0</Version>
|
||||
<Version>0.1500.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.14.9.0</Version>
|
||||
<Version>0.1500.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.14.9.0</Version>
|
||||
<Version>0.1500.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -46,5 +46,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnMoneyChanged(int prevAmount, int newAmount)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateMoney });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -22,6 +23,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnExperienceChanged(int prevAmount, int newAmount, Vector2 textPopupPos)
|
||||
{
|
||||
if (Math.Abs(prevAmount - newAmount) > 0)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdateExperience });
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg)
|
||||
{
|
||||
msg.Write(ID);
|
||||
@@ -53,6 +62,17 @@ namespace Barotrauma
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
// TODO: animations
|
||||
msg.Write((byte)savedStatValues.SelectMany(s => s.Value).Count());
|
||||
foreach (var savedStatValuePair in savedStatValues)
|
||||
{
|
||||
foreach (var savedStatValue in savedStatValuePair.Value)
|
||||
{
|
||||
msg.Write((byte)savedStatValuePair.Key);
|
||||
msg.Write(savedStatValue.StatIdentifier);
|
||||
msg.Write(savedStatValue.StatValue);
|
||||
msg.Write(savedStatValue.RemoveOnDeath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ namespace Barotrauma
|
||||
break;
|
||||
|
||||
case ClientNetObject.ENTITY_STATE:
|
||||
int eventType = msg.ReadRangedInteger(0, 3);
|
||||
int eventType = msg.ReadRangedInteger(0, 4);
|
||||
switch (eventType)
|
||||
{
|
||||
case 0:
|
||||
@@ -268,8 +268,35 @@ namespace Barotrauma
|
||||
if (IsIncapacitated)
|
||||
{
|
||||
var causeOfDeath = CharacterHealth.GetCauseOfDeath();
|
||||
Kill(causeOfDeath.First, causeOfDeath.Second);
|
||||
Kill(causeOfDeath.type, causeOfDeath.affliction);
|
||||
}
|
||||
break;
|
||||
case 3: // NetEntityEvent.Type.UpdateTalents
|
||||
if (c.Character != this)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.Log("Received a character update message from a client who's not controlling the character");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// get the full list of talents from the player, only give the ones
|
||||
// that are not already given (or otherwise not viable)
|
||||
ushort talentCount = msg.ReadUInt16();
|
||||
List<string> talentSelection = new List<string>();
|
||||
for (int i = 0; i < talentCount; i++)
|
||||
{
|
||||
UInt32 talentIdentifier = msg.ReadUInt32();
|
||||
var prefab = TalentPrefab.TalentPrefabs.Find(p => p.UIntIdentifier == talentIdentifier);
|
||||
if (prefab != null) { talentSelection.Add(prefab.Identifier); }
|
||||
}
|
||||
talentSelection = TalentTree.CheckTalentSelection(this, talentSelection);
|
||||
|
||||
foreach (string talent in talentSelection)
|
||||
{
|
||||
GiveTalent(talent);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -283,7 +310,7 @@ namespace Barotrauma
|
||||
|
||||
if (extraData != null)
|
||||
{
|
||||
const int min = 0, max = 9;
|
||||
const int min = 0, max = 12;
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
@@ -394,6 +421,22 @@ namespace Barotrauma
|
||||
msg.Write(inventoryItemIDs[i]);
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateExperience:
|
||||
msg.WriteRangedInteger(10, min, max);
|
||||
msg.Write(Info.ExperiencePoints);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateTalents:
|
||||
msg.WriteRangedInteger(11, min, max);
|
||||
msg.Write((ushort)characterTalents.Count);
|
||||
foreach (var unlockedTalent in characterTalents)
|
||||
{
|
||||
msg.Write(unlockedTalent.Prefab.UIntIdentifier);
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateMoney:
|
||||
msg.WriteRangedInteger(12, min, max);
|
||||
msg.Write(GameMain.GameSession.Campaign.Money);
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError("Invalid NetworkEvent type for entity " + ToString() + " (" + (NetEntityEvent.Type)extraData[0] + ")");
|
||||
break;
|
||||
@@ -499,7 +542,7 @@ namespace Barotrauma
|
||||
if (writeStatus)
|
||||
{
|
||||
WriteStatus(tempBuffer);
|
||||
(AIController as EnemyAIController)?.PetBehavior?.ServerWrite(tempBuffer);
|
||||
AIController?.ServerWrite(tempBuffer);
|
||||
HealthUpdatePending = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1187,6 +1187,7 @@ namespace Barotrauma
|
||||
NewMessage("*****************", Color.Lime);
|
||||
GameServer.Log("Console command \"restart\" executed: closing the server...", ServerLog.MessageType.ServerMessage);
|
||||
GameMain.Instance.CloseServer();
|
||||
GameMain.Instance.TryStartChildServerRelay();
|
||||
GameMain.Instance.StartServer();
|
||||
}));
|
||||
|
||||
|
||||
@@ -18,7 +18,17 @@ namespace Barotrauma
|
||||
{
|
||||
public static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
||||
|
||||
public static World World;
|
||||
|
||||
private static World world;
|
||||
public static World World
|
||||
{
|
||||
get
|
||||
{
|
||||
if (world == null) { world = new World(new Vector2(0, -9.82f)); }
|
||||
return world;
|
||||
}
|
||||
set { world = value; }
|
||||
}
|
||||
public static GameSettings Config;
|
||||
|
||||
public static GameServer Server;
|
||||
@@ -123,6 +133,8 @@ namespace Barotrauma
|
||||
ItemAssemblyPrefab.LoadAll();
|
||||
LevelObjectPrefab.LoadAll();
|
||||
BallastFloraPrefab.LoadAll(GetFilesOfType(ContentType.MapCreature));
|
||||
TalentPrefab.LoadAll(GetFilesOfType(ContentType.Talents));
|
||||
TalentTree.LoadAll(GetFilesOfType(ContentType.TalentTrees));
|
||||
|
||||
GameModePreset.Init();
|
||||
DecalManager = new DecalManager();
|
||||
@@ -179,6 +191,20 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryStartChildServerRelay()
|
||||
{
|
||||
for (int i = 0; i < CommandLineArgs.Length; i++)
|
||||
{
|
||||
switch (CommandLineArgs[i].Trim())
|
||||
{
|
||||
case "-pipes":
|
||||
ChildServerRelay.Start(CommandLineArgs[i + 2], CommandLineArgs[i + 1]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void StartServer()
|
||||
{
|
||||
string name = "Server";
|
||||
@@ -264,7 +290,7 @@ namespace Barotrauma
|
||||
i++;
|
||||
break;
|
||||
case "-pipes":
|
||||
ChildServerRelay.Start(CommandLineArgs[i + 2], CommandLineArgs[i + 1]);
|
||||
//handled in TryStartChildServerRelay
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
@@ -323,6 +349,7 @@ namespace Barotrauma
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Items.Components.ItemComponent));
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Hull));
|
||||
|
||||
TryStartChildServerRelay();
|
||||
Init();
|
||||
StartServer();
|
||||
|
||||
|
||||
@@ -56,6 +56,6 @@ namespace Barotrauma
|
||||
public void ApplyOrderData(Character character)
|
||||
{
|
||||
CharacterInfo.ApplyOrderData(character, OrderData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,12 @@ namespace Barotrauma.Items.Components
|
||||
set { unsentChanges = value; }
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
pathFinder = null;
|
||||
}
|
||||
|
||||
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Barotrauma.Networking.Client c)
|
||||
{
|
||||
|
||||
@@ -289,6 +289,14 @@ namespace Barotrauma
|
||||
teamID = (byte)wifiComponent.TeamID;
|
||||
break;
|
||||
}
|
||||
if (teamID == 0)
|
||||
{
|
||||
foreach (IdCard idCard in GetComponents<IdCard>())
|
||||
{
|
||||
teamID = (byte)idCard.TeamID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
msg.Write(teamID);
|
||||
bool tagsChanged = tags.Count != prefab.Tags.Count || !tags.All(t => prefab.Tags.Contains(t));
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Barotrauma.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System.IO.Pipes;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
|
||||
@@ -2354,6 +2354,8 @@ namespace Barotrauma.Networking
|
||||
characterData.ApplyHealthData(spawnedCharacter);
|
||||
characterData.ApplyOrderData(spawnedCharacter);
|
||||
spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]);
|
||||
spawnedCharacter.LoadTalents();
|
||||
|
||||
characterData.HasSpawned = true;
|
||||
}
|
||||
spawnedCharacter.OwnerClientEndPoint = teamClients[i].Connection.EndPointString;
|
||||
@@ -2366,6 +2368,8 @@ namespace Barotrauma.Networking
|
||||
spawnedCharacter.TeamID = teamID;
|
||||
spawnedCharacter.GiveJobItems(mainSubWaypoints[i]);
|
||||
spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]);
|
||||
// talents are only avilable for players in online sessions, but modders or someone else might want to have them loaded anyway
|
||||
spawnedCharacter.LoadTalents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2431,6 +2435,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
roundStartTime = DateTime.Now;
|
||||
|
||||
startGameCoroutine = null;
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
@@ -2619,8 +2624,8 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
Submarine.Unload();
|
||||
entityEventManager.Clear();
|
||||
Submarine.Unload();
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
Log("Round ended.", ServerLog.MessageType.ServerMessage);
|
||||
|
||||
@@ -3145,28 +3150,19 @@ namespace Barotrauma.Networking
|
||||
public void SendOrderChatMessage(OrderChatMessage message)
|
||||
{
|
||||
if (message.Sender == null || message.Sender.SpeechImpediment >= 100.0f) { return; }
|
||||
//ChatMessageType messageType = ChatMessage.CanUseRadio(message.Sender) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
|
||||
//check which clients can receive the message and apply distance effects
|
||||
foreach (Client client in ConnectedClients)
|
||||
{
|
||||
string modifiedMessage = message.Text;
|
||||
|
||||
if (message.Sender != null &&
|
||||
client.Character != null && !client.Character.IsDead)
|
||||
if (message.Sender != null && client.Character != null && !client.Character.IsDead)
|
||||
{
|
||||
//too far to hear the msg -> don't send
|
||||
if (!client.Character.CanHearCharacter(message.Sender)) { continue; }
|
||||
}
|
||||
|
||||
SendDirectChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.TargetEntity, message.TargetCharacter, message.Sender), client);
|
||||
}
|
||||
|
||||
string myReceivedMessage = message.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(myReceivedMessage))
|
||||
if (!string.IsNullOrWhiteSpace(message.Text))
|
||||
{
|
||||
AddChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, myReceivedMessage, message.TargetEntity, message.TargetCharacter, message.Sender));
|
||||
AddChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.Text, message.TargetEntity, message.TargetCharacter, message.Sender));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,11 +44,11 @@ namespace Barotrauma.Networking
|
||||
|
||||
class ServerEntityEventManager : NetEntityEventManager
|
||||
{
|
||||
private List<ServerEntityEvent> events;
|
||||
private readonly List<ServerEntityEvent> events;
|
||||
|
||||
//list of unique events (i.e. !IsDuplicate) created during the round
|
||||
//used for syncing clients who join mid-round
|
||||
private List<ServerEntityEvent> uniqueEvents;
|
||||
private readonly List<ServerEntityEvent> uniqueEvents;
|
||||
|
||||
private UInt16 lastSentToAll;
|
||||
private UInt16 lastSentToAnyone;
|
||||
@@ -90,11 +90,11 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private List<BufferedEvent> bufferedEvents;
|
||||
private readonly List<BufferedEvent> bufferedEvents;
|
||||
|
||||
private UInt16 ID;
|
||||
|
||||
private GameServer server;
|
||||
private readonly GameServer server;
|
||||
|
||||
private double lastEventCountHighWarning;
|
||||
|
||||
|
||||
@@ -284,6 +284,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
partial void RespawnCharactersProjSpecific(Vector2? shuttlePos)
|
||||
{
|
||||
respawnedCharacters.Clear();
|
||||
|
||||
var respawnSub = RespawnShuttle ?? Submarine.MainSub;
|
||||
|
||||
MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign;
|
||||
@@ -300,7 +302,7 @@ namespace Barotrauma.Networking
|
||||
if (matchingData != null && !matchingData.HasSpawned)
|
||||
{
|
||||
c.CharacterInfo = matchingData.CharacterInfo;
|
||||
}
|
||||
}
|
||||
|
||||
//all characters are in Team 1 in game modes/missions with only one team.
|
||||
//if at some point we add a game mode with multiple teams where respawning is possible, this needs to be reworked
|
||||
@@ -355,8 +357,21 @@ namespace Barotrauma.Networking
|
||||
|
||||
characterInfos[i].ClearCurrentOrders();
|
||||
|
||||
var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, characterInfos[i].Name, isRemotePlayer: !bot, hasAi: bot);
|
||||
bool forceSpawnInMainSub = false;
|
||||
if (!bot && campaign != null)
|
||||
{
|
||||
var matchingData = campaign?.GetClientCharacterData(clients[i]);
|
||||
if (matchingData != null && !matchingData.HasSpawned)
|
||||
{
|
||||
forceSpawnInMainSub = true;
|
||||
}
|
||||
}
|
||||
|
||||
var character = Character.Create(characterInfos[i], (forceSpawnInMainSub ? mainSubSpawnPoints[i] : shuttleSpawnPoints[i]).WorldPosition, characterInfos[i].Name, isRemotePlayer: !bot, hasAi: bot);
|
||||
character.TeamID = CharacterTeamType.Team1;
|
||||
character.LoadTalents();
|
||||
|
||||
respawnedCharacters.Add(character);
|
||||
|
||||
if (bot)
|
||||
{
|
||||
|
||||
@@ -185,7 +185,10 @@ namespace Barotrauma
|
||||
{
|
||||
existingItems.Add(item);
|
||||
}
|
||||
Entity.Spawner.AddToSpawnQueue(targetPrefab, targetContainer.OwnInventory);
|
||||
Entity.Spawner.AddToSpawnQueue(targetPrefab, targetContainer.OwnInventory, null, item =>
|
||||
{
|
||||
item.AddTag("traitormissionitem");
|
||||
});
|
||||
target = null;
|
||||
}
|
||||
else if (allowExisting)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.14.9.0</Version>
|
||||
<Version>0.1500.0.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -63,6 +63,11 @@
|
||||
<Item file="Content/Items/Gardening/gardeningtools.xml" />
|
||||
<Item file="Content/Items/Gardening/plantproducts.xml" />
|
||||
<Item file="Content/Map/Pirates/PirateItems.xml" />
|
||||
<Item file="Content/Items/Jobgear/Mechanic/mechanic_talent_items.xml" />
|
||||
<Item file="Content/Items/Jobgear/Security/securityofficer_talent_items.xml" />
|
||||
<Item file="Content/Items/Jobgear/Engineer/engineer_talent_items.xml" />
|
||||
<Item file="Content/Items/Jobgear/Medic/medic_talent_items.xml" />
|
||||
<Item file="Content/Items/Jobgear/Captain/captain_talent_items.xml" />
|
||||
<Character file="Content/Characters/Balloon/Balloon.xml" />
|
||||
<Character file="Content/Characters/Carrier/Carrier.xml" />
|
||||
<Character file="Content/Characters/Charybdis/Charybdis.xml" />
|
||||
@@ -147,6 +152,12 @@
|
||||
<Text file="Content/Texts/Korean/KoreanVanilla.xml" />
|
||||
<UIStyle file="Content/UI/style.xml" />
|
||||
<Afflictions file="Content/Afflictions.xml" />
|
||||
<Afflictions file="Content/Talents/Assistant/AfflictionsAssistant.xml" />
|
||||
<Afflictions file="Content/Talents/Captain/AfflictionsCaptain.xml" />
|
||||
<Afflictions file="Content/Talents/Doctor/AfflictionsDoctor.xml" />
|
||||
<Afflictions file="Content/Talents/Engineer/AfflictionsEngineer.xml" />
|
||||
<Afflictions file="Content/Talents/Mechanic/AfflictionsMechanic.xml" />
|
||||
<Afflictions file="Content/Talents/Security/AfflictionsSecurity.xml" />
|
||||
<Structure file="Content/Map/StructurePrefabs.xml" />
|
||||
<Structure file="Content/Map/Outposts/OutpostStructurePrefabs.xml" />
|
||||
<Structure file="Content/Map/Pirates/PirateStructures.xml" />
|
||||
@@ -261,4 +272,11 @@
|
||||
<EnemySubmarine file="Content/Map/EnemySubmarines/DugongPirate.sub"/>
|
||||
<EnemySubmarine file="Content/Map/EnemySubmarines/HumpbackPirate.sub"/>
|
||||
<EnemySubmarine file="Content/Map/EnemySubmarines/Typhon2Pirate.sub"/>
|
||||
<Talents file="Content/Talents/Assistant/TalentsAssistant.xml"/>
|
||||
<Talents file="Content/Talents/Security/TalentsSecurity.xml"/>
|
||||
<Talents file="Content/Talents/Engineer/TalentsEngineer.xml"/>
|
||||
<Talents file="Content/Talents/Mechanic/TalentsMechanic.xml"/>
|
||||
<Talents file="Content/Talents/Captain/TalentsCaptain.xml"/>
|
||||
<Talents file="Content/Talents/Doctor/TalentsDoctor.xml"/>
|
||||
<TalentTrees file="Content/Talents/TalentTrees.xml"/>
|
||||
</contentpackage>
|
||||
@@ -1,7 +1,8 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.Items.Components;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -328,5 +329,8 @@ namespace Barotrauma
|
||||
|
||||
protected virtual void OnStateChanged(AIState from, AIState to) { }
|
||||
protected virtual void OnTargetChanged(AITarget previousTarget, AITarget newTarget) { }
|
||||
|
||||
public virtual void ClientRead(IReadMessage msg) { }
|
||||
public virtual void ServerWrite(IWriteMessage msg) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework;
|
||||
@@ -37,6 +38,12 @@ namespace Barotrauma
|
||||
PreviousState = _state;
|
||||
OnStateChanged(_state, value);
|
||||
_state = value;
|
||||
if (_state == AIState.Attack)
|
||||
{
|
||||
#if CLIENT
|
||||
Character.PlaySound(CharacterSound.SoundType.Attack, maxInterval: 3);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +57,8 @@ namespace Barotrauma
|
||||
private readonly float updateTargetsInterval = 1;
|
||||
private readonly float updateMemoriesInverval = 1;
|
||||
private readonly float attackLimbResetInterval = 2;
|
||||
// Min priority for the memorized targets. The actual value fades gradually, unless kept fresh by selecting the target.
|
||||
private const float minPriority = 10;
|
||||
|
||||
private readonly float avoidLookAheadDistance;
|
||||
|
||||
@@ -394,7 +403,7 @@ namespace Barotrauma
|
||||
public void SelectTarget(AITarget target, float priority)
|
||||
{
|
||||
SelectedAiTarget = target;
|
||||
selectedTargetMemory = GetTargetMemory(target, true);
|
||||
selectedTargetMemory = GetTargetMemory(target, addIfNotFound: true);
|
||||
selectedTargetMemory.Priority = priority;
|
||||
ignoredTargets.Remove(target);
|
||||
}
|
||||
@@ -641,7 +650,7 @@ namespace Barotrauma
|
||||
{
|
||||
Character c = a.Character;
|
||||
if (c.IsDead || c.Removed) { return false; }
|
||||
if (!IsFriendly(Character, c)) { return true; }
|
||||
if (!Character.IsFriendly(c)) { return true; }
|
||||
// Only apply the threshold to friendly characters
|
||||
return a.Damage >= selectedTargetingParams.DamageThreshold;
|
||||
}
|
||||
@@ -976,7 +985,7 @@ namespace Barotrauma
|
||||
Character owner = GetOwner(item);
|
||||
if (owner != null)
|
||||
{
|
||||
if (IsFriendly(Character, owner))
|
||||
if (Character.IsFriendly(owner))
|
||||
{
|
||||
ResetAITarget();
|
||||
State = AIState.Idle;
|
||||
@@ -1337,7 +1346,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
canAttack = Character.CharacterList.All(c => c == Character || !IsFriendly(Character, c) || IsFarEnough(c));
|
||||
canAttack = Character.CharacterList.All(c => c == Character || !Character.IsFriendly(c) || IsFarEnough(c));
|
||||
}
|
||||
if (canAttack)
|
||||
{
|
||||
@@ -1356,7 +1365,7 @@ namespace Barotrauma
|
||||
{
|
||||
hitTarget = limb.character;
|
||||
}
|
||||
if (hitTarget != null && !hitTarget.IsDead && IsFriendly(Character, hitTarget))
|
||||
if (hitTarget != null && !hitTarget.IsDead && Character.IsFriendly(hitTarget))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -1764,7 +1773,7 @@ namespace Barotrauma
|
||||
Character.AnimController.ReleaseStuckLimbs();
|
||||
LatchOntoAI?.DeattachFromBody(reset: true, cooldown: 1);
|
||||
if (attacker == null || attacker.AiTarget == null || attacker.Removed || attacker.IsDead) { return; }
|
||||
bool isFriendly = IsFriendly(Character, attacker);
|
||||
bool isFriendly = Character.IsFriendly(attacker);
|
||||
if (wasLatched)
|
||||
{
|
||||
State = AIState.Escape;
|
||||
@@ -1840,7 +1849,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
AITargetMemory targetMemory = GetTargetMemory(attacker.AiTarget, true);
|
||||
AITargetMemory targetMemory = GetTargetMemory(attacker.AiTarget, addIfNotFound: true);
|
||||
targetMemory.Priority += GetRelativeDamage(attackResult.Damage, Character.Vitality) * AIParams.AggressionHurt;
|
||||
|
||||
// Only allow to react once. Otherwise would attack the target with only a fraction of a cooldown
|
||||
@@ -1884,16 +1893,15 @@ namespace Barotrauma
|
||||
private bool UpdateLimbAttack(float deltaTime, Limb attackingLimb, Vector2 attackSimPos, float distance = -1, Limb targetLimb = null)
|
||||
{
|
||||
if (SelectedAiTarget?.Entity == null) { return false; }
|
||||
|
||||
ActiveAttack = attackingLimb?.attack;
|
||||
|
||||
if (attackingLimb?.attack == null) { return false; }
|
||||
ActiveAttack = attackingLimb.attack;
|
||||
if (wallTarget != null)
|
||||
{
|
||||
// If the selected target is not the wall target, make the wall target the selected target.
|
||||
var aiTarget = wallTarget.Structure.AiTarget;
|
||||
if (aiTarget != null && SelectedAiTarget != aiTarget)
|
||||
{
|
||||
SelectTarget(aiTarget, GetTargetMemory(SelectedAiTarget, true).Priority);
|
||||
SelectTarget(aiTarget, GetTargetMemory(SelectedAiTarget, addIfNotFound: true).Priority);
|
||||
State = AIState.Attack;
|
||||
}
|
||||
}
|
||||
@@ -1902,23 +1910,35 @@ namespace Barotrauma
|
||||
{
|
||||
//simulate attack input to get the character to attack client-side
|
||||
Character.SetInput(InputType.Attack, true, true);
|
||||
#if SERVER
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new object[]
|
||||
if (!ActiveAttack.IsRunning)
|
||||
{
|
||||
#if SERVER
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new object[]
|
||||
{
|
||||
Networking.NetEntityEvent.Type.SetAttackTarget,
|
||||
attackingLimb,
|
||||
(damageTarget as Entity)?.ID ?? Entity.NullEntityID,
|
||||
damageTarget is Character character && targetLimb != null ? Array.IndexOf(character.AnimController.Limbs, targetLimb) : 0,
|
||||
SimPosition.X,
|
||||
SimPosition.Y
|
||||
});
|
||||
});
|
||||
#else
|
||||
Character.PlaySound(CharacterSound.SoundType.Attack, maxInterval: 3);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (attackingLimb.UpdateAttack(deltaTime, attackSimPos, damageTarget, out AttackResult attackResult, distance, targetLimb))
|
||||
{
|
||||
if (damageTarget.Health > 0 && attackResult.Damage > 0)
|
||||
{
|
||||
// Managed to hit a living/non-destroyed target. Increase the priority more if the target is low in health -> dies easily/soon
|
||||
selectedTargetMemory.Priority += GetRelativeDamage(attackResult.Damage, damageTarget.Health) * AIParams.AggressionGreed;
|
||||
float greed = AIParams.AggressionGreed;
|
||||
if (!(damageTarget is Character))
|
||||
{
|
||||
// Halve the greed for attacking non-characters.
|
||||
greed /= 2;
|
||||
}
|
||||
selectedTargetMemory.Priority += GetRelativeDamage(attackResult.Damage, damageTarget.Health) * greed;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2125,6 +2145,9 @@ namespace Barotrauma
|
||||
string targetingTag = null;
|
||||
if (targetCharacter != null)
|
||||
{
|
||||
// ignore if target is tagged to be explicitly ignored (Feign Death)
|
||||
if (targetCharacter.HasAbilityFlag(AbilityFlags.IgnoredByEnemyAI)) { continue; }
|
||||
|
||||
if (targetCharacter.IsDead)
|
||||
{
|
||||
targetingTag = "dead";
|
||||
@@ -2139,7 +2162,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsFriendly(Character, targetCharacter))
|
||||
if (Character.IsFriendly(targetCharacter))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -2449,7 +2472,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (otherCharacter == character) { continue; }
|
||||
if (otherCharacter.AIController?.SelectedAiTarget != aiTarget) { continue; }
|
||||
if (!IsFriendly(character, otherCharacter)) { continue; }
|
||||
if (!character.IsFriendly(otherCharacter)) { continue; }
|
||||
valueModifier /= 2;
|
||||
}
|
||||
}
|
||||
@@ -2469,7 +2492,7 @@ namespace Barotrauma
|
||||
// -> just ignore the distance and attack whatever has the highest priority
|
||||
dist = Math.Max(dist, 100.0f);
|
||||
|
||||
AITargetMemory targetMemory = GetTargetMemory(aiTarget, true);
|
||||
AITargetMemory targetMemory = GetTargetMemory(aiTarget, addIfNotFound: true);
|
||||
if (Character.CurrentHull != null && Math.Abs(toTarget.Y) > Character.CurrentHull.Size.Y)
|
||||
{
|
||||
// Inside the sub, treat objects that are up or down, as they were farther away.
|
||||
@@ -2527,7 +2550,7 @@ namespace Barotrauma
|
||||
// Don't target items that we own.
|
||||
// This is a rare case, and almost entirely related to Humanhusks, so let's check it last to reduce unnecessary checks (although the check shouldn't be expensive)
|
||||
if (owner == character) { continue; }
|
||||
if (owner != null && (IsFriendly(Character, owner) || owner.AiTarget != null && ignoredTargets.Contains(owner.AiTarget)))
|
||||
if (owner != null && (Character.IsFriendly(owner) || owner.AiTarget != null && ignoredTargets.Contains(owner.AiTarget)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -2599,7 +2622,7 @@ namespace Barotrauma
|
||||
wall = wallTarget?.Structure;
|
||||
}
|
||||
// The target is not a wall or it's not the same as we are attached to -> release
|
||||
bool releaseTarget = wall == null || (!wall.Bodies.Contains(LatchOntoAI.AttachJoints[0].BodyB) && wall.Submarine?.PhysicsBody?.FarseerBody != LatchOntoAI.AttachJoints[0].BodyB);
|
||||
bool releaseTarget = wall?.Bodies == null || (!wall.Bodies.Contains(LatchOntoAI.AttachJoints[0].BodyB) && wall.Submarine?.PhysicsBody?.FarseerBody != LatchOntoAI.AttachJoints[0].BodyB);
|
||||
if (!releaseTarget)
|
||||
{
|
||||
for (int i = 0; i < wall.Sections.Length; i++)
|
||||
@@ -2847,10 +2870,15 @@ namespace Barotrauma
|
||||
{
|
||||
if (addIfNotFound)
|
||||
{
|
||||
memory = new AITargetMemory(target, 10);
|
||||
memory = new AITargetMemory(target, minPriority);
|
||||
targetMemories.Add(target, memory);
|
||||
}
|
||||
}
|
||||
if (addIfNotFound)
|
||||
{
|
||||
// Keep the memory alive.
|
||||
memory.Priority = Math.Max(memory.Priority, minPriority);
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -3014,7 +3042,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!onlyExisting && !tempParams.ContainsKey(tag))
|
||||
{
|
||||
if (AIParams.TryAddNewTarget(tag, state, priority ?? 100, out targetParams))
|
||||
if (AIParams.TryAddNewTarget(tag, state, priority ?? minPriority, out targetParams))
|
||||
{
|
||||
tempParams.Add(tag, targetParams);
|
||||
}
|
||||
@@ -3051,6 +3079,7 @@ namespace Barotrauma
|
||||
ChangeParams(target.SpeciesName, state, priority);
|
||||
if (target.IsHuman)
|
||||
{
|
||||
priority = GetTargetParams("human")?.Priority;
|
||||
// Target also items, because if we are blind and the target doesn't move, we can only perceive the target when it uses items
|
||||
if (state == AIState.Attack || state == AIState.Escape)
|
||||
{
|
||||
@@ -3061,20 +3090,19 @@ namespace Barotrauma
|
||||
{
|
||||
// If the target is shooting from the submarine, we might not perceive it because it doesn't move.
|
||||
// --> Target the submarine too.
|
||||
if (target.Submarine != null && (canAttackDoors || canAttackWalls))
|
||||
if (target.Submarine != null && Character.Submarine == null && (canAttackDoors || canAttackWalls))
|
||||
{
|
||||
ChangeParams("room", state, priority);
|
||||
ChangeParams("room", state, priority * 0.1f);
|
||||
if (canAttackWalls)
|
||||
{
|
||||
ChangeParams("wall", state, priority);
|
||||
ChangeParams("wall", state, priority * 0.1f);
|
||||
}
|
||||
if (canAttackDoors)
|
||||
{
|
||||
ChangeParams("door", state, priority);
|
||||
ChangeParams("door", state, priority * 0.1f);
|
||||
}
|
||||
}
|
||||
ChangeParams("provocative", state, priority, onlyExisting: true);
|
||||
ChangeParams("light", state, priority, onlyExisting: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3306,7 +3334,17 @@ namespace Barotrauma
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool IsFriendly(Character me, Character other) => other.SpeciesName == me.SpeciesName || other.Params.CompareGroup(me.Params.Group);
|
||||
public override void ServerWrite(IWriteMessage msg)
|
||||
{
|
||||
msg.Write((byte)State);
|
||||
PetBehavior?.ServerWrite(msg);
|
||||
}
|
||||
|
||||
public override void ClientRead(IReadMessage msg)
|
||||
{
|
||||
State = (AIState)msg.ReadByte();
|
||||
PetBehavior?.ClientRead(msg);
|
||||
}
|
||||
}
|
||||
|
||||
//the "memory" of the Character
|
||||
|
||||
@@ -915,10 +915,10 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void ReportProblem(Character reporter, Order order)
|
||||
public static void ReportProblem(Character reporter, Order order, Hull targetHull = null)
|
||||
{
|
||||
if (reporter == null || order == null) { return; }
|
||||
var visibleHulls = new List<Hull>(reporter.GetVisibleHulls());
|
||||
var visibleHulls = targetHull is null ? new List<Hull>(reporter.GetVisibleHulls()) : new List<Hull> { targetHull };
|
||||
foreach (var hull in visibleHulls)
|
||||
{
|
||||
PropagateHullSafety(reporter, hull);
|
||||
@@ -1415,7 +1415,7 @@ namespace Barotrauma
|
||||
if (GameMain.GameSession?.Campaign?.Map?.CurrentLocation != null)
|
||||
{
|
||||
var reputationLoss = damageAmount * Reputation.ReputationLossPerWallDamage;
|
||||
GameMain.GameSession.Campaign.Map.CurrentLocation.Reputation.Value -= reputationLoss;
|
||||
GameMain.GameSession.Campaign.Map.CurrentLocation.Reputation.AddReputation(-reputationLoss);
|
||||
}
|
||||
|
||||
if (accumulatedDamage <= WarningThreshold) { return; }
|
||||
@@ -1510,7 +1510,7 @@ namespace Barotrauma
|
||||
var reputationLoss = MathHelper.Clamp(
|
||||
(item.Prefab.GetMinPrice() ?? 0) * Reputation.ReputationLossPerStolenItemPrice,
|
||||
Reputation.MinReputationLossPerStolenItem, Reputation.MaxReputationLossPerStolenItem);
|
||||
GameMain.GameSession.Campaign.Map.CurrentLocation.Reputation.Value -= reputationLoss;
|
||||
GameMain.GameSession.Campaign.Map.CurrentLocation.Reputation.AddReputation(-reputationLoss);
|
||||
}
|
||||
item.StolenDuringRound = true;
|
||||
otherCharacter.Speak(TextManager.Get("dialogstealwarning"), null, Rand.Range(0.5f, 1.0f), "thief", 10.0f);
|
||||
@@ -1971,13 +1971,13 @@ namespace Barotrauma
|
||||
if (c.Removed) { continue; }
|
||||
if (c.TeamID != Character.TeamID) { continue; }
|
||||
if (c.IsIncapacitated) { continue; }
|
||||
other = c;
|
||||
if (c.IsPlayer)
|
||||
{
|
||||
if (c.SelectedConstruction == target.Item)
|
||||
{
|
||||
// If the other character is player, don't try to operate
|
||||
return true;
|
||||
other = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (c.AIController is HumanAIController operatingAI)
|
||||
@@ -1991,7 +1991,8 @@ namespace Barotrauma
|
||||
if (!isOrder && isTargetOrdered)
|
||||
{
|
||||
// If the other bot is ordered to operate the item, let him do it, unless we are ordered too
|
||||
return true;
|
||||
other = c;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2012,18 +2013,20 @@ namespace Barotrauma
|
||||
// Steering is hard-coded -> cannot use the required skills collection defined in the xml
|
||||
if (Character.GetSkillLevel("helm") <= c.GetSkillLevel("helm"))
|
||||
{
|
||||
return true;
|
||||
other = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (target.DegreeOfSuccess(Character) <= target.DegreeOfSuccess(c))
|
||||
{
|
||||
return true;
|
||||
other = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return other != null;
|
||||
bool IsOrderedToOperateThis(AIController ai) => ai is HumanAIController humanAI && humanAI.ObjectiveManager.CurrentOrder is AIObjectiveOperateItem operateOrder && operateOrder.Component.Item == target.Item;
|
||||
}
|
||||
|
||||
|
||||
@@ -161,12 +161,13 @@ namespace Barotrauma
|
||||
private Vector2 CalculateSteeringSeek(Vector2 target, float weight, Func<PathNode, bool> startNodeFilter = null, Func<PathNode, bool> endNodeFilter = null, Func<PathNode, bool> nodeFilter = null, bool checkVisibility = true)
|
||||
{
|
||||
Vector2 targetDiff = target - currentTarget;
|
||||
if (currentPath != null && currentPath.Nodes.Any())
|
||||
if (currentPath != null && currentPath.Nodes.Any() && character.Submarine != null)
|
||||
{
|
||||
//current path calculated relative to a different sub than where the character is now
|
||||
//target in a different sub than where the character is now
|
||||
//take that into account when calculating if the target has moved
|
||||
Submarine currentPathSub = currentPath?.Nodes.First().Submarine;
|
||||
if (currentPathSub != character.Submarine && character.Submarine != null)
|
||||
Submarine currentPathSub = currentPath?.CurrentNode?.Submarine;
|
||||
if (currentPathSub == character.Submarine) { currentPathSub = currentPath?.Nodes.LastOrDefault()?.Submarine; }
|
||||
if (currentPathSub != character.Submarine && targetDiff.LengthSquared() > 1 && currentPathSub != null)
|
||||
{
|
||||
Vector2 subDiff = character.Submarine.SimPosition - currentPathSub.SimPosition;
|
||||
targetDiff += subDiff;
|
||||
|
||||
@@ -101,11 +101,11 @@ namespace Barotrauma
|
||||
|
||||
public enum CombatMode
|
||||
{
|
||||
Defensive,
|
||||
Offensive,
|
||||
Arrest,
|
||||
Retreat,
|
||||
None
|
||||
Defensive, // Use weapons against the enemy, but try to retreat to a safe place
|
||||
Offensive, // Engage the enemy and keep attacking it
|
||||
Arrest, // Try to arrest the enemy without using lethal weapons (stunning + handcuffs)
|
||||
Retreat, // Run to a safe place without attacking the target
|
||||
None // Don't use
|
||||
}
|
||||
|
||||
public CombatMode Mode { get; private set; }
|
||||
@@ -958,14 +958,15 @@ namespace Barotrauma
|
||||
}
|
||||
if (reloadTimer > 0) { return; }
|
||||
if (holdFireCondition != null && holdFireCondition()) { return; }
|
||||
float sqrDist = Vector2.DistanceSquared(character.Position, Enemy.Position);
|
||||
sqrDistance = Vector2.DistanceSquared(character.WorldPosition, Enemy.WorldPosition);
|
||||
distanceTimer = distanceCheckInterval;
|
||||
if (WeaponComponent is MeleeWeapon meleeWeapon)
|
||||
{
|
||||
bool closeEnough = true;
|
||||
float sqrRange = meleeWeapon.Range * meleeWeapon.Range;
|
||||
if (character.AnimController.InWater)
|
||||
{
|
||||
if (sqrDist > sqrRange)
|
||||
if (sqrDistance > sqrRange)
|
||||
{
|
||||
closeEnough = false;
|
||||
}
|
||||
@@ -1003,7 +1004,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (WeaponComponent is RepairTool repairTool)
|
||||
{
|
||||
if (sqrDist > repairTool.Range * repairTool.Range) { return; }
|
||||
if (sqrDistance > repairTool.Range * repairTool.Range) { return; }
|
||||
}
|
||||
float aimFactor = MathHelper.PiOver2 * (1 - AimAccuracy);
|
||||
if (VectorExtensions.Angle(VectorExtensions.Forward(Weapon.body.TransformedRotation), Enemy.Position - Weapon.Position) < MathHelper.PiOver4 + aimFactor)
|
||||
|
||||
@@ -53,9 +53,13 @@ namespace Barotrauma
|
||||
distanceFactor = 1;
|
||||
}
|
||||
float severity = AIObjectiveExtinguishFires.GetFireSeverity(targetHull);
|
||||
if (severity > 0.5f && !isOrder)
|
||||
if (severity > 0.75f && !isOrder &&
|
||||
targetHull.RoomName != null &&
|
||||
!targetHull.RoomName.Contains("reactor", StringComparison.OrdinalIgnoreCase) &&
|
||||
!targetHull.RoomName.Contains("engine", StringComparison.OrdinalIgnoreCase) &&
|
||||
!targetHull.RoomName.Contains("command", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Ignore severe fires unless ordered. (Let the fire drain all the oxygen instead).
|
||||
// Ignore severe fires to prevent casualities unless ordered to extinguish.
|
||||
Priority = 0;
|
||||
Abandon = true;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// 0-1 based on the horizontal size of all of the fires in the hull.
|
||||
/// </summary>
|
||||
public static float GetFireSeverity(Hull hull) => MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, Math.Min(hull.Rect.Width, 1000), hull.FireSources.Sum(fs => fs.Size.X)));
|
||||
public static float GetFireSeverity(Hull hull) => MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, 500, hull.FireSources.Sum(fs => fs.Size.X)));
|
||||
|
||||
protected override IEnumerable<Hull> GetList() => Hull.hullList;
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace Barotrauma
|
||||
if (target.CurrentHull == null) { return false; }
|
||||
if (HumanAIController.IsFriendly(character, target)) { return false; }
|
||||
if (!character.Submarine.IsConnectedTo(target.Submarine)) { return false; }
|
||||
if (target.HasAbilityFlag(AbilityFlags.IgnoredByEnemyAI)) { return false; }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,20 @@ namespace Barotrauma
|
||||
};
|
||||
},
|
||||
onAbandon: () => Abandon = true,
|
||||
onCompleted: () => RemoveSubObjective(ref getDivingGear));
|
||||
onCompleted: () =>
|
||||
{
|
||||
RemoveSubObjective(ref getDivingGear);
|
||||
if (gearTag == HEAVY_DIVING_GEAR && HumanAIController.HasItem(character, LIGHT_DIVING_GEAR, out IEnumerable<Item> masks, requireEquipped: true))
|
||||
{
|
||||
foreach (Item mask in masks)
|
||||
{
|
||||
if (mask != targetItem)
|
||||
{
|
||||
character.Inventory.TryPutItem(mask, character, CharacterInventory.anySlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -71,9 +84,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
if (HumanAIController.HasItem(character, "oxygensource", out _, conditionPercentage: min))
|
||||
if (HumanAIController.HasItem(character, OXYGEN_SOURCE, out _, conditionPercentage: min))
|
||||
{
|
||||
character.Speak(TextManager.Get("dialogswappingoxygentank"), null, 0, "swappingoxygentank", 30.0f);
|
||||
if (character.Inventory.FindAllItems(i => i.HasTag(OXYGEN_SOURCE) && i.Condition > min).Count == 1)
|
||||
{
|
||||
character.Speak(TextManager.Get("dialoglastoxygentank"), null, 0.0f, "dialoglastoxygentank", 30.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -105,7 +122,7 @@ namespace Barotrauma
|
||||
onAbandon: () =>
|
||||
{
|
||||
Abandon = true;
|
||||
if (remainingTanks > 0 && !HumanAIController.HasItem(character, "oxygensource", out _, conditionPercentage: 0.01f))
|
||||
if (remainingTanks > 0 && !HumanAIController.HasItem(character, OXYGEN_SOURCE, out _, conditionPercentage: 0.01f))
|
||||
{
|
||||
character.Speak(TextManager.Get("dialogcantfindtoxygen"), null, 0, "cantfindoxygen", 30.0f);
|
||||
}
|
||||
@@ -121,7 +138,7 @@ namespace Barotrauma
|
||||
int ReportOxygenTankCount()
|
||||
{
|
||||
if (character.Submarine != Submarine.MainSub) { return 1; }
|
||||
int remainingOxygenTanks = Submarine.MainSub.GetItems(false).Count(i => i.HasTag("oxygensource") && i.Condition > 1);
|
||||
int remainingOxygenTanks = Submarine.MainSub.GetItems(false).Count(i => i.HasTag(OXYGEN_SOURCE) && i.Condition > 1);
|
||||
if (remainingOxygenTanks == 0)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogOutOfOxygenTanks"), null, 0.0f, "outofoxygentanks", 30.0f);
|
||||
@@ -136,17 +153,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns false only when no inventory can be found from the item.
|
||||
/// </summary>
|
||||
public static bool EjectEmptyTanks(Character actor, Item target, out IEnumerable<Item> containedItems)
|
||||
{
|
||||
containedItems = target.OwnInventory?.AllItems;
|
||||
if (containedItems == null) { return false; }
|
||||
AIController.UnequipEmptyItems(actor, target);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
@@ -242,9 +242,8 @@ namespace Barotrauma
|
||||
if (!searchingNewHull)
|
||||
{
|
||||
//find all available hulls first
|
||||
FindTargetHulls();
|
||||
searchingNewHull = true;
|
||||
return;
|
||||
FindTargetHulls();
|
||||
}
|
||||
else if (targetHulls.Any())
|
||||
{
|
||||
@@ -255,11 +254,10 @@ namespace Barotrauma
|
||||
var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, errorMsgStr: null, nodeFilter: node =>
|
||||
{
|
||||
if (node.Waypoint.CurrentHull == null) { return false; }
|
||||
// Check that there is no unsafe or forbidden hulls on the way to the target
|
||||
// Check that there is no unsafe hulls on the way to the target
|
||||
if (node.Waypoint.CurrentHull != character.CurrentHull && HumanAIController.UnsafeHulls.Contains(node.Waypoint.CurrentHull)) { return false; }
|
||||
if (isCurrentHullAllowed && IsForbidden(node.Waypoint.CurrentHull)) { return false; }
|
||||
return true;
|
||||
});
|
||||
}, endNodeFilter: node => !isCurrentHullAllowed | !IsForbidden(node.Waypoint.CurrentHull));
|
||||
if (path.Unreachable)
|
||||
{
|
||||
//can't go to this room, remove it from the list and try another room
|
||||
@@ -271,30 +269,19 @@ namespace Barotrauma
|
||||
SetTargetTimerLow();
|
||||
return;
|
||||
}
|
||||
character.AIController.SelectTarget(currentTarget.AiTarget);
|
||||
PathSteering.SetPath(path);
|
||||
SetTargetTimerNormal();
|
||||
searchingNewHull = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Couldn't find a target for some reason -> reset
|
||||
// Couldn't find a valid hull
|
||||
SetTargetTimerHigh();
|
||||
searchingNewHull = false;
|
||||
}
|
||||
|
||||
if (currentTarget != null)
|
||||
{
|
||||
character.AIController.SelectTarget(currentTarget.AiTarget);
|
||||
string errorMsg = null;
|
||||
#if DEBUG
|
||||
bool isRoomNameFound = currentTarget.DisplayName != null;
|
||||
errorMsg = "(Character " + character.Name + " idling, target " + (isRoomNameFound ? currentTarget.DisplayName : currentTarget.ToString()) + ")";
|
||||
#endif
|
||||
var path = PathSteering.PathFinder.FindPath(character.SimPosition, currentTarget.SimPosition, errorMsgStr: errorMsg, nodeFilter: node => node.Waypoint.CurrentHull != null);
|
||||
PathSteering.SetPath(path);
|
||||
}
|
||||
SetTargetTimerNormal();
|
||||
}
|
||||
newTargetTimer -= deltaTime;
|
||||
|
||||
if (!character.IsClimbing && IsSteeringFinished())
|
||||
{
|
||||
Wander(deltaTime);
|
||||
|
||||
@@ -141,6 +141,7 @@ namespace Barotrauma
|
||||
public Entity TargetEntity;
|
||||
public ItemComponent TargetItemComponent;
|
||||
public readonly bool UseController;
|
||||
public readonly string[] ControllerTags;
|
||||
public Controller ConnectedController;
|
||||
|
||||
public Character OrderGiver;
|
||||
@@ -309,6 +310,7 @@ namespace Barotrauma
|
||||
color = orderElement.GetAttributeColor("color");
|
||||
FadeOutTime = orderElement.GetAttributeFloat("fadeouttime", 0.0f);
|
||||
UseController = orderElement.GetAttributeBool("usecontroller", false);
|
||||
ControllerTags = orderElement.GetAttributeStringArray("controllertags", new string[0]);
|
||||
TargetAllCharacters = orderElement.GetAttributeBool("targetallcharacters", false);
|
||||
AppropriateJobs = orderElement.GetAttributeStringArray("appropriatejobs", new string[0]);
|
||||
Options = orderElement.GetAttributeStringArray("options", new string[0]);
|
||||
@@ -380,6 +382,7 @@ namespace Barotrauma
|
||||
SymbolSprite = prefab.SymbolSprite;
|
||||
Color = prefab.Color;
|
||||
UseController = prefab.UseController;
|
||||
ControllerTags = prefab.ControllerTags;
|
||||
TargetAllCharacters = prefab.TargetAllCharacters;
|
||||
AppropriateJobs = prefab.AppropriateJobs;
|
||||
FadeOutTime = prefab.FadeOutTime;
|
||||
@@ -399,7 +402,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (UseController)
|
||||
{
|
||||
ConnectedController = targetItem.Item?.FindController();
|
||||
ConnectedController = targetItem.Item?.FindController(tags: ControllerTags);
|
||||
if (ConnectedController == null)
|
||||
{
|
||||
DebugConsole.AddWarning("AI: Tried to use a controller for operating an item, but couldn't find any.");
|
||||
@@ -450,19 +453,37 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
public string GetChatMessage(string targetCharacterName, string targetRoomName, bool givingOrderToSelf, string orderOption = "")
|
||||
public string GetChatMessage(string targetCharacterName, string targetRoomName, bool givingOrderToSelf, string orderOption = "", int? priority = null)
|
||||
{
|
||||
orderOption ??= "";
|
||||
|
||||
string messageTag = (givingOrderToSelf && !TargetAllCharacters ? "OrderDialogSelf." : "OrderDialog.") + Identifier;
|
||||
if (Identifier != "dismissed" && !string.IsNullOrEmpty(orderOption)) { messageTag += "." + orderOption; }
|
||||
|
||||
if (targetCharacterName == null) { targetCharacterName = ""; }
|
||||
if (targetRoomName == null) { targetRoomName = ""; }
|
||||
string msg = TextManager.GetWithVariables(messageTag, new string[2] { "[name]", "[roomname]" }, new string[2] { targetCharacterName, targetRoomName }, new bool[2] { false, true }, true);
|
||||
if (msg == null) { return ""; }
|
||||
|
||||
return msg;
|
||||
priority ??= CharacterInfo.HighestManualOrderPriority;
|
||||
// If the order has a lesser priority, it means we are rearranging character orders
|
||||
if (!TargetAllCharacters && priority != CharacterInfo.HighestManualOrderPriority && Identifier != "dismissed")
|
||||
{
|
||||
return TextManager.GetWithVariable("rearrangedorders", "[name]", targetCharacterName ?? string.Empty, returnNull: true) ?? string.Empty;
|
||||
}
|
||||
string messageTag = $"{(givingOrderToSelf && !TargetAllCharacters ? "OrderDialogSelf" : "OrderDialog")}";
|
||||
messageTag += $".{Identifier}";
|
||||
if (!string.IsNullOrEmpty(orderOption))
|
||||
{
|
||||
if (Identifier != "dismissed")
|
||||
{
|
||||
messageTag += $".{orderOption}";
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] splitOption = orderOption.Split('.');
|
||||
if (splitOption.Length > 0)
|
||||
{
|
||||
messageTag += $".{splitOption[0]}";
|
||||
}
|
||||
}
|
||||
}
|
||||
string msg = TextManager.GetWithVariables(messageTag,
|
||||
new string[2] { "[name]", "[roomname]" },
|
||||
new string[2] { targetCharacterName ?? string.Empty, targetRoomName ?? string.Empty },
|
||||
formatCapitals: new bool[2] { false, true },
|
||||
returnNull: true);
|
||||
return msg ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -505,7 +526,7 @@ namespace Barotrauma
|
||||
if (item.NonInteractable) { continue; }
|
||||
if (ItemComponentType != null && item.Components.None(c => c.GetType() == ItemComponentType)) { continue; }
|
||||
Controller controller = null;
|
||||
if (UseController && !item.TryFindController(out controller)) { continue; }
|
||||
if (UseController && !item.TryFindController(out controller, tags: ControllerTags)) { continue; }
|
||||
if (interactableFor != null && (!item.IsInteractable(interactableFor) || (UseController && !controller.Item.IsInteractable(interactableFor)))) { continue; }
|
||||
matchingItems.Add(item);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user