Unstable 0.1400.0.0
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
abstract partial class AIObjective
|
||||||
|
{
|
||||||
|
public static Sprite GetSprite(string identifier, string option, Entity targetEntity)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(identifier))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
identifier = identifier.RemoveWhitespace();
|
||||||
|
if (Order.Prefabs.TryGetValue(identifier, out Order orderPrefab))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(option) && orderPrefab.OptionSprites.TryGetValue(option, out var optionSprite))
|
||||||
|
{
|
||||||
|
return optionSprite;
|
||||||
|
}
|
||||||
|
if (targetEntity is Item targetItem && targetItem.Prefab.MinimapIcon != null)
|
||||||
|
{
|
||||||
|
return targetItem.Prefab.MinimapIcon;
|
||||||
|
}
|
||||||
|
return orderPrefab.SymbolSprite;
|
||||||
|
}
|
||||||
|
return GUI.Style.GetComponentStyle($"{identifier}objectiveicon")?.GetDefaultSprite();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sprite GetSprite()
|
||||||
|
{
|
||||||
|
return GetSprite(Identifier, Option, (this as AIObjectiveOperateItem)?.OperateTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -102,11 +102,13 @@ namespace Barotrauma
|
|||||||
set { chromaticAberrationStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
set { chromaticAberrationStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Color GrainColor { get; set; }
|
||||||
|
|
||||||
private float grainStrength;
|
private float grainStrength;
|
||||||
public float GrainStrength
|
public float GrainStrength
|
||||||
{
|
{
|
||||||
get => grainStrength;
|
get => grainStrength;
|
||||||
set => grainStrength = MathHelper.Clamp(value, 0.0f, 1.0f);
|
set => grainStrength = Math.Max(0, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<ParticleEmitter> bloodEmitters = new List<ParticleEmitter>();
|
private readonly List<ParticleEmitter> bloodEmitters = new List<ParticleEmitter>();
|
||||||
@@ -859,7 +861,14 @@ namespace Barotrauma
|
|||||||
Color nameColor = Color.White;
|
Color nameColor = Color.White;
|
||||||
if (Controlled != null && TeamID != Controlled.TeamID)
|
if (Controlled != null && TeamID != Controlled.TeamID)
|
||||||
{
|
{
|
||||||
nameColor = TeamID == CharacterTeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
|
if (TeamID == CharacterTeamType.FriendlyNPC)
|
||||||
|
{
|
||||||
|
nameColor = UniqueNameColor ?? Color.SkyBlue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nameColor = GUI.Style.Red;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
|
if (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ namespace Barotrauma
|
|||||||
float alpha = GetDistanceBasedIconAlpha(brokenItem);
|
float alpha = GetDistanceBasedIconAlpha(brokenItem);
|
||||||
if (alpha <= 0.0f) continue;
|
if (alpha <= 0.0f) continue;
|
||||||
GUI.DrawIndicator(spriteBatch, brokenItem.DrawPosition, cam, 100.0f, GUI.BrokenIcon,
|
GUI.DrawIndicator(spriteBatch, brokenItem.DrawPosition, cam, 100.0f, GUI.BrokenIcon,
|
||||||
Color.Lerp(GUI.Style.Red, GUI.Style.Orange * 0.5f, brokenItem.Condition / brokenItem.MaxCondition) * alpha);
|
Color.Lerp(GUI.Style.Red, GUI.Style.Orange * 0.5f, brokenItem.Condition / brokenItem.MaxCondition) * alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
float GetDistanceBasedIconAlpha(ISpatialEntity target, float maxDistance = 1000.0f)
|
float GetDistanceBasedIconAlpha(ISpatialEntity target, float maxDistance = 1000.0f)
|
||||||
@@ -341,7 +341,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld)
|
if (!GUI.DisableItemHighlights && !Inventory.DraggingItemToWorld)
|
||||||
{
|
{
|
||||||
bool shiftDown = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift);
|
bool shiftDown = PlayerInput.IsShiftDown();
|
||||||
if (shouldRecreateHudTexts || heldDownShiftWhenGotHudTexts != shiftDown)
|
if (shouldRecreateHudTexts || heldDownShiftWhenGotHudTexts != shiftDown)
|
||||||
{
|
{
|
||||||
shouldRecreateHudTexts = true;
|
shouldRecreateHudTexts = true;
|
||||||
@@ -391,7 +391,16 @@ namespace Barotrauma
|
|||||||
if (npc.CampaignInteractionType == CampaignMode.InteractionType.None || npc.Submarine != character.Submarine || npc.IsDead || npc.IsIncapacitated) { continue; }
|
if (npc.CampaignInteractionType == CampaignMode.InteractionType.None || npc.Submarine != character.Submarine || npc.IsDead || npc.IsIncapacitated) { continue; }
|
||||||
|
|
||||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionIcon." + npc.CampaignInteractionType);
|
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionIcon." + npc.CampaignInteractionType);
|
||||||
GUI.DrawIndicator(spriteBatch, npc.WorldPosition, cam, 500.0f, iconStyle.GetDefaultSprite(), iconStyle.Color);
|
GUI.DrawIndicator(spriteBatch, npc.WorldPosition, cam, npc.CurrentHull == Character.Controlled.CurrentHull ? 500.0f : 100.0f, iconStyle.GetDefaultSprite(), iconStyle.Color);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Item item in Item.ItemList)
|
||||||
|
{
|
||||||
|
if (item.IconStyle is null || item.Submarine != character.Submarine) { continue; }
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -291,8 +291,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case ServerNetObject.ENTITY_EVENT:
|
case ServerNetObject.ENTITY_EVENT:
|
||||||
|
int eventType = msg.ReadRangedInteger(0, 9);
|
||||||
int eventType = msg.ReadRangedInteger(0, 6);
|
|
||||||
switch (eventType)
|
switch (eventType)
|
||||||
{
|
{
|
||||||
case 0: //NetEntityEvent.Type.InventoryState
|
case 0: //NetEntityEvent.Type.InventoryState
|
||||||
@@ -354,56 +353,88 @@ namespace Barotrauma
|
|||||||
info?.SetSkillLevel(skillIdentifier, skillLevel, Position + Vector2.UnitY * 150.0f);
|
info?.SetSkillLevel(skillIdentifier, skillLevel, Position + Vector2.UnitY * 150.0f);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4: //NetEntityEvent.Type.ExecuteAttack
|
case 4: // NetEntityEvent.Type.SetAttackTarget
|
||||||
|
case 5: //NetEntityEvent.Type.ExecuteAttack
|
||||||
int attackLimbIndex = msg.ReadByte();
|
int attackLimbIndex = msg.ReadByte();
|
||||||
UInt16 targetEntityID = msg.ReadUInt16();
|
UInt16 targetEntityID = msg.ReadUInt16();
|
||||||
int targetLimbIndex = msg.ReadByte();
|
int targetLimbIndex = msg.ReadByte();
|
||||||
|
|
||||||
//255 = entity already removed, no need to do anything
|
//255 = entity already removed, no need to do anything
|
||||||
if (attackLimbIndex == 255 || Removed) { break; }
|
if (attackLimbIndex == 255 || Removed) { break; }
|
||||||
|
Vector2 targetSimPos = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||||
if (attackLimbIndex >= AnimController.Limbs.Length)
|
if (attackLimbIndex >= AnimController.Limbs.Length)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})");
|
DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Limb attackLimb = AnimController.Limbs[attackLimbIndex];
|
Limb attackLimb = AnimController.Limbs[attackLimbIndex];
|
||||||
Limb targetLimb = null;
|
Limb targetLimb = null;
|
||||||
if (!(FindEntityByID(targetEntityID) is IDamageable targetEntity))
|
if (!(FindEntityByID(targetEntityID) is IDamageable targetEntity))
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target entity not found (ID {targetEntityID})");
|
DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Target entity not found (ID {targetEntityID})");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (targetEntity is Character targetCharacter)
|
if (targetEntity is Character targetCharacter)
|
||||||
{
|
{
|
||||||
if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length)
|
if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Received invalid ExecuteAttack message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})");
|
DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
|
targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
|
||||||
}
|
}
|
||||||
if (attackLimb?.attack != null)
|
if (attackLimb?.attack != null)
|
||||||
{
|
{
|
||||||
attackLimb.ExecuteAttack(targetEntity, targetLimb, out _);
|
if (eventType == 4)
|
||||||
|
{
|
||||||
|
SetAttackTarget(attackLimb, targetEntity, targetSimPos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
attackLimb.ExecuteAttack(targetEntity, targetLimb, out _);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 5: //NetEntityEvent.Type.AssignCampaignInteraction
|
case 6: //NetEntityEvent.Type.AssignCampaignInteraction
|
||||||
byte campaignInteractionType = msg.ReadByte();
|
byte campaignInteractionType = msg.ReadByte();
|
||||||
(GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType);
|
(GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType);
|
||||||
break;
|
break;
|
||||||
case 6: //NetEntityEvent.Type.ObjectiveManagerOrderState
|
case 7: //NetEntityEvent.Type.ObjectiveManagerState
|
||||||
bool properData = msg.ReadBoolean();
|
// 1 = order, 2 = objective
|
||||||
if (!properData) { break; }
|
int msgType = msg.ReadRangedInteger(0, 2);
|
||||||
int orderIndex = msg.ReadRangedInteger(0, Order.PrefabList.Count);
|
if (msgType == 0) { break; }
|
||||||
var orderPrefab = Order.PrefabList[orderIndex];
|
bool validData = msg.ReadBoolean();
|
||||||
string option = null;
|
if (!validData) { break; }
|
||||||
if (orderPrefab.HasOptions)
|
if (msgType == 1)
|
||||||
{
|
{
|
||||||
int optionIndex = msg.ReadRangedInteger(0, orderPrefab.Options.Length);
|
int orderIndex = msg.ReadRangedInteger(0, Order.PrefabList.Count);
|
||||||
option = orderPrefab.Options[optionIndex];
|
var orderPrefab = Order.PrefabList[orderIndex];
|
||||||
|
string option = null;
|
||||||
|
if (orderPrefab.HasOptions)
|
||||||
|
{
|
||||||
|
int optionIndex = msg.ReadRangedInteger(0, orderPrefab.Options.Length);
|
||||||
|
option = orderPrefab.Options[optionIndex];
|
||||||
|
}
|
||||||
|
GameMain.GameSession?.CrewManager?.SetOrderHighlight(this, orderPrefab.Identifier, option);
|
||||||
|
}
|
||||||
|
else if (msgType == 2)
|
||||||
|
{
|
||||||
|
string identifier = msg.ReadString();
|
||||||
|
string option = msg.ReadString();
|
||||||
|
ushort objectiveTargetEntityId = msg.ReadUInt16();
|
||||||
|
var objectiveTargetEntity = FindEntityByID(objectiveTargetEntityId);
|
||||||
|
GameMain.GameSession?.CrewManager?.CreateObjectiveIcon(this, identifier, option, objectiveTargetEntity);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8: //NetEntityEvent.Type.TeamChange
|
||||||
|
byte newTeamId = msg.ReadByte();
|
||||||
|
ChangeTeam((CharacterTeamType)newTeamId);
|
||||||
|
break;
|
||||||
|
case 9: //NetEntityEvent.Type.AddToCrew
|
||||||
|
GameMain.GameSession.CrewManager.AddCharacter(this);
|
||||||
|
foreach (Item item in Inventory.AllItems)
|
||||||
|
{
|
||||||
|
item.AllowStealing = true;
|
||||||
}
|
}
|
||||||
GameMain.GameSession.CrewManager.SetHighlightedOrderIcon(this, orderPrefab.Identifier, option);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
msg.ReadPadBits();
|
msg.ReadPadBits();
|
||||||
@@ -471,7 +502,7 @@ namespace Barotrauma
|
|||||||
var x = inc.ReadSingle();
|
var x = inc.ReadSingle();
|
||||||
var y = inc.ReadSingle();
|
var y = inc.ReadSingle();
|
||||||
var hull = FindEntityByID(inc.ReadUInt16()) as Hull;
|
var hull = FindEntityByID(inc.ReadUInt16()) as Hull;
|
||||||
targetPosition = new OrderTarget(new Vector2(x, y), hull, true);
|
targetPosition = new OrderTarget(new Vector2(x, y), hull, creatingFromExistingData: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (orderPrefabIndex >= 0 && orderPrefabIndex < Order.PrefabList.Count)
|
if (orderPrefabIndex >= 0 && orderPrefabIndex < Order.PrefabList.Count)
|
||||||
@@ -485,7 +516,7 @@ namespace Barotrauma
|
|||||||
new Order(orderPrefab, targetPosition, orderGiver: orderGiver);
|
new Order(orderPrefab, targetPosition, orderGiver: orderGiver);
|
||||||
character.SetOrder(order,
|
character.SetOrder(order,
|
||||||
orderOptionIndex >= 0 && orderOptionIndex < orderPrefab.Options.Length ? orderPrefab.Options[orderOptionIndex] : null,
|
orderOptionIndex >= 0 && orderOptionIndex < orderPrefab.Options.Length ? orderPrefab.Options[orderOptionIndex] : null,
|
||||||
orderPriority, orderGiver, speak: false);
|
orderPriority, orderGiver, speak: false, force: true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private GUIListBox afflictionTooltip;
|
private GUIListBox afflictionTooltip;
|
||||||
|
|
||||||
|
private static readonly Color oxygenLowGrainColor = new Color(0.1f, 0.1f, 0.1f, 1f);
|
||||||
|
|
||||||
private struct HeartratePosition
|
private struct HeartratePosition
|
||||||
{
|
{
|
||||||
public float Time;
|
public float Time;
|
||||||
@@ -671,17 +673,19 @@ namespace Barotrauma
|
|||||||
bloodParticleTimer -= deltaTime * (affliction.Strength / 10.0f);
|
bloodParticleTimer -= deltaTime * (affliction.Strength / 10.0f);
|
||||||
if (bloodParticleTimer <= 0.0f)
|
if (bloodParticleTimer <= 0.0f)
|
||||||
{
|
{
|
||||||
var emitter = Character.BloodEmitters.FirstOrDefault();
|
bool inWater = Character.AnimController.InWater;
|
||||||
|
var drawTarget = inWater ? Particles.ParticlePrefab.DrawTargetType.Water : Particles.ParticlePrefab.DrawTargetType.Air;
|
||||||
|
var emitter = Character.BloodEmitters.FirstOrDefault(e => e.Prefab.ParticlePrefab.DrawTarget == drawTarget || e.Prefab.ParticlePrefab.DrawTarget == Particles.ParticlePrefab.DrawTargetType.Both);
|
||||||
float particleMinScale = emitter != null ? emitter.Prefab.ScaleMin : 0.5f;
|
float particleMinScale = emitter != null ? emitter.Prefab.ScaleMin : 0.5f;
|
||||||
float particleMaxScale = emitter != null ? emitter.Prefab.ScaleMax : 1;
|
float particleMaxScale = emitter != null ? emitter.Prefab.ScaleMax : 1;
|
||||||
float severity = Math.Min(affliction.Strength / affliction.Prefab.MaxStrength * Character.Params.BleedParticleMultiplier, 1);
|
float severity = Math.Min(affliction.Strength / affliction.Prefab.MaxStrength * Character.Params.BleedParticleMultiplier, 1);
|
||||||
float bloodParticleSize = MathHelper.Lerp(particleMinScale, particleMaxScale, severity);
|
float bloodParticleSize = MathHelper.Lerp(particleMinScale, particleMaxScale, severity);
|
||||||
bool inWater = Character.AnimController.InWater;
|
|
||||||
if (!inWater)
|
if (!inWater)
|
||||||
{
|
{
|
||||||
bloodParticleSize *= 2.0f;
|
bloodParticleSize *= 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use the blood emitter?
|
||||||
var blood = GameMain.ParticleManager.CreateParticle(
|
var blood = GameMain.ParticleManager.CreateParticle(
|
||||||
inWater ? Character.Params.BleedParticleWater : Character.Params.BleedParticleAir,
|
inWater ? Character.Params.BleedParticleWater : Character.Params.BleedParticleAir,
|
||||||
targetLimb.WorldPosition, Rand.Vector(affliction.Strength), 0.0f, Character.AnimController.CurrentHull);
|
targetLimb.WorldPosition, Rand.Vector(affliction.Strength), 0.0f, Character.AnimController.CurrentHull);
|
||||||
@@ -742,6 +746,7 @@ namespace Barotrauma
|
|||||||
float radialDistortStrength = 0.0f;
|
float radialDistortStrength = 0.0f;
|
||||||
float chromaticAberrationStrength = 0.0f;
|
float chromaticAberrationStrength = 0.0f;
|
||||||
float grainStrength = 0.0f;
|
float grainStrength = 0.0f;
|
||||||
|
Color grainColor = Color.White;
|
||||||
|
|
||||||
if (Character.IsUnconscious)
|
if (Character.IsUnconscious)
|
||||||
{
|
{
|
||||||
@@ -750,10 +755,15 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (OxygenAmount < 100.0f)
|
else if (OxygenAmount < 100.0f)
|
||||||
{
|
{
|
||||||
|
// TODO disable some of these?
|
||||||
blurStrength = MathHelper.Lerp(0.5f, 1.0f, 1.0f - Vitality / MaxVitality);
|
blurStrength = MathHelper.Lerp(0.5f, 1.0f, 1.0f - Vitality / MaxVitality);
|
||||||
distortStrength = blurStrength;
|
distortStrength = blurStrength;
|
||||||
distortSpeed = (blurStrength + 1.0f);
|
distortSpeed = (blurStrength + 1.0f);
|
||||||
distortSpeed *= distortSpeed * distortSpeed * distortSpeed;
|
distortSpeed *= distortSpeed * distortSpeed * distortSpeed;
|
||||||
|
|
||||||
|
|
||||||
|
grainStrength = MathHelper.Lerp(0.5f, 10.0f, 1.0f - (OxygenAmount - LowOxygenThreshold) / LowOxygenThreshold);
|
||||||
|
grainColor = oxygenLowGrainColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Affliction affliction in afflictions)
|
foreach (Affliction affliction in afflictions)
|
||||||
@@ -778,6 +788,7 @@ namespace Barotrauma
|
|||||||
Character.RadialDistortStrength = radialDistortStrength;
|
Character.RadialDistortStrength = radialDistortStrength;
|
||||||
Character.ChromaticAberrationStrength = chromaticAberrationStrength;
|
Character.ChromaticAberrationStrength = chromaticAberrationStrength;
|
||||||
Character.GrainStrength = grainStrength;
|
Character.GrainStrength = grainStrength;
|
||||||
|
Character.GrainColor = grainColor;
|
||||||
if (blurStrength > 0.0f)
|
if (blurStrength > 0.0f)
|
||||||
{
|
{
|
||||||
distortTimer = (distortTimer + deltaTime * distortSpeed) % MathHelper.TwoPi;
|
distortTimer = (distortTimer + deltaTime * distortSpeed) % MathHelper.TwoPi;
|
||||||
@@ -2004,7 +2015,7 @@ namespace Barotrauma
|
|||||||
existingAffliction.PeriodicEffectTimers[periodicEffect.First] = periodicEffect.Second;
|
existingAffliction.PeriodicEffectTimers[periodicEffect.First] = periodicEffect.Second;
|
||||||
foreach (StatusEffect effect in periodicEffect.First.StatusEffects)
|
foreach (StatusEffect effect in periodicEffect.First.StatusEffects)
|
||||||
{
|
{
|
||||||
existingAffliction.ApplyStatusEffect(effect, deltaTime: 1.0f, this, targetLimb: null);
|
existingAffliction.ApplyStatusEffect(ActionType.OnActive, effect, deltaTime: 1.0f, this, targetLimb: null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2071,7 +2082,7 @@ namespace Barotrauma
|
|||||||
foreach (StatusEffect effect in periodicEffect.First.StatusEffects)
|
foreach (StatusEffect effect in periodicEffect.First.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(newAffliction.First));
|
||||||
existingAffliction.ApplyStatusEffect(effect, deltaTime: 1.0f, this, targetLimb: targetLimb);
|
existingAffliction.ApplyStatusEffect(ActionType.OnActive, effect, deltaTime: 1.0f, this, targetLimb: targetLimb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -997,7 +997,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
wearableColor = wearableItemComponent.Item.GetSpriteColor();
|
wearableColor = wearableItemComponent.Item.GetSpriteColor();
|
||||||
}
|
}
|
||||||
float textureScale = wearable.InheritTextureScale ? TextureScale : 1;
|
float textureScale = wearable.InheritTextureScale ? TextureScale : wearable.Scale;
|
||||||
|
|
||||||
wearable.Sprite.Draw(spriteBatch,
|
wearable.Sprite.Draw(spriteBatch,
|
||||||
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ using Barotrauma.Extensions;
|
|||||||
using Barotrauma.Steam;
|
using Barotrauma.Steam;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Barotrauma.MapCreatures.Behavior;
|
using Barotrauma.MapCreatures.Behavior;
|
||||||
|
using static Barotrauma.FabricationRecipe;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -1367,6 +1368,237 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}, isCheat: false));
|
}, isCheat: false));
|
||||||
|
|
||||||
|
commands.Add(new Command("analyzeitem", "analyzeitem: Analyzes one item for exploits.", (string[] args) =>
|
||||||
|
{
|
||||||
|
if (args.Length < 1) return;
|
||||||
|
|
||||||
|
List<FabricationRecipe> fabricableItems = new List<FabricationRecipe>();
|
||||||
|
foreach (ItemPrefab iPrefab in ItemPrefab.Prefabs)
|
||||||
|
{
|
||||||
|
fabricableItems.AddRange(iPrefab.FabricationRecipes);
|
||||||
|
}
|
||||||
|
|
||||||
|
string itemNameOrId = args[0].ToLowerInvariant();
|
||||||
|
|
||||||
|
ItemPrefab itemPrefab =
|
||||||
|
(MapEntityPrefab.Find(itemNameOrId, identifier: null, showErrorMessages: false) ??
|
||||||
|
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
|
||||||
|
|
||||||
|
if (itemPrefab == null)
|
||||||
|
{
|
||||||
|
NewMessage("Item not found for analyzing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NewMessage("Analyzing item " + itemPrefab.Name + " with base cost " + itemPrefab.DefaultPrice.Price);
|
||||||
|
|
||||||
|
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == itemPrefab);
|
||||||
|
// omega nesting incoming
|
||||||
|
if (fabricationRecipe != null)
|
||||||
|
{
|
||||||
|
foreach (Tuple<string, PriceInfo> itemLocationPrice in itemPrefab.GetSellPricesOver(0))
|
||||||
|
{
|
||||||
|
NewMessage(" If bought at " + itemLocationPrice.Item1 + " it costs " + itemLocationPrice.Item2.Price);
|
||||||
|
int totalPrice = 0;
|
||||||
|
int? totalBestPrice = 0;
|
||||||
|
foreach (var ingredient in fabricationRecipe.RequiredItems)
|
||||||
|
{
|
||||||
|
foreach (ItemPrefab ingredientItemPrefab in ingredient.ItemPrefabs)
|
||||||
|
{
|
||||||
|
NewMessage(" Its ingredient " + ingredientItemPrefab.Name + " has base cost " + ingredientItemPrefab.DefaultPrice.Price);
|
||||||
|
totalPrice += ingredientItemPrefab.DefaultPrice.Price;
|
||||||
|
totalBestPrice += ingredientItemPrefab.GetMinPrice();
|
||||||
|
int basePrice = ingredientItemPrefab.DefaultPrice.Price;
|
||||||
|
foreach (Tuple<string, PriceInfo> ingredientItemLocationPrice in ingredientItemPrefab.GetBuyPricesUnder())
|
||||||
|
{
|
||||||
|
if (basePrice > ingredientItemLocationPrice.Item2.Price)
|
||||||
|
{
|
||||||
|
NewMessage(" Location " + ingredientItemLocationPrice.Item1 + " sells ingredient " + ingredientItemPrefab.Name + " for cheaper, " + ingredientItemLocationPrice.Item2.Price, Color.Yellow);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NewMessage(" Location " + ingredientItemLocationPrice.Item1 + " sells ingredient " + ingredientItemPrefab.Name + " for more, " + ingredientItemLocationPrice.Item2.Price, Color.Teal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int costDifference = itemPrefab.DefaultPrice.Price - totalPrice;
|
||||||
|
NewMessage(" Constructing the item from store-bought items provides " + costDifference + " profit with default values.");
|
||||||
|
|
||||||
|
if (totalBestPrice.HasValue)
|
||||||
|
{
|
||||||
|
int? bestDifference = itemLocationPrice.Item2.Price - totalBestPrice;
|
||||||
|
NewMessage(" Constructing the item from store-bought items provides " + bestDifference + " profit with best-case scenario values.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, isCheat: false));
|
||||||
|
|
||||||
|
commands.Add(new Command("checkcraftingexploits", "checkcraftingexploits: Finds outright item exploits created by buying store-bought ingredients and constructing them into sellable items.", (string[] args) =>
|
||||||
|
{
|
||||||
|
List<FabricationRecipe> fabricableItems = new List<FabricationRecipe>();
|
||||||
|
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
|
||||||
|
{
|
||||||
|
fabricableItems.AddRange(itemPrefab.FabricationRecipes);
|
||||||
|
}
|
||||||
|
List<Tuple<string, int>> costDifferences = new List<Tuple<string, int>>();
|
||||||
|
|
||||||
|
int maximumAllowedCost = 5;
|
||||||
|
|
||||||
|
if (args.Length > 0)
|
||||||
|
{
|
||||||
|
Int32.TryParse(args[0], out maximumAllowedCost);
|
||||||
|
}
|
||||||
|
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
|
||||||
|
{
|
||||||
|
int? defaultCost = itemPrefab.DefaultPrice?.Price;
|
||||||
|
int? fabricationCostStore = null;
|
||||||
|
|
||||||
|
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == itemPrefab);
|
||||||
|
if (fabricationRecipe == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canBeBought = true;
|
||||||
|
|
||||||
|
foreach (var ingredient in fabricationRecipe.RequiredItems)
|
||||||
|
{
|
||||||
|
int? ingredientPrice = ingredient.ItemPrefabs.Where(p => p.CanBeBought).Min(ip => ip.DefaultPrice?.Price);
|
||||||
|
if (ingredientPrice.HasValue)
|
||||||
|
{
|
||||||
|
if (!fabricationCostStore.HasValue) { fabricationCostStore = 0; }
|
||||||
|
float useAmount = ingredient.UseCondition ? ingredient.MinCondition : 1.0f;
|
||||||
|
fabricationCostStore += (int)(ingredientPrice.Value * ingredient.Amount * useAmount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
canBeBought = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fabricationCostStore.HasValue && defaultCost.HasValue && canBeBought)
|
||||||
|
{
|
||||||
|
int costDifference = defaultCost.Value - fabricationCostStore.Value;
|
||||||
|
if (costDifference > maximumAllowedCost || costDifference < 0f)
|
||||||
|
{
|
||||||
|
float ratio = (float)fabricationCostStore.Value / defaultCost.Value;
|
||||||
|
string message = "Fabricating \"" + itemPrefab.Name + "\" costs " + (int)(ratio * 100) + "% of the price of the item, or " + costDifference + " more. Item price: " + defaultCost.Value + ", ingredient prices: " + fabricationCostStore.Value;
|
||||||
|
costDifferences.Add(new Tuple<string, int>(message, costDifference));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
costDifferences.Sort((x, y) => x.Item2.CompareTo(y.Item2));
|
||||||
|
|
||||||
|
foreach (Tuple<string, int> costDifference in costDifferences)
|
||||||
|
{
|
||||||
|
Color color = Color.Yellow;
|
||||||
|
NewMessage(costDifference.Item1, color);
|
||||||
|
}
|
||||||
|
}, isCheat: false));
|
||||||
|
|
||||||
|
commands.Add(new Command("adjustprice", "adjustprice: Recursively prints out expected price adjustments for items derived from this item.", (string[] args) =>
|
||||||
|
{
|
||||||
|
List<FabricationRecipe> fabricableItems = new List<FabricationRecipe>();
|
||||||
|
foreach (ItemPrefab iP in ItemPrefab.Prefabs)
|
||||||
|
{
|
||||||
|
fabricableItems.AddRange(iP.FabricationRecipes);
|
||||||
|
}
|
||||||
|
if (args.Length < 2)
|
||||||
|
{
|
||||||
|
NewMessage("Item or value not defined.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string itemNameOrId = args[0].ToLowerInvariant();
|
||||||
|
|
||||||
|
ItemPrefab materialPrefab =
|
||||||
|
(MapEntityPrefab.Find(itemNameOrId, identifier: null, showErrorMessages: false) ??
|
||||||
|
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
|
||||||
|
|
||||||
|
if (materialPrefab == null)
|
||||||
|
{
|
||||||
|
NewMessage("Item not found for price adjustment.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdjustItemTypes adjustItemType = AdjustItemTypes.NoAdjustment;
|
||||||
|
if (args.Length > 2)
|
||||||
|
{
|
||||||
|
switch (args[2].ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "add":
|
||||||
|
adjustItemType = AdjustItemTypes.Additive;
|
||||||
|
break;
|
||||||
|
case "mult":
|
||||||
|
adjustItemType = AdjustItemTypes.Multiplicative;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Int32.TryParse(args[1].ToLowerInvariant(), out int newPrice))
|
||||||
|
{
|
||||||
|
Dictionary<ItemPrefab, int> newPrices = new Dictionary<ItemPrefab, int>();
|
||||||
|
PrintItemCosts(newPrices, materialPrefab, fabricableItems, newPrice, true, adjustItemType: adjustItemType);
|
||||||
|
PrintItemCosts(newPrices, materialPrefab, fabricableItems, newPrice, false, adjustItemType: adjustItemType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, isCheat: false));
|
||||||
|
|
||||||
|
commands.Add(new Command("deconstructvalue", "deconstructvalue: Views and compares deconstructed component prices for this item.", (string[] args) =>
|
||||||
|
{
|
||||||
|
List<FabricationRecipe> fabricableItems = new List<FabricationRecipe>();
|
||||||
|
foreach (ItemPrefab iP in ItemPrefab.Prefabs)
|
||||||
|
{
|
||||||
|
fabricableItems.AddRange(iP.FabricationRecipes);
|
||||||
|
}
|
||||||
|
if (args.Length < 1)
|
||||||
|
{
|
||||||
|
NewMessage("Item not defined.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string itemNameOrId = args[0].ToLowerInvariant();
|
||||||
|
|
||||||
|
ItemPrefab parentItem =
|
||||||
|
(MapEntityPrefab.Find(itemNameOrId, identifier: null, showErrorMessages: false) ??
|
||||||
|
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
|
||||||
|
|
||||||
|
if (parentItem == null)
|
||||||
|
{
|
||||||
|
NewMessage("Item not found for price adjustment.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == parentItem);
|
||||||
|
int totalValue = 0;
|
||||||
|
NewMessage(parentItem.Name + " has the price " + parentItem.DefaultPrice.Price);
|
||||||
|
if (fabricationRecipe != null)
|
||||||
|
{
|
||||||
|
NewMessage(" It constructs from:");
|
||||||
|
|
||||||
|
foreach (RequiredItem requiredItem in fabricationRecipe.RequiredItems)
|
||||||
|
{
|
||||||
|
foreach (ItemPrefab itemPrefab in requiredItem.ItemPrefabs)
|
||||||
|
{
|
||||||
|
NewMessage(" " + itemPrefab.Name + " has the price " + itemPrefab.DefaultPrice.Price);
|
||||||
|
totalValue += itemPrefab.DefaultPrice.Price;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NewMessage("Its total value was: " + totalValue);
|
||||||
|
totalValue = 0;
|
||||||
|
}
|
||||||
|
NewMessage(" The item deconstructs into:");
|
||||||
|
foreach (DeconstructItem deconstructItem in parentItem.DeconstructItems)
|
||||||
|
{
|
||||||
|
ItemPrefab itemPrefab =
|
||||||
|
(MapEntityPrefab.Find(deconstructItem.ItemIdentifier, identifier: null, showErrorMessages: false) ??
|
||||||
|
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
|
||||||
|
|
||||||
|
NewMessage(" " + itemPrefab.Name + " has the price " + itemPrefab.DefaultPrice.Price);
|
||||||
|
totalValue += itemPrefab.DefaultPrice.Price;
|
||||||
|
}
|
||||||
|
NewMessage("Its deconstruct value was: " + totalValue);
|
||||||
|
|
||||||
|
}, isCheat: false));
|
||||||
|
|
||||||
commands.Add(new Command("setentityproperties", "setentityproperties [property name] [value]: Sets the value of some property on all selected items/structures in the sub editor.", (string[] args) =>
|
commands.Add(new Command("setentityproperties", "setentityproperties [property name] [value]: Sets the value of some property on all selected items/structures in the sub editor.", (string[] args) =>
|
||||||
{
|
{
|
||||||
if (args.Length != 2 || Screen.Selected != GameMain.SubEditorScreen) { return; }
|
if (args.Length != 2 || Screen.Selected != GameMain.SubEditorScreen) { return; }
|
||||||
@@ -2935,5 +3167,155 @@ namespace Barotrauma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private enum AdjustItemTypes
|
||||||
|
{
|
||||||
|
NoAdjustment,
|
||||||
|
Additive,
|
||||||
|
Multiplicative
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintItemCosts(Dictionary<ItemPrefab, int> newPrices, ItemPrefab materialPrefab, List<FabricationRecipe> fabricableItems, int newPrice, bool adjustDown, string depth = "", AdjustItemTypes adjustItemType = AdjustItemTypes.NoAdjustment)
|
||||||
|
{
|
||||||
|
if (newPrice < 1)
|
||||||
|
{
|
||||||
|
NewMessage(depth + materialPrefab.Name + " cannot be adjusted to this price, because it would become less than 1.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
depth += " ";
|
||||||
|
|
||||||
|
if (newPrice > 0)
|
||||||
|
{
|
||||||
|
newPrices.TryAdd(materialPrefab, newPrice);
|
||||||
|
}
|
||||||
|
|
||||||
|
int componentCost = 0;
|
||||||
|
int newComponentCost = 0;
|
||||||
|
|
||||||
|
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == materialPrefab);
|
||||||
|
|
||||||
|
if (fabricationRecipe != null)
|
||||||
|
{
|
||||||
|
foreach (RequiredItem requiredItem in fabricationRecipe.RequiredItems)
|
||||||
|
{
|
||||||
|
foreach (ItemPrefab itemPrefab in requiredItem.ItemPrefabs)
|
||||||
|
{
|
||||||
|
GetAdjustedPrice(itemPrefab, ref componentCost, ref newComponentCost, newPrices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string componentCostMultiplier = "";
|
||||||
|
if (componentCost > 0)
|
||||||
|
{
|
||||||
|
componentCostMultiplier = $" (Relative difference to component cost {GetComponentCostDifference(materialPrefab.DefaultPrice.Price, componentCost)} => {GetComponentCostDifference(newPrice, newComponentCost)}, or flat profit {(int)(materialPrefab.DefaultPrice.Price - (int)componentCost)} => {newPrice - newComponentCost})";
|
||||||
|
}
|
||||||
|
string priceAdjustment = "";
|
||||||
|
if (newPrice != materialPrefab.DefaultPrice.Price)
|
||||||
|
{
|
||||||
|
priceAdjustment = ", Suggested price adjustment is " + materialPrefab.DefaultPrice.Price + " => " + newPrice;
|
||||||
|
}
|
||||||
|
NewMessage(depth + materialPrefab.Name + "(" + materialPrefab.DefaultPrice.Price + ") " + priceAdjustment + componentCostMultiplier);
|
||||||
|
|
||||||
|
if (adjustDown)
|
||||||
|
{
|
||||||
|
if (componentCost > 0)
|
||||||
|
{
|
||||||
|
double newPriceMult = (double)newPrice / (double)(materialPrefab.DefaultPrice.Price);
|
||||||
|
int newPriceDiff = componentCost + newPrice - materialPrefab.DefaultPrice.Price;
|
||||||
|
|
||||||
|
switch (adjustItemType)
|
||||||
|
{
|
||||||
|
case AdjustItemTypes.Additive:
|
||||||
|
NewMessage(depth + materialPrefab.Name + "'s components should be adjusted " + componentCost + " => " + newPriceDiff);
|
||||||
|
break;
|
||||||
|
case AdjustItemTypes.Multiplicative:
|
||||||
|
NewMessage(depth + materialPrefab.Name + "'s components should be adjusted " + componentCost + " => " + Math.Round(newPriceMult * componentCost));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fabricationRecipe != null)
|
||||||
|
{
|
||||||
|
foreach (RequiredItem requiredItem in fabricationRecipe.RequiredItems)
|
||||||
|
{
|
||||||
|
foreach (ItemPrefab itemPrefab in requiredItem.ItemPrefabs)
|
||||||
|
{
|
||||||
|
if (itemPrefab.DefaultPrice != null)
|
||||||
|
{
|
||||||
|
switch (adjustItemType)
|
||||||
|
{
|
||||||
|
case AdjustItemTypes.NoAdjustment:
|
||||||
|
PrintItemCosts(newPrices, itemPrefab, fabricableItems, itemPrefab.DefaultPrice.Price, adjustDown, depth, adjustItemType);
|
||||||
|
break;
|
||||||
|
case AdjustItemTypes.Additive:
|
||||||
|
PrintItemCosts(newPrices, itemPrefab, fabricableItems, itemPrefab.DefaultPrice.Price + (int)((newPrice - materialPrefab.DefaultPrice.Price) / (double)fabricationRecipe.RequiredItems.Count), adjustDown, depth, adjustItemType);
|
||||||
|
break;
|
||||||
|
case AdjustItemTypes.Multiplicative:
|
||||||
|
PrintItemCosts(newPrices, itemPrefab, fabricableItems, (int)(itemPrefab.DefaultPrice.Price * newPriceMult), adjustDown, depth, adjustItemType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var fabricationRecipes = fabricableItems.Where(f => f.RequiredItems.Any(x => x.ItemPrefabs.Contains(materialPrefab)));
|
||||||
|
|
||||||
|
foreach (FabricationRecipe fabricationRecipeParent in fabricationRecipes)
|
||||||
|
{
|
||||||
|
if (fabricationRecipeParent.TargetItem.DefaultPrice != null)
|
||||||
|
{
|
||||||
|
int targetComponentCost = 0;
|
||||||
|
int newTargetComponentCost = 0;
|
||||||
|
|
||||||
|
foreach (RequiredItem requiredItem in fabricationRecipeParent.RequiredItems)
|
||||||
|
{
|
||||||
|
foreach (ItemPrefab itemPrefab in requiredItem.ItemPrefabs)
|
||||||
|
{
|
||||||
|
GetAdjustedPrice(itemPrefab, ref targetComponentCost, ref newTargetComponentCost, newPrices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (adjustItemType)
|
||||||
|
{
|
||||||
|
case AdjustItemTypes.NoAdjustment:
|
||||||
|
PrintItemCosts(newPrices, fabricationRecipeParent.TargetItem, fabricableItems, fabricationRecipeParent.TargetItem.DefaultPrice.Price, adjustDown, depth, adjustItemType);
|
||||||
|
break;
|
||||||
|
case AdjustItemTypes.Additive:
|
||||||
|
PrintItemCosts(newPrices, fabricationRecipeParent.TargetItem, fabricableItems, fabricationRecipeParent.TargetItem.DefaultPrice.Price + newPrice - materialPrefab.DefaultPrice.Price, adjustDown, depth, adjustItemType);
|
||||||
|
break;
|
||||||
|
case AdjustItemTypes.Multiplicative:
|
||||||
|
double maintainedMultiplier = GetComponentCostDifference(fabricationRecipeParent.TargetItem.DefaultPrice.Price, targetComponentCost);
|
||||||
|
PrintItemCosts(newPrices, fabricationRecipeParent.TargetItem, fabricableItems, (int)(newTargetComponentCost * maintainedMultiplier), adjustDown, depth, adjustItemType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double GetComponentCostDifference(int itemCost, int componentCost)
|
||||||
|
{
|
||||||
|
return Math.Round((double)(itemCost / (double)componentCost), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetAdjustedPrice(ItemPrefab itemPrefab, ref int componentCost, ref int newComponentCost, Dictionary<ItemPrefab, int> newPrices)
|
||||||
|
{
|
||||||
|
if (newPrices.TryGetValue(itemPrefab, out int newPrice))
|
||||||
|
{
|
||||||
|
newComponentCost += newPrice;
|
||||||
|
}
|
||||||
|
else if (itemPrefab.DefaultPrice != null)
|
||||||
|
{
|
||||||
|
newComponentCost += itemPrefab.DefaultPrice.Price;
|
||||||
|
}
|
||||||
|
if (itemPrefab.DefaultPrice != null)
|
||||||
|
{
|
||||||
|
componentCost += itemPrefab.DefaultPrice.Price;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, Hull hull, float depth)
|
public void Draw(SpriteBatch spriteBatch, Hull hull, float depth)
|
||||||
{
|
{
|
||||||
|
if (Sprite.Texture == null) { return; }
|
||||||
|
|
||||||
Vector2 drawPos = position + hull.Rect.Location.ToVector2();
|
Vector2 drawPos = position + hull.Rect.Location.ToVector2();
|
||||||
if (hull.Submarine != null) { drawPos += hull.Submarine.DrawPosition; }
|
if (hull.Submarine != null) { drawPos += hull.Submarine.DrawPosition; }
|
||||||
drawPos.Y = -drawPos.Y;
|
drawPos.Y = -drawPos.Y;
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ namespace Barotrauma
|
|||||||
GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "FloodingAmount: " + (int)Math.Round(floodingAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, floodingAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
|
GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "FloodingAmount: " + (int)Math.Round(floodingAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, floodingAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
|
||||||
GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "FireAmount: " + (int)Math.Round(fireAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, fireAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
|
GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "FireAmount: " + (int)Math.Round(fireAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, fireAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
|
||||||
GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "EnemyDanger: " + (int)Math.Round(enemyDanger * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, enemyDanger), Color.Black * 0.6f, 0, GUI.SmallFont);
|
GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "EnemyDanger: " + (int)Math.Round(enemyDanger * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, enemyDanger), Color.Black * 0.6f, 0, GUI.SmallFont);
|
||||||
|
GUI.DrawString(spriteBatch, new Vector2(15, y + 140), "MonsterTotalStrength: " + (int)Math.Round(monsterTotalStrength), Color.Lerp(GUI.Style.Green, GUI.Style.Red, monsterTotalStrength / 5000f), Color.Black * 0.6f, 0, GUI.SmallFont);
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftAlt) &&
|
if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftAlt) &&
|
||||||
@@ -75,7 +76,7 @@ namespace Barotrauma
|
|||||||
lastIntensityUpdate = (float) Timing.TotalTime;
|
lastIntensityUpdate = (float) Timing.TotalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle graphRect = new Rectangle(15, y + 150, 150, 50);
|
Rectangle graphRect = new Rectangle(15, y + 165, 150, 50);
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch, graphRect, Color.Black * 0.5f, true);
|
GUI.DrawRectangle(spriteBatch, graphRect, Color.Black * 0.5f, true);
|
||||||
intensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, GUI.Style.Red, currentIntensity));
|
intensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, GUI.Style.Red, currentIntensity));
|
||||||
|
|||||||
@@ -1,9 +1,28 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
partial class CargoMission : Mission
|
partial class CargoMission : Mission
|
||||||
{
|
{
|
||||||
|
public override string GetMissionRewardText(Submarine sub)
|
||||||
|
{
|
||||||
|
string rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", GetReward(sub)));
|
||||||
|
|
||||||
|
if (rewardPerCrate.HasValue)
|
||||||
|
{
|
||||||
|
string rewardPerCrateText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", rewardPerCrate.Value));
|
||||||
|
return TextManager.GetWithVariables("missionrewardcargopercrate",
|
||||||
|
new string[] { "[rewardpercrate]", "[itemcount]", "[maxitemcount]", "[totalreward]" },
|
||||||
|
new string[] { rewardPerCrateText, itemsToSpawn.Count.ToString(), maxItemCount.ToString(), $"‖color:gui.orange‖{rewardText}‖end‖" });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return TextManager.GetWithVariables("missionrewardcargo",
|
||||||
|
new string[] { "[totalreward]", "[itemcount]", "[maxitemcount]" },
|
||||||
|
new string[] { $"‖color:gui.orange‖{rewardText}‖end‖", itemsToSpawn.Count.ToString(), maxItemCount.ToString() });
|
||||||
|
}
|
||||||
|
}
|
||||||
public override void ClientReadInitial(IReadMessage msg)
|
public override void ClientReadInitial(IReadMessage msg)
|
||||||
{
|
{
|
||||||
items.Clear();
|
items.Clear();
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using Barotrauma.Networking;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
partial class EscortMission : Mission
|
||||||
|
{
|
||||||
|
public override void ClientReadInitial(IReadMessage msg)
|
||||||
|
{
|
||||||
|
byte characterCount = msg.ReadByte();
|
||||||
|
|
||||||
|
for (int i = 0; i < characterCount; i++)
|
||||||
|
{
|
||||||
|
characters.Add(Character.ReadSpawnData(msg));
|
||||||
|
ushort itemCount = msg.ReadUInt16();
|
||||||
|
for (int j = 0; j < itemCount; j++)
|
||||||
|
{
|
||||||
|
Item.ReadSpawnData(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (characters.Contains(null))
|
||||||
|
{
|
||||||
|
throw new System.Exception("Error in EscortMission.ClientReadInitial: character list contains null (mission: " + Prefab.Identifier + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (characters.Count != characterCount)
|
||||||
|
{
|
||||||
|
throw new System.Exception("Error in EscortMission.ClientReadInitial: character count does not match the server count (" + characterCount + " != " + characters.Count + "mission: " + Prefab.Identifier + ")");
|
||||||
|
}
|
||||||
|
InitCharacters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,9 +21,9 @@ namespace Barotrauma
|
|||||||
return ToolBox.GradientLerp(t, GUI.Style.Green, GUI.Style.Orange, GUI.Style.Red);
|
return ToolBox.GradientLerp(t, GUI.Style.Green, GUI.Style.Orange, GUI.Style.Red);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetMissionRewardText()
|
public virtual string GetMissionRewardText(Submarine sub)
|
||||||
{
|
{
|
||||||
string rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", Reward));
|
string rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", GetReward(sub)));
|
||||||
return TextManager.GetWithVariable("missionreward", "[reward]", $"‖color:gui.orange‖{rewardText}‖end‖");
|
return TextManager.GetWithVariable("missionreward", "[reward]", $"‖color:gui.orange‖{rewardText}‖end‖");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using Barotrauma.Networking;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
partial class PirateMission : Mission
|
||||||
|
{
|
||||||
|
public override void ClientReadInitial(IReadMessage msg)
|
||||||
|
{
|
||||||
|
// duplicate code from escortmission, should possibly be combined, though additional loot items might be added so maybe not
|
||||||
|
byte characterCount = msg.ReadByte();
|
||||||
|
|
||||||
|
for (int i = 0; i < characterCount; i++)
|
||||||
|
{
|
||||||
|
characters.Add(Character.ReadSpawnData(msg));
|
||||||
|
ushort itemCount = msg.ReadUInt16();
|
||||||
|
for (int j = 0; j < itemCount; j++)
|
||||||
|
{
|
||||||
|
Item.ReadSpawnData(msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (characters.Contains(null))
|
||||||
|
{
|
||||||
|
throw new System.Exception("Error in PirateMission.ClientReadInitial: character list contains null (mission: " + Prefab.Identifier + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (characters.Count != characterCount)
|
||||||
|
{
|
||||||
|
throw new System.Exception("Error in PirateMission.ClientReadInitial: character count does not match the server count (" + characterCount + " != " + characters.Count + "mission: " + Prefab.Identifier + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1331,7 +1331,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
/// <param name="createOffset">Should the indicator move based on the camera position?</param>
|
/// <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>
|
/// <param name="overrideAlpha">Override the distance-based alpha value with the specified alpha value</param>
|
||||||
public static void DrawIndicator(SpriteBatch spriteBatch, Vector2 worldPosition, Camera cam, float hideDist, Sprite sprite, Color color,
|
public static void DrawIndicator(SpriteBatch spriteBatch, in Vector2 worldPosition, Camera cam, in Vector2 visibleRange, Sprite sprite, in Color color,
|
||||||
bool createOffset = true, float scaleMultiplier = 1.0f, float? overrideAlpha = null)
|
bool createOffset = true, float scaleMultiplier = 1.0f, float? overrideAlpha = null)
|
||||||
{
|
{
|
||||||
Vector2 diff = worldPosition - cam.WorldViewCenter;
|
Vector2 diff = worldPosition - cam.WorldViewCenter;
|
||||||
@@ -1339,9 +1339,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
float symbolScale = Math.Min(64.0f / sprite.size.X, 1.0f) * scaleMultiplier * Scale;
|
float symbolScale = Math.Min(64.0f / sprite.size.X, 1.0f) * scaleMultiplier * Scale;
|
||||||
|
|
||||||
if (overrideAlpha.HasValue || dist > hideDist)
|
if (overrideAlpha.HasValue || (dist > visibleRange.X && dist < visibleRange.Y))
|
||||||
{
|
{
|
||||||
float alpha = overrideAlpha ?? Math.Min((dist - hideDist) / 100.0f, 1.0f);
|
float alpha = overrideAlpha ?? MathUtils.Min((dist - visibleRange.X) / 100.0f, 1.0f - ((dist - visibleRange.Y + 100f) / 100.0f), 1.0f);
|
||||||
Vector2 targetScreenPos = cam.WorldToScreen(worldPosition);
|
Vector2 targetScreenPos = cam.WorldToScreen(worldPosition);
|
||||||
|
|
||||||
if (!createOffset)
|
if (!createOffset)
|
||||||
@@ -1395,6 +1395,12 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
public static void DrawLine(SpriteBatch sb, Vector2 start, Vector2 end, Color clr, float depth = 0.0f, float width = 1)
|
public static void DrawLine(SpriteBatch sb, Vector2 start, Vector2 end, Color clr, float depth = 0.0f, float width = 1)
|
||||||
{
|
{
|
||||||
DrawLine(sb, t, start, end, clr, depth, (int)width);
|
DrawLine(sb, t, start, end, clr, depth, (int)width);
|
||||||
@@ -1495,6 +1501,22 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void DrawFilledRectangle(SpriteBatch sb, Vector2 start, Vector2 size, Color clr, float depth = 0.0f)
|
||||||
|
{
|
||||||
|
if (size.X < 0)
|
||||||
|
{
|
||||||
|
start.X += size.X;
|
||||||
|
size.X = -size.X;
|
||||||
|
}
|
||||||
|
if (size.Y < 0)
|
||||||
|
{
|
||||||
|
start.Y += size.Y;
|
||||||
|
size.Y = -size.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Draw(t, start, null, clr, 0f, Vector2.Zero, size, SpriteEffects.None, depth);
|
||||||
|
}
|
||||||
|
|
||||||
public static void DrawRectangle(SpriteBatch sb, Vector2 center, float width, float height, float rotation, Color clr, float depth = 0.0f, float thickness = 1)
|
public static void DrawRectangle(SpriteBatch sb, Vector2 center, float width, float height, float rotation, Color clr, float depth = 0.0f, float thickness = 1)
|
||||||
{
|
{
|
||||||
Matrix rotate = Matrix.CreateRotationZ(rotation);
|
Matrix rotate = Matrix.CreateRotationZ(rotation);
|
||||||
@@ -1971,6 +1993,30 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GUIMessageBox AskForConfirmation(string header, string body, Action onConfirm, Action onDeny = null)
|
||||||
|
{
|
||||||
|
string[] buttons = { TextManager.Get("Ok"), TextManager.Get("Cancel") };
|
||||||
|
GUIMessageBox msgBox = new GUIMessageBox(header, body, buttons, new Vector2(0.2f, 0.175f), minSize: new Point(300, 175));
|
||||||
|
|
||||||
|
// Cancel button
|
||||||
|
msgBox.Buttons[1].OnClicked = delegate
|
||||||
|
{
|
||||||
|
onDeny?.Invoke();
|
||||||
|
msgBox.Close();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ok button
|
||||||
|
msgBox.Buttons[0].OnClicked = delegate
|
||||||
|
{
|
||||||
|
onConfirm.Invoke();
|
||||||
|
msgBox.Close();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return msgBox;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Element positioning
|
#region Element positioning
|
||||||
@@ -2221,6 +2267,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool IsOutpostLevel() => GameMain.GameSession != null && Level.IsLoadedOutpost;
|
||||||
if (Screen.Selected == GameMain.GameScreen && GameMain.GameSession != null)
|
if (Screen.Selected == GameMain.GameScreen && GameMain.GameSession != null)
|
||||||
{
|
{
|
||||||
if (GameMain.GameSession.GameMode is SinglePlayerCampaign spMode)
|
if (GameMain.GameSession.GameMode is SinglePlayerCampaign spMode)
|
||||||
@@ -2253,45 +2300,22 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
var saveAndQuitButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSaveQuit"))
|
if (IsOutpostLevel())
|
||||||
{
|
{
|
||||||
UserData = "save"
|
var saveAndQuitButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSaveQuit"))
|
||||||
};
|
|
||||||
saveAndQuitButton.OnClicked += (btn, userdata) =>
|
|
||||||
{
|
|
||||||
//Only allow saving mid-round in outpost levels. Quitting in the middle of a mission reset progress to the start of the round.
|
|
||||||
if (GameMain.GameSession == null)
|
|
||||||
{
|
{
|
||||||
pauseMenuOpen = false;
|
UserData = "save",
|
||||||
|
OnClicked = (btn, userData) =>
|
||||||
}
|
|
||||||
else if (GameMain.GameSession?.Campaign == null || Level.IsLoadedOutpost)
|
|
||||||
{
|
|
||||||
pauseMenuOpen = false;
|
|
||||||
GameMain.QuitToMainMenu(save: true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var msgBox = new GUIMessageBox("", TextManager.Get("PauseMenuSaveAndQuitVerification", fallBackTag: "pausemenuquitverification"), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
|
|
||||||
{
|
|
||||||
UserData = "verificationprompt"
|
|
||||||
};
|
|
||||||
msgBox.Buttons[0].OnClicked = (_, userdata) =>
|
|
||||||
{
|
{
|
||||||
pauseMenuOpen = false;
|
pauseMenuOpen = false;
|
||||||
GameMain.QuitToMainMenu(save: false);
|
if (IsOutpostLevel())
|
||||||
|
{
|
||||||
|
GameMain.QuitToMainMenu(save: true);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
};
|
||||||
msgBox.Buttons[1].OnClicked = (_, userdata) =>
|
}
|
||||||
{
|
|
||||||
pauseMenuOpen = false;
|
|
||||||
msgBox.Close();
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
else if (GameMain.GameSession.GameMode is TestGameMode)
|
else if (GameMain.GameSession.GameMode is TestGameMode)
|
||||||
{
|
{
|
||||||
@@ -2313,7 +2337,7 @@ namespace Barotrauma
|
|||||||
OnClicked = (btn, userdata) =>
|
OnClicked = (btn, userdata) =>
|
||||||
{
|
{
|
||||||
if (!GameMain.Client.HasPermission(ClientPermissions.ManageRound)) { return false; }
|
if (!GameMain.Client.HasPermission(ClientPermissions.ManageRound)) { return false; }
|
||||||
if (GameMain.GameSession.GameMode is CampaignMode || (!Submarine.MainSub.AtStartExit && !Submarine.MainSub.AtEndExit))
|
if (GameMain.GameSession.GameMode is CampaignMode && !IsOutpostLevel() || (!Submarine.MainSub.AtStartExit && !Submarine.MainSub.AtEndExit))
|
||||||
{
|
{
|
||||||
var msgBox = new GUIMessageBox("",
|
var msgBox = new GUIMessageBox("",
|
||||||
TextManager.Get(GameMain.GameSession.GameMode is CampaignMode ? "PauseMenuReturnToServerLobbyVerification" : "EndRoundSubNotAtLevelEnd"),
|
TextManager.Get(GameMain.GameSession.GameMode is CampaignMode ? "PauseMenuReturnToServerLobbyVerification" : "EndRoundSubNotAtLevelEnd"),
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (value == intValue) { return; }
|
if (value == intValue) { return; }
|
||||||
intValue = value;
|
intValue = value;
|
||||||
|
ClampIntValue();
|
||||||
UpdateText();
|
UpdateText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,11 @@ namespace Barotrauma
|
|||||||
get { return _caretIndex; }
|
get { return _caretIndex; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_caretIndex = value;
|
if (value >= 0)
|
||||||
caretPosDirty = true;
|
{
|
||||||
|
_caretIndex = value;
|
||||||
|
caretPosDirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private bool caretPosDirty;
|
private bool caretPosDirty;
|
||||||
@@ -454,7 +457,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (!isSelecting)
|
if (!isSelecting)
|
||||||
{
|
{
|
||||||
isSelecting = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift);
|
isSelecting = PlayerInput.IsShiftDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mouseHeldInside && !PlayerInput.PrimaryMouseButtonHeld())
|
if (mouseHeldInside && !PlayerInput.PrimaryMouseButtonHeld())
|
||||||
@@ -879,15 +882,22 @@ namespace Barotrauma
|
|||||||
selectionEndIndex = Math.Min(CaretIndex, textDrawn.Length);
|
selectionEndIndex = Math.Min(CaretIndex, textDrawn.Length);
|
||||||
selectionEndPos = caretPos;
|
selectionEndPos = caretPos;
|
||||||
selectedCharacters = Math.Abs(selectionStartIndex - selectionEndIndex);
|
selectedCharacters = Math.Abs(selectionStartIndex - selectionEndIndex);
|
||||||
if (IsLeftToRight)
|
try
|
||||||
{
|
{
|
||||||
selectedText = Text.Substring(selectionStartIndex, selectedCharacters);
|
if (IsLeftToRight)
|
||||||
selectionRectSize = Font.MeasureString(textDrawn.Substring(selectionStartIndex, selectedCharacters)) * TextBlock.TextScale;
|
{
|
||||||
|
selectedText = Text.Substring(selectionStartIndex, Math.Min(selectedCharacters, Text.Length));
|
||||||
|
selectionRectSize = Font.MeasureString(textDrawn.Substring(selectionStartIndex, Math.Min(selectedCharacters, textDrawn.Length))) * TextBlock.TextScale;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
selectedText = Text.Substring(selectionEndIndex, Math.Min(selectedCharacters, Text.Length));
|
||||||
|
selectionRectSize = Font.MeasureString(textDrawn.Substring(selectionEndIndex, Math.Min(selectedCharacters, textDrawn.Length))) * TextBlock.TextScale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
catch (ArgumentOutOfRangeException exception)
|
||||||
{
|
{
|
||||||
selectedText = Text.Substring(selectionEndIndex, Math.Min(selectedCharacters, textDrawn.Length - selectionEndIndex));
|
DebugConsole.ThrowError($"GUITextBox: Invalid selection: ({exception})");
|
||||||
selectionRectSize = Font.MeasureString(textDrawn.Substring(selectionEndIndex, selectedCharacters)) * TextBlock.TextScale;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -947,7 +947,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
descriptionText += "\n\n" + missionMessage;
|
descriptionText += "\n\n" + missionMessage;
|
||||||
}
|
}
|
||||||
string rewardText = mission.GetMissionRewardText();
|
string rewardText = mission.GetMissionRewardText(Submarine.MainSub);
|
||||||
string reputationText = mission.GetReputationRewardText(mission.Locations[0]);
|
string reputationText = mission.GetReputationRewardText(mission.Locations[0]);
|
||||||
|
|
||||||
var missionNameRichTextData = RichTextData.GetRichTextData(mission.Name, out string missionNameString);
|
var missionNameRichTextData = RichTextData.GetRichTextData(mission.Name, out string missionNameString);
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@@ -7,8 +9,10 @@ using Barotrauma.Extensions;
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
using FarseerPhysics;
|
using FarseerPhysics;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using SpriteBatch = Microsoft.Xna.Framework.Graphics.SpriteBatch;
|
|
||||||
|
// ReSharper disable UnusedVariable
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -18,8 +22,8 @@ namespace Barotrauma
|
|||||||
public readonly struct CategoryData
|
public readonly struct CategoryData
|
||||||
{
|
{
|
||||||
public readonly UpgradeCategory Category;
|
public readonly UpgradeCategory Category;
|
||||||
public readonly List<UpgradePrefab> Prefabs;
|
public readonly List<UpgradePrefab>? Prefabs;
|
||||||
public readonly UpgradePrefab SinglePrefab;
|
public readonly UpgradePrefab? SinglePrefab;
|
||||||
|
|
||||||
public CategoryData(UpgradeCategory category, List<UpgradePrefab> prefabs)
|
public CategoryData(UpgradeCategory category, List<UpgradePrefab> prefabs)
|
||||||
{
|
{
|
||||||
@@ -37,30 +41,34 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly CampaignUI campaignUI;
|
private readonly CampaignUI campaignUI;
|
||||||
private CampaignMode Campaign => campaignUI?.Campaign;
|
private CampaignMode? Campaign => campaignUI.Campaign;
|
||||||
|
private int AvailableMoney => Campaign?.Money ?? 0;
|
||||||
private UpgradeTab selectedUpgradTab = UpgradeTab.Upgrade;
|
private UpgradeTab selectedUpgradTab = UpgradeTab.Upgrade;
|
||||||
|
|
||||||
private GUIMessageBox currectConfirmation;
|
private GUIMessageBox? currectConfirmation;
|
||||||
|
|
||||||
public readonly GUIFrame ItemInfoFrame;
|
public readonly GUIFrame ItemInfoFrame;
|
||||||
private GUIComponent selectedUpgradeCategoryLayout;
|
private GUIComponent? selectedUpgradeCategoryLayout;
|
||||||
private GUILayoutGroup topHeaderLayout;
|
private GUILayoutGroup? topHeaderLayout;
|
||||||
private GUILayoutGroup mainStoreLayout;
|
private GUILayoutGroup? mainStoreLayout;
|
||||||
private GUILayoutGroup storeLayout;
|
private GUILayoutGroup? storeLayout;
|
||||||
private GUILayoutGroup categoryButtonLayout;
|
private GUILayoutGroup? categoryButtonLayout;
|
||||||
private GUILayoutGroup submarineInfoFrame;
|
private GUILayoutGroup? submarineInfoFrame;
|
||||||
private GUIListBox currentStoreLayout;
|
private GUIListBox? currentStoreLayout;
|
||||||
private GUICustomComponent submarinePreviewComponent;
|
private GUICustomComponent? submarinePreviewComponent;
|
||||||
private GUIFrame subPreviewFrame;
|
private GUIFrame? subPreviewFrame;
|
||||||
private Submarine drawnSubmarine;
|
private Submarine? drawnSubmarine;
|
||||||
private readonly List<UpgradeCategory> applicableCategories = new List<UpgradeCategory>();
|
private readonly List<UpgradeCategory> applicableCategories = new List<UpgradeCategory>();
|
||||||
private Vector2[][] subHullVerticies = new Vector2[0][];
|
private Vector2[][] subHullVerticies = new Vector2[0][];
|
||||||
private List<Structure> submarineWalls = new List<Structure>();
|
private List<Structure> submarineWalls = new List<Structure>();
|
||||||
|
|
||||||
public MapEntity HoveredItem;
|
public MapEntity? HoveredItem;
|
||||||
private bool highlightWalls;
|
private bool highlightWalls;
|
||||||
|
|
||||||
private readonly Dictionary<Item, GUIFrame> itemPreviews = new Dictionary<Item, GUIFrame>();
|
private UpgradeCategory? currentUpgradeCategory;
|
||||||
|
private GUIButton? activeItemSwapSlideDown;
|
||||||
|
|
||||||
|
private readonly Dictionary<Item, GUIComponent> itemPreviews = new Dictionary<Item, GUIComponent>();
|
||||||
|
|
||||||
private static readonly Color previewWhite = Color.White * 0.5f;
|
private static readonly Color previewWhite = Color.White * 0.5f;
|
||||||
|
|
||||||
@@ -94,6 +102,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
CreateUI(upgradeFrame);
|
CreateUI(upgradeFrame);
|
||||||
|
|
||||||
|
if (Campaign == null) { return; }
|
||||||
Campaign.UpgradeManager.OnUpgradesChanged += RefreshAll;
|
Campaign.UpgradeManager.OnUpgradesChanged += RefreshAll;
|
||||||
Campaign.CargoManager.OnPurchasedItemsChanged += RefreshAll;
|
Campaign.CargoManager.OnPurchasedItemsChanged += RefreshAll;
|
||||||
Campaign.CargoManager.OnSoldItemsChanged += RefreshAll;
|
Campaign.CargoManager.OnSoldItemsChanged += RefreshAll;
|
||||||
@@ -103,29 +112,41 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
switch (selectedUpgradTab)
|
switch (selectedUpgradTab)
|
||||||
{
|
{
|
||||||
case UpgradeTab.Repairs:
|
case UpgradeTab.Repairs:
|
||||||
{
|
|
||||||
SelectTab(UpgradeTab.Repairs);
|
SelectTab(UpgradeTab.Repairs);
|
||||||
break;
|
break;
|
||||||
}
|
case UpgradeTab.Upgrade:
|
||||||
case UpgradeTab.Upgrade:
|
|
||||||
{
|
|
||||||
RefreshUpgradeList();
|
RefreshUpgradeList();
|
||||||
break;
|
foreach (var itemPreview in itemPreviews)
|
||||||
}
|
{
|
||||||
|
if (itemPreview.Key?.PendingItemSwap?.UpgradePreviewSprite == null) { continue; }
|
||||||
|
if (!(itemPreview.Value is GUIImage image)) { continue; }
|
||||||
|
image.Sprite = itemPreview.Key.PendingItemSwap.UpgradePreviewSprite;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshUpgradeList()
|
private void RefreshUpgradeList()
|
||||||
{
|
{
|
||||||
|
if (Campaign == null) { return; }
|
||||||
// Updates the progress bar / text and disables the buy button if we reached max level
|
// Updates the progress bar / text and disables the buy button if we reached max level
|
||||||
if (selectedUpgradeCategoryLayout?.Parent != null && selectedUpgradeCategoryLayout.FindChild("prefablist", true) is GUIListBox listBox)
|
if (selectedUpgradeCategoryLayout?.Parent != null && selectedUpgradeCategoryLayout.FindChild("prefablist", true) is GUIListBox listBox)
|
||||||
{
|
{
|
||||||
foreach (var component in listBox.Content.Children)
|
foreach (var component in listBox.Content.Children)
|
||||||
{
|
{
|
||||||
if (component.UserData is CategoryData data)
|
if (component.UserData is CategoryData { SinglePrefab: { } prefab} data)
|
||||||
{
|
{
|
||||||
UpdateUpgradeEntry(component, data.SinglePrefab, data.Category, Campaign);
|
UpdateUpgradeEntry(component, prefab, data.Category, Campaign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (customizeTabOpen && selectedUpgradeCategoryLayout != null && Submarine.MainSub != null && currentUpgradeCategory != null)
|
||||||
|
{
|
||||||
|
CreateSwappableItemList(listBox, currentUpgradeCategory, Submarine.MainSub);
|
||||||
|
if (activeItemSwapSlideDown?.UserData is Item prevOpenedItem)
|
||||||
|
{
|
||||||
|
var currentButton = listBox.FindChild(c => c.UserData as Item == prevOpenedItem, recursive: true) as GUIButton;
|
||||||
|
currentButton?.OnClicked(currentButton, prevOpenedItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,16 +156,18 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
UpdateCategoryList(currentStoreLayout, Campaign, drawnSubmarine, applicableCategories);
|
UpdateCategoryList(currentStoreLayout, Campaign, drawnSubmarine, applicableCategories);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: move this somewhere else
|
//TODO: move this somewhere else
|
||||||
public static void UpdateCategoryList(GUIListBox categoryList, CampaignMode campaign, Submarine drawnSubmarine, IEnumerable<UpgradeCategory> applicableCategories)
|
public static void UpdateCategoryList(GUIListBox categoryList, CampaignMode campaign, Submarine? drawnSubmarine, IEnumerable<UpgradeCategory> applicableCategories)
|
||||||
{
|
{
|
||||||
foreach (GUIComponent component in categoryList.Content.Children)
|
foreach (GUIComponent component in categoryList.Content.Children)
|
||||||
{
|
{
|
||||||
if (!(component.UserData is CategoryData data)) { continue; }
|
if (!(component.UserData is CategoryData data)) { continue; }
|
||||||
if (component.FindChild("indicators", true) is { } indicators)
|
if (component.FindChild("indicators", true) is { } indicators && data.Prefabs != null)
|
||||||
{
|
{
|
||||||
|
// ReSharper disable once PossibleMultipleEnumeration
|
||||||
UpdateCategoryIndicators(indicators, component, data.Prefabs, data.Category, campaign, drawnSubmarine, applicableCategories);
|
UpdateCategoryIndicators(indicators, component, data.Prefabs, data.Category, campaign, drawnSubmarine, applicableCategories);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,7 +275,7 @@ namespace Barotrauma
|
|||||||
GUILayoutGroup rightLayout = new GUILayoutGroup(rectT(0.5f, 1, topHeaderLayout), childAnchor: Anchor.TopRight);
|
GUILayoutGroup rightLayout = new GUILayoutGroup(rectT(0.5f, 1, topHeaderLayout), childAnchor: Anchor.TopRight);
|
||||||
GUILayoutGroup priceLayout = new GUILayoutGroup(rectT(1, 0.8f, rightLayout), childAnchor: Anchor.Center) { RelativeSpacing = 0.08f };
|
GUILayoutGroup priceLayout = new GUILayoutGroup(rectT(1, 0.8f, rightLayout), childAnchor: Anchor.Center) { RelativeSpacing = 0.08f };
|
||||||
new GUITextBlock(rectT(1f, 0f, priceLayout), TextManager.Get("CampaignStore.Balance"), font: GUI.SubHeadingFont, textAlignment: Alignment.Right);
|
new GUITextBlock(rectT(1f, 0f, priceLayout), TextManager.Get("CampaignStore.Balance"), font: GUI.SubHeadingFont, textAlignment: Alignment.Right);
|
||||||
new GUITextBlock(rectT(1f, 0f, priceLayout), FormatCurrency(Campaign.Money, format: true), font: GUI.SubHeadingFont, textAlignment: Alignment.Right) { TextGetter = () => FormatCurrency(Campaign.Money, format: true) };
|
new GUITextBlock(rectT(1f, 0f, priceLayout), FormatCurrency(AvailableMoney, format: true), font: GUI.SubHeadingFont, textAlignment: Alignment.Right) { TextGetter = () => FormatCurrency(AvailableMoney, format: true) };
|
||||||
new GUIFrame(rectT(0.5f, 0.1f, rightLayout, Anchor.BottomRight), style: "HorizontalLine") { IgnoreLayoutGroups = true };
|
new GUIFrame(rectT(0.5f, 0.1f, rightLayout, Anchor.BottomRight), style: "HorizontalLine") { IgnoreLayoutGroups = true };
|
||||||
|
|
||||||
repairButton.OnClicked = upgradeButton.OnClicked = (button, o) =>
|
repairButton.OnClicked = upgradeButton.OnClicked = (button, o) =>
|
||||||
@@ -304,12 +327,12 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (currentStoreLayout != null)
|
if (currentStoreLayout != null)
|
||||||
{
|
{
|
||||||
storeLayout.RemoveChild(currentStoreLayout);
|
storeLayout?.RemoveChild(currentStoreLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedUpgradeCategoryLayout != null)
|
if (selectedUpgradeCategoryLayout != null)
|
||||||
{
|
{
|
||||||
mainStoreLayout.RemoveChild(selectedUpgradeCategoryLayout);
|
mainStoreLayout?.RemoveChild(selectedUpgradeCategoryLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (tab)
|
switch (tab)
|
||||||
@@ -329,8 +352,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CreateRepairsTab()
|
private void CreateRepairsTab()
|
||||||
{
|
{
|
||||||
|
if (Campaign == null || storeLayout == null) { return; }
|
||||||
|
|
||||||
highlightWalls = false;
|
highlightWalls = false;
|
||||||
foreach (GUIFrame itemFrame in itemPreviews.Values)
|
foreach (GUIComponent itemFrame in itemPreviews.Values)
|
||||||
{
|
{
|
||||||
itemFrame.OutlineColor = previewWhite;
|
itemFrame.OutlineColor = previewWhite;
|
||||||
}
|
}
|
||||||
@@ -355,12 +380,12 @@ namespace Barotrauma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Campaign.Money >= hullRepairCost)
|
if (AvailableMoney >= hullRepairCost)
|
||||||
{
|
{
|
||||||
string body = TextManager.GetWithVariable("WallRepairs.PurchasePromptBody", "[amount]", hullRepairCost.ToString());
|
string body = TextManager.GetWithVariable("WallRepairs.PurchasePromptBody", "[amount]", hullRepairCost.ToString());
|
||||||
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), body, () =>
|
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), body, () =>
|
||||||
{
|
{
|
||||||
if (Campaign.Money >= hullRepairCost)
|
if (AvailableMoney >= hullRepairCost)
|
||||||
{
|
{
|
||||||
Campaign.Money -= hullRepairCost;
|
Campaign.Money -= hullRepairCost;
|
||||||
Campaign.PurchasedHullRepairs = true;
|
Campaign.PurchasedHullRepairs = true;
|
||||||
@@ -389,12 +414,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
CreateRepairEntry(currentStoreLayout.Content, TextManager.Get("repairallitems"), "RepairItemsButton", itemRepairCost, (button, o) =>
|
CreateRepairEntry(currentStoreLayout.Content, TextManager.Get("repairallitems"), "RepairItemsButton", itemRepairCost, (button, o) =>
|
||||||
{
|
{
|
||||||
if (Campaign.Money >= itemRepairCost && !Campaign.PurchasedItemRepairs)
|
if (AvailableMoney >= itemRepairCost && !Campaign.PurchasedItemRepairs)
|
||||||
{
|
{
|
||||||
string body = TextManager.GetWithVariable("ItemRepairs.PurchasePromptBody", "[amount]", itemRepairCost.ToString());
|
string body = TextManager.GetWithVariable("ItemRepairs.PurchasePromptBody", "[amount]", itemRepairCost.ToString());
|
||||||
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), body, () =>
|
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), body, () =>
|
||||||
{
|
{
|
||||||
if (Campaign.Money >= itemRepairCost && !Campaign.PurchasedItemRepairs)
|
if (AvailableMoney >= itemRepairCost && !Campaign.PurchasedItemRepairs)
|
||||||
{
|
{
|
||||||
Campaign.Money -= itemRepairCost;
|
Campaign.Money -= itemRepairCost;
|
||||||
Campaign.PurchasedItemRepairs = true;
|
Campaign.PurchasedItemRepairs = true;
|
||||||
@@ -434,12 +459,12 @@ namespace Barotrauma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Campaign.Money >= shuttleRetrieveCost && !Campaign.PurchasedLostShuttles)
|
if (AvailableMoney >= shuttleRetrieveCost && !Campaign.PurchasedLostShuttles)
|
||||||
{
|
{
|
||||||
string body = TextManager.GetWithVariable("ReplaceLostShuttles.PurchasePromptBody", "[amount]", shuttleRetrieveCost.ToString());
|
string body = TextManager.GetWithVariable("ReplaceLostShuttles.PurchasePromptBody", "[amount]", shuttleRetrieveCost.ToString());
|
||||||
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), body, () =>
|
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), body, () =>
|
||||||
{
|
{
|
||||||
if (Campaign.Money >= shuttleRetrieveCost && !Campaign.PurchasedLostShuttles)
|
if (AvailableMoney >= shuttleRetrieveCost && !Campaign.PurchasedLostShuttles)
|
||||||
{
|
{
|
||||||
Campaign.Money -= shuttleRetrieveCost;
|
Campaign.Money -= shuttleRetrieveCost;
|
||||||
Campaign.PurchasedLostShuttles = true;
|
Campaign.PurchasedLostShuttles = true;
|
||||||
@@ -460,12 +485,13 @@ namespace Barotrauma
|
|||||||
}, Campaign.PurchasedLostShuttles || !HasPermission || GameMain.GameSession?.SubmarineInfo == null || !GameMain.GameSession.SubmarineInfo.SubsLeftBehind, isHovered =>
|
}, Campaign.PurchasedLostShuttles || !HasPermission || GameMain.GameSession?.SubmarineInfo == null || !GameMain.GameSession.SubmarineInfo.SubsLeftBehind, isHovered =>
|
||||||
{
|
{
|
||||||
if (!isHovered) { return false; }
|
if (!isHovered) { return false; }
|
||||||
|
if (!(GameMain.GameSession?.SubmarineInfo is { } subInfo)) { return false; }
|
||||||
|
|
||||||
foreach (var (item, itemFrame) in itemPreviews)
|
foreach (var (item, itemFrame) in itemPreviews)
|
||||||
{
|
{
|
||||||
if (GameMain.GameSession.SubmarineInfo.LeftBehindDockingPortIDs.Contains(item.ID))
|
if (subInfo.LeftBehindDockingPortIDs.Contains(item.ID))
|
||||||
{
|
{
|
||||||
itemFrame.OutlineColor = itemFrame.Color = GameMain.GameSession.SubmarineInfo.BlockedDockingPortIDs.Contains(item.ID) ? GUI.Style.Red : GUI.Style.Green;
|
itemFrame.OutlineColor = itemFrame.Color = subInfo.BlockedDockingPortIDs.Contains(item.ID) ? GUI.Style.Red : GUI.Style.Green;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -476,7 +502,7 @@ namespace Barotrauma
|
|||||||
}, disableElement: true);
|
}, disableElement: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateRepairEntry(GUIComponent parent, string title, string imageStyle, int price, GUIButton.OnClickedHandler onPressed, bool isDisabled, Func<bool, bool> onHover = null, bool disableElement = false)
|
private void CreateRepairEntry(GUIComponent parent, string title, string imageStyle, int price, GUIButton.OnClickedHandler onPressed, bool isDisabled, Func<bool, bool>? onHover = null, bool disableElement = false)
|
||||||
{
|
{
|
||||||
GUIFrame frameChild = new GUIFrame(rectT(new Point(parent.Rect.Width, (int) (96 * GUI.Scale)), parent), style: "UpgradeUIFrame");
|
GUIFrame frameChild = new GUIFrame(rectT(new Point(parent.Rect.Width, (int) (96 * GUI.Scale)), parent), style: "UpgradeUIFrame");
|
||||||
frameChild.SelectedColor = frameChild.Color;
|
frameChild.SelectedColor = frameChild.Color;
|
||||||
@@ -497,13 +523,13 @@ namespace Barotrauma
|
|||||||
new GUITextBlock(rectT(1, 0, textLayout), title, font: GUI.SubHeadingFont) { CanBeFocused = false, AutoScaleHorizontal = true };
|
new GUITextBlock(rectT(1, 0, textLayout), title, font: GUI.SubHeadingFont) { CanBeFocused = false, AutoScaleHorizontal = true };
|
||||||
new GUITextBlock(rectT(1, 0, textLayout), FormatCurrency(price));
|
new GUITextBlock(rectT(1, 0, textLayout), FormatCurrency(price));
|
||||||
GUILayoutGroup buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, contentLayout), childAnchor: Anchor.Center) { UserData = "buybutton" };
|
GUILayoutGroup buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, contentLayout), childAnchor: Anchor.Center) { UserData = "buybutton" };
|
||||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { ClickSound = GUISoundType.HireRepairClick, Enabled = Campaign.Money >= price && !isDisabled, OnClicked = onPressed };
|
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { ClickSound = GUISoundType.HireRepairClick, Enabled = AvailableMoney >= price && !isDisabled, OnClicked = onPressed };
|
||||||
contentLayout.Recalculate();
|
contentLayout.Recalculate();
|
||||||
buyButtonLayout.Recalculate();
|
buyButtonLayout.Recalculate();
|
||||||
|
|
||||||
if (disableElement)
|
if (disableElement)
|
||||||
{
|
{
|
||||||
frameChild.Enabled = Campaign.Money >= price && !isDisabled;
|
frameChild.Enabled = AvailableMoney >= price && !isDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!HasPermission)
|
if (!HasPermission)
|
||||||
@@ -594,6 +620,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CreateUpgradeTab()
|
private void CreateUpgradeTab()
|
||||||
{
|
{
|
||||||
|
if (storeLayout == null || mainStoreLayout == null) { return; }
|
||||||
currentStoreLayout = CreateUpgradeCategoryList(rectT(1.0f, 1.5f, storeLayout));
|
currentStoreLayout = CreateUpgradeCategoryList(rectT(1.0f, 1.5f, storeLayout));
|
||||||
|
|
||||||
selectedUpgradeCategoryLayout = new GUIFrame(rectT(GUI.IsFourByThree() ? 0.3f : 0.25f, 1, mainStoreLayout), style: null) { CanBeFocused = false };
|
selectedUpgradeCategoryLayout = new GUIFrame(rectT(GUI.IsFourByThree() ? 0.3f : 0.25f, 1, mainStoreLayout), style: null) { CanBeFocused = false };
|
||||||
@@ -605,16 +632,16 @@ namespace Barotrauma
|
|||||||
if (!component.Enabled)
|
if (!component.Enabled)
|
||||||
{
|
{
|
||||||
selectedUpgradeCategoryLayout?.ClearChildren();
|
selectedUpgradeCategoryLayout?.ClearChildren();
|
||||||
foreach (GUIFrame itemFrame in itemPreviews.Values)
|
foreach (GUIComponent itemFrame in itemPreviews.Values)
|
||||||
{
|
{
|
||||||
itemFrame.OutlineColor = itemFrame.Color = previewWhite;
|
itemFrame.OutlineColor = itemFrame.Color = previewWhite;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userData is CategoryData categoryData && Submarine.MainSub != null)
|
if (userData is CategoryData categoryData && Submarine.MainSub is { } sub && categoryData.Prefabs is { } prefabs)
|
||||||
{
|
{
|
||||||
TrySelectCategory(categoryData.Prefabs, categoryData.Category, Submarine.MainSub);
|
TrySelectCategory(prefabs, categoryData.Category, sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -624,35 +651,296 @@ namespace Barotrauma
|
|||||||
// This was supposed to have some logic for fancy animations to slide the previous tab out but maybe another time
|
// This was supposed to have some logic for fancy animations to slide the previous tab out but maybe another time
|
||||||
private void TrySelectCategory(List<UpgradePrefab> prefabs, UpgradeCategory category, Submarine submarine) => SelectUpgradeCategory(prefabs, category, submarine);
|
private void TrySelectCategory(List<UpgradePrefab> prefabs, UpgradeCategory category, Submarine submarine) => SelectUpgradeCategory(prefabs, category, submarine);
|
||||||
|
|
||||||
|
private bool customizeTabOpen;
|
||||||
|
|
||||||
private void SelectUpgradeCategory(List<UpgradePrefab> prefabs, UpgradeCategory category, Submarine submarine)
|
private void SelectUpgradeCategory(List<UpgradePrefab> prefabs, UpgradeCategory category, Submarine submarine)
|
||||||
{
|
{
|
||||||
if (selectedUpgradeCategoryLayout == null || submarine == null) { return; }
|
if (selectedUpgradeCategoryLayout == null) { return; }
|
||||||
|
|
||||||
GUIFrame[] categoryFrames = GetFrames(category);
|
customizeTabOpen = false;
|
||||||
foreach (GUIFrame itemFrame in itemPreviews.Values)
|
|
||||||
|
GUIComponent[] categoryFrames = GetFrames(category);
|
||||||
|
foreach (GUIComponent itemFrame in itemPreviews.Values)
|
||||||
{
|
{
|
||||||
itemFrame.OutlineColor = itemFrame.Color = categoryFrames.Contains(itemFrame) ? GUI.Style.Orange : previewWhite;
|
itemFrame.OutlineColor = itemFrame.Color = categoryFrames.Contains(itemFrame) ? GUI.Style.Orange : previewWhite;
|
||||||
}
|
}
|
||||||
|
|
||||||
highlightWalls = category.IsWallUpgrade;
|
highlightWalls = category.IsWallUpgrade;
|
||||||
|
|
||||||
selectedUpgradeCategoryLayout?.ClearChildren();
|
selectedUpgradeCategoryLayout.ClearChildren();
|
||||||
GUIFrame frame = new GUIFrame(rectT(1, 0.4f, selectedUpgradeCategoryLayout));
|
GUIFrame frame = new GUIFrame(rectT(1.0f, 0.4f, selectedUpgradeCategoryLayout));
|
||||||
GUIListBox prefabList = new GUIListBox(rectT(0.93f, 0.9f, frame, Anchor.Center)) { UserData = "prefablist" };
|
GUIFrame paddedFrame = new GUIFrame(rectT(0.93f, 0.9f, frame, Anchor.Center), style: null);
|
||||||
|
|
||||||
List<Item> entitiesOnSub = null;
|
bool hasSwappableItems = Submarine.MainSub.GetItems(true).Any(i =>
|
||||||
|
i.Prefab.SwappableItem != null && (i.Prefab.SwappableItem.CanBeBought || ItemPrefab.Prefabs.Any(ip => ip.SwappableItem?.ReplacementOnUninstall == i.Prefab.Identifier)) &&
|
||||||
|
Submarine.MainSub.IsEntityFoundOnThisSub(i, true) && category.ItemTags.Any(t => i.HasTag(t)));
|
||||||
|
|
||||||
|
float listHeight = hasSwappableItems ? 0.9f : 1.0f;
|
||||||
|
|
||||||
|
GUIListBox prefabList = new GUIListBox(rectT(1.0f, listHeight, paddedFrame, Anchor.BottomLeft))
|
||||||
|
{
|
||||||
|
UserData = "prefablist",
|
||||||
|
AutoHideScrollBar = false,
|
||||||
|
ScrollBarVisible = true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (hasSwappableItems)
|
||||||
|
{
|
||||||
|
GUILayoutGroup buttonLayout = new GUILayoutGroup(rectT(1.0f, 0.1f, paddedFrame, anchor: Anchor.TopLeft), isHorizontal: true);
|
||||||
|
|
||||||
|
GUIButton upgradeButton = new GUIButton(rectT(0.5f, 1f, buttonLayout), text: TextManager.Get("uicategory.upgrades"), style: "GUITabButton")
|
||||||
|
{
|
||||||
|
Selected = true
|
||||||
|
};
|
||||||
|
|
||||||
|
GUIButton customizeButton = new GUIButton(rectT(0.5f, 1f, buttonLayout), text: TextManager.Get("uicategory.customize"), style: "GUITabButton");
|
||||||
|
|
||||||
|
upgradeButton.OnClicked = delegate
|
||||||
|
{
|
||||||
|
customizeTabOpen = false;
|
||||||
|
customizeButton.Selected = false;
|
||||||
|
upgradeButton.Selected = true;
|
||||||
|
CreateUpgradePrefabList(prefabList, category, prefabs, submarine);
|
||||||
|
GUIComponent[] categoryFrames = GetFrames(category);
|
||||||
|
foreach (GUIComponent itemFrame in itemPreviews.Values)
|
||||||
|
{
|
||||||
|
itemFrame.OutlineColor = itemFrame.Color = categoryFrames.Contains(itemFrame) ? GUI.Style.Orange : previewWhite;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
customizeButton.OnClicked = delegate
|
||||||
|
{
|
||||||
|
customizeTabOpen = true;
|
||||||
|
customizeButton.Selected = true;
|
||||||
|
upgradeButton.Selected = false;
|
||||||
|
CreateSwappableItemList(prefabList, category, submarine);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateUpgradePrefabList(prefabList, category, prefabs, submarine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateUpgradePrefabList(GUIListBox parent, UpgradeCategory category, List<UpgradePrefab> prefabs, Submarine submarine)
|
||||||
|
{
|
||||||
|
parent.Content.ClearChildren();
|
||||||
|
List<Item>? entitiesOnSub = null;
|
||||||
if (!category.IsWallUpgrade)
|
if (!category.IsWallUpgrade)
|
||||||
{
|
{
|
||||||
entitiesOnSub = submarine.GetItems(true).Where(i => submarine.IsEntityFoundOnThisSub(i, true)).ToList();
|
entitiesOnSub = submarine.GetItems(true).Where(i => submarine.IsEntityFoundOnThisSub(i, true)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (UpgradePrefab prefab in prefabs)
|
foreach (UpgradePrefab prefab in prefabs)
|
||||||
{
|
{
|
||||||
CreateUpgradeEntry(prefab, category, prefabList.Content, entitiesOnSub);
|
CreateUpgradeEntry(prefab, category, parent.Content, entitiesOnSub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateSwappableItemList(GUIListBox parent, UpgradeCategory category, Submarine submarine)
|
||||||
|
{
|
||||||
|
parent.Content.ClearChildren();
|
||||||
|
currentUpgradeCategory = category;
|
||||||
|
IEnumerable<ItemPrefab> availableReplacements = MapEntityPrefab.List.Where(p =>
|
||||||
|
p is ItemPrefab itemPrefab &&
|
||||||
|
category.ItemTags.Any(t => itemPrefab.Tags.Contains(t)) &&
|
||||||
|
(itemPrefab.SwappableItem?.CanBeBought ?? false)).Cast<ItemPrefab>();
|
||||||
|
var entitiesOnSub = submarine.GetItems(true).Where(i => submarine.IsEntityFoundOnThisSub(i, true) && category.ItemTags.Any(t => i.HasTag(t))).ToList();
|
||||||
|
|
||||||
|
int slotIndex = 0;
|
||||||
|
foreach (Item item in entitiesOnSub)
|
||||||
|
{
|
||||||
|
slotIndex++;
|
||||||
|
CreateSwappableItemSlideDown(parent, slotIndex, item, availableReplacements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateSwappableItemSlideDown(GUIListBox parent, int slotIndex, Item item, IEnumerable<ItemPrefab> availableReplacements)
|
||||||
|
{
|
||||||
|
if (Campaign == null) { return; }
|
||||||
|
|
||||||
|
var currentOrPending = item.PendingItemSwap ?? item.Prefab;
|
||||||
|
|
||||||
|
bool isOpen = false;
|
||||||
|
GUIButton toggleButton = new GUIButton(rectT(1f, 0.1f, parent.Content), text: string.Empty, style: "SlideDown")
|
||||||
|
{
|
||||||
|
UserData = item
|
||||||
|
};
|
||||||
|
GUILayoutGroup buttonLayout = new GUILayoutGroup(rectT(1f, 1f, toggleButton.Frame), isHorizontal: true);
|
||||||
|
new GUITextBlock(rectT(0.3f, 1f, buttonLayout), text: TextManager.GetWithVariable("weaponslot", "[number]", slotIndex.ToString()), font: GUI.SubHeadingFont);
|
||||||
|
GUILayoutGroup group = new GUILayoutGroup(rectT(0.7f, 1f, buttonLayout), isHorizontal: true) { Stretch = true };
|
||||||
|
|
||||||
|
string title = item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", currentOrPending.Name) : item.Name;
|
||||||
|
GUITextBlock text = new GUITextBlock(rectT(0.7f, 1f, group), text: title, font: GUI.SubHeadingFont, textAlignment: Alignment.Right, parseRichText: true)
|
||||||
|
{
|
||||||
|
TextColor = GUI.Style.Orange
|
||||||
|
};
|
||||||
|
GUIImage arrowImage = new GUIImage(rectT(0.5f, 1f, group, scaleBasis: ScaleBasis.BothHeight), style: "SlideDownArrow", scaleToFit: true);
|
||||||
|
|
||||||
|
group.Recalculate();
|
||||||
|
if (text.TextSize.X > text.Rect.Width)
|
||||||
|
{
|
||||||
|
text.ToolTip = text.Text;
|
||||||
|
text.Text = ToolBox.LimitString(text.Text, text.Font, text.Rect.Width);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GUIFrame> frames = new List<GUIFrame>();
|
||||||
|
if (currentOrPending != null)
|
||||||
|
{
|
||||||
|
bool canUninstall = item.PendingItemSwap != null || !string.IsNullOrEmpty(currentOrPending.SwappableItem?.ReplacementOnUninstall);
|
||||||
|
|
||||||
|
bool isUninstallPending = item.PendingItemSwap?.Identifier == item.Prefab.SwappableItem.ReplacementOnUninstall;
|
||||||
|
if (isUninstallPending) { canUninstall = false; }
|
||||||
|
|
||||||
|
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), currentOrPending.UpgradePreviewSprite,
|
||||||
|
TextManager.GetWithVariable(item.PendingItemSwap != null ? "upgrades.pendingitem" : "upgrades.installeditem", "[itemname]", currentOrPending.Name),
|
||||||
|
currentOrPending.Description,
|
||||||
|
0, null, addBuyButton: canUninstall, addProgressBar: false, buttonStyle: "StoreRemoveFromCrateButton"));
|
||||||
|
|
||||||
|
if (canUninstall && frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton refundButton)
|
||||||
|
{
|
||||||
|
refundButton.Enabled = true;
|
||||||
|
refundButton.OnClicked += (button, o) =>
|
||||||
|
{
|
||||||
|
string textTag = item.PendingItemSwap != null ? "upgrades.cancelitemswappromptbody" : "upgrades.itemuninstallpromptbody";
|
||||||
|
if (isUninstallPending) { textTag = "upgrades.cancelitemuninstallpromptbody"; }
|
||||||
|
string promptBody = TextManager.GetWithVariables(textTag,
|
||||||
|
new[] { "[itemtouninstall]" },
|
||||||
|
new[] { isUninstallPending ? item.Name : currentOrPending.Name });
|
||||||
|
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("upgrades.refundprompttitle"), promptBody, () =>
|
||||||
|
{
|
||||||
|
if (GameMain.NetworkMember != null)
|
||||||
|
{
|
||||||
|
WaitForServerUpdate = true;
|
||||||
|
}
|
||||||
|
Campaign?.UpgradeManager.CancelItemSwap(item);
|
||||||
|
GameMain.Client?.SendCampaignState();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var dividerContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), parent.Content.RectTransform), style: null);
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(0.8f, 0.5f), dividerContainer.RectTransform, Anchor.Center), style: "HorizontalLine");
|
||||||
|
frames.Add(dividerContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ItemPrefab replacement in availableReplacements)
|
||||||
|
{
|
||||||
|
if (replacement == currentOrPending) { continue; }
|
||||||
|
|
||||||
|
bool isPurchased = item.AvailableSwaps.Contains(replacement);
|
||||||
|
|
||||||
|
int price = isPurchased || replacement == item.Prefab ? 0 : replacement.SwappableItem.GetPrice(Campaign.Map?.CurrentLocation);
|
||||||
|
|
||||||
|
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), replacement.UpgradePreviewSprite, replacement.Name, replacement.Description,
|
||||||
|
price, null,
|
||||||
|
addBuyButton: true,
|
||||||
|
addProgressBar: false,
|
||||||
|
buttonStyle: isPurchased ? "UpgradeBuyButton" : "StoreAddToCrateButton"));
|
||||||
|
|
||||||
|
if (!(frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton buyButton)) { continue; }
|
||||||
|
if (Campaign.Money >= price)
|
||||||
|
{
|
||||||
|
buyButton.Enabled = true;
|
||||||
|
buyButton.OnClicked += (button, o) =>
|
||||||
|
{
|
||||||
|
string promptBody = TextManager.GetWithVariables(isPurchased ? "upgrades.itemswappromptbody" : "upgrades.purchaseitemswappromptbody",
|
||||||
|
new[] { "[itemtoinstall]", "[amount]" },
|
||||||
|
new[] { replacement.Name, replacement.SwappableItem.GetPrice(Campaign?.Map?.CurrentLocation).ToString() });
|
||||||
|
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), promptBody, () =>
|
||||||
|
{
|
||||||
|
if (GameMain.NetworkMember != null)
|
||||||
|
{
|
||||||
|
WaitForServerUpdate = true;
|
||||||
|
}
|
||||||
|
if (item.Prefab == replacement && item.PendingItemSwap != null)
|
||||||
|
{
|
||||||
|
Campaign?.UpgradeManager.CancelItemSwap(item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Campaign?.UpgradeManager.PurchaseItemSwap(item, replacement);
|
||||||
|
}
|
||||||
|
GameMain.Client?.SendCampaignState();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buyButton.Enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (GUIFrame frame in frames)
|
||||||
|
{
|
||||||
|
frame.Visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleButton.OnClicked = delegate
|
||||||
|
{
|
||||||
|
isOpen = !isOpen;
|
||||||
|
toggleButton.Selected = !toggleButton.Selected;
|
||||||
|
foreach (GUIFrame frame in frames)
|
||||||
|
{
|
||||||
|
frame.Visible = toggleButton.Selected;
|
||||||
|
}
|
||||||
|
if (toggleButton.Selected)
|
||||||
|
{
|
||||||
|
foreach (var itemPreview in itemPreviews)
|
||||||
|
{
|
||||||
|
itemPreview.Value.OutlineColor = itemPreview.Value.Color = itemPreview.Key == item ? GUI.Style.Orange : previewWhite;
|
||||||
|
}
|
||||||
|
foreach (GUIComponent otherComponent in toggleButton.Parent.Children)
|
||||||
|
{
|
||||||
|
if (otherComponent == toggleButton || frames.Contains(otherComponent)) { continue; }
|
||||||
|
if (otherComponent is GUIButton otherButton)
|
||||||
|
{
|
||||||
|
var otherArrowImage = otherComponent.FindChild(c => c is GUIImage, recursive: true);
|
||||||
|
otherArrowImage.SpriteEffects = SpriteEffects.None;
|
||||||
|
otherButton.Selected = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
otherComponent.Visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var itemPreview in itemPreviews)
|
||||||
|
{
|
||||||
|
if (currentStoreLayout?.SelectedData is CategoryData categoryData && !categoryData.Category.ItemTags.Any(t => itemPreview.Key.HasTag(t))) { continue; }
|
||||||
|
itemPreview.Value.OutlineColor = itemPreview.Value.Color = GUI.Style.Orange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activeItemSwapSlideDown = toggleButton.Selected ? toggleButton : null;
|
||||||
|
arrowImage.SpriteEffects = toggleButton.Selected ? SpriteEffects.FlipVertically : SpriteEffects.None;
|
||||||
|
parent.RecalculateChildren();
|
||||||
|
parent.UpdateScrollBarSize();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static GUIFrame CreateUpgradeFrame(UpgradePrefab prefab, UpgradeCategory category, CampaignMode campaign, RectTransform rectTransform, bool addBuyButton = true)
|
public static GUIFrame CreateUpgradeFrame(UpgradePrefab prefab, UpgradeCategory category, CampaignMode campaign, RectTransform rectTransform, bool addBuyButton = true)
|
||||||
{
|
{
|
||||||
|
int price = prefab.Price.GetBuyprice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation);
|
||||||
|
return CreateUpgradeEntry(rectTransform, prefab.Sprite, prefab.Name, prefab.Description, price, new CategoryData(category, prefab), addBuyButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GUIFrame CreateUpgradeEntry(RectTransform parent, Sprite sprite, string title, string body, int price, object? userData, bool addBuyButton = true, bool addProgressBar = true, string buttonStyle = "UpgradeBuyButton")
|
||||||
|
{
|
||||||
|
float progressBarHeight = 0.25f;
|
||||||
|
|
||||||
|
if (!addProgressBar)
|
||||||
|
{
|
||||||
|
progressBarHeight = 0f;
|
||||||
|
}
|
||||||
/* UPGRADE PREFAB ENTRY
|
/* UPGRADE PREFAB ENTRY
|
||||||
* |------------------------------------------------------------------|
|
* |------------------------------------------------------------------|
|
||||||
* | | title | price |
|
* | | title | price |
|
||||||
@@ -662,23 +950,40 @@ namespace Barotrauma
|
|||||||
* | | progress bar | x / y | |
|
* | | progress bar | x / y | |
|
||||||
* |------------------------------------------------------------------|
|
* |------------------------------------------------------------------|
|
||||||
*/
|
*/
|
||||||
GUIFrame prefabFrame = new GUIFrame(rectTransform, style: "ListBoxElement") { SelectedColor = Color.Transparent, UserData = new CategoryData(category, prefab) };
|
GUIFrame prefabFrame = new GUIFrame(parent, style: "ListBoxElement") { SelectedColor = Color.Transparent, UserData = userData };
|
||||||
GUILayoutGroup prefabLayout = new GUILayoutGroup(rectT(0.98f, 0.95f, prefabFrame, Anchor.Center), isHorizontal: true) { Stretch = true };
|
GUILayoutGroup prefabLayout = new GUILayoutGroup(rectT(0.98f, 0.95f, prefabFrame, Anchor.Center), isHorizontal: true) { Stretch = true };
|
||||||
GUILayoutGroup imageLayout = new GUILayoutGroup(rectT(new Point(prefabLayout.Rect.Height, prefabLayout.Rect.Height), prefabLayout), childAnchor: Anchor.Center);
|
GUILayoutGroup imageLayout = new GUILayoutGroup(rectT(new Point(prefabLayout.Rect.Height, prefabLayout.Rect.Height), prefabLayout), childAnchor: Anchor.Center);
|
||||||
var icon = new GUIImage(rectT(0.9f, 0.9f, imageLayout), prefab.Sprite, scaleToFit: true) { CanBeFocused = false };
|
var icon = new GUIImage(rectT(0.9f, 0.9f, imageLayout, scaleBasis: ScaleBasis.BothHeight), sprite, scaleToFit: true) { CanBeFocused = false };
|
||||||
GUILayoutGroup textLayout = new GUILayoutGroup(rectT(0.8f - imageLayout.RectTransform.RelativeSize.X, 1, prefabLayout));
|
GUILayoutGroup textLayout = new GUILayoutGroup(rectT(0.8f - imageLayout.RectTransform.RelativeSize.X, 1, prefabLayout));
|
||||||
var name = new GUITextBlock(rectT(1, 0.25f, textLayout), prefab.Name, font: GUI.SubHeadingFont) { AutoScaleHorizontal = true, AutoScaleVertical = true, Padding = Vector4.Zero };
|
var name = new GUITextBlock(rectT(1, 0.25f, textLayout), title, font: GUI.SubHeadingFont, parseRichText: true) { AutoScaleHorizontal = true, AutoScaleVertical = true, Padding = Vector4.Zero };
|
||||||
GUILayoutGroup descriptionLayout = new GUILayoutGroup(rectT(1, 0.50f, textLayout));
|
GUILayoutGroup descriptionLayout = new GUILayoutGroup(rectT(1, 0.75f - progressBarHeight, textLayout));
|
||||||
var description = new GUITextBlock(rectT(1, 1, descriptionLayout), prefab.Description, font: GUI.SmallFont, wrap: true, textAlignment: Alignment.TopLeft) { Padding = Vector4.Zero };
|
var description = new GUITextBlock(rectT(1, 1, descriptionLayout), body, font: GUI.SmallFont, wrap: true, textAlignment: Alignment.TopLeft) { Padding = Vector4.Zero };
|
||||||
GUILayoutGroup progressLayout = new GUILayoutGroup(rectT(1, 0.25f, textLayout), isHorizontal: true, childAnchor: Anchor.CenterLeft) { UserData = "progressbar" };
|
GUILayoutGroup? progressLayout = null;
|
||||||
new GUIProgressBar(rectT(0.8f, 0.75f, progressLayout), 0.0f, GUI.Style.Orange);
|
GUILayoutGroup? buyButtonLayout = null;
|
||||||
new GUITextBlock(rectT(0.2f, 1, progressLayout), string.Empty, font: GUI.SmallFont, textAlignment: Alignment.Center) { Padding = Vector4.Zero };
|
|
||||||
GUILayoutGroup buyButtonLayout = null;
|
if (addProgressBar)
|
||||||
|
{
|
||||||
|
progressLayout = new GUILayoutGroup(rectT(1, 0.25f, textLayout), isHorizontal: true, childAnchor: Anchor.CenterLeft) { UserData = "progressbar" };
|
||||||
|
new GUIProgressBar(rectT(0.8f, 0.75f, progressLayout), 0.0f, GUI.Style.Orange);
|
||||||
|
new GUITextBlock(rectT(0.2f, 1, progressLayout), string.Empty, font: GUI.SmallFont, textAlignment: Alignment.Center) { Padding = Vector4.Zero };
|
||||||
|
}
|
||||||
|
|
||||||
if (addBuyButton)
|
if (addBuyButton)
|
||||||
{
|
{
|
||||||
buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, prefabLayout), childAnchor: Anchor.TopCenter) { UserData = "buybutton" };
|
string formattedPrice = FormatCurrency(Math.Abs(price));
|
||||||
new GUITextBlock(rectT(1, 0.4f, buyButtonLayout), FormatCurrency(prefab.Price.GetBuyprice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation)), textAlignment: Alignment.Center) { Padding = Vector4.Zero };
|
//negative price = refund
|
||||||
var buyButton = new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "UpgradeBuyButton") { Enabled = false };
|
if (price < 0) { formattedPrice = "+" + formattedPrice; }
|
||||||
|
buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, prefabLayout), childAnchor: Anchor.TopCenter) { UserData = "buybutton" };
|
||||||
|
var priceText = new GUITextBlock(rectT(1, 0.4f, buyButtonLayout), formattedPrice, textAlignment: Alignment.Center);
|
||||||
|
if (price < 0)
|
||||||
|
{
|
||||||
|
priceText.TextColor = GUI.Style.Green;
|
||||||
|
}
|
||||||
|
else if (price == 0)
|
||||||
|
{
|
||||||
|
priceText.Text = string.Empty;
|
||||||
|
}
|
||||||
|
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: buttonStyle) { Enabled = false };
|
||||||
}
|
}
|
||||||
|
|
||||||
description.CalculateHeightFromText();
|
description.CalculateHeightFromText();
|
||||||
@@ -691,24 +996,26 @@ namespace Barotrauma
|
|||||||
|
|
||||||
description.Text = newString.Substring(0, newString.Length - 4) + "...";
|
description.Text = newString.Substring(0, newString.Length - 4) + "...";
|
||||||
description.CalculateHeightFromText();
|
description.CalculateHeightFromText();
|
||||||
description.ToolTip = prefab.Description;
|
description.ToolTip = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculate everything to prevent jumping
|
// Recalculate everything to prevent jumping
|
||||||
if (rectTransform.Parent.GUIComponent is GUILayoutGroup group) { group.Recalculate(); }
|
if (parent.Parent.GUIComponent is GUILayoutGroup group) { group.Recalculate(); }
|
||||||
|
|
||||||
descriptionLayout.Recalculate();
|
descriptionLayout.Recalculate();
|
||||||
prefabLayout.Recalculate();
|
prefabLayout.Recalculate();
|
||||||
imageLayout.Recalculate();
|
imageLayout.Recalculate();
|
||||||
textLayout.Recalculate();
|
textLayout.Recalculate();
|
||||||
progressLayout.Recalculate();
|
progressLayout?.Recalculate();
|
||||||
buyButtonLayout?.Recalculate();
|
buyButtonLayout?.Recalculate();
|
||||||
|
|
||||||
return prefabFrame;
|
return prefabFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateUpgradeEntry(UpgradePrefab prefab, UpgradeCategory category, GUIComponent parent, List<Item> itemsOnSubmarine)
|
private void CreateUpgradeEntry(UpgradePrefab prefab, UpgradeCategory category, GUIComponent parent, List<Item>? itemsOnSubmarine)
|
||||||
{
|
{
|
||||||
|
if (Campaign is null) { return; }
|
||||||
|
|
||||||
GUIFrame prefabFrame = CreateUpgradeFrame(prefab, category, Campaign, rectT(1f, 0.25f, parent));
|
GUIFrame prefabFrame = CreateUpgradeFrame(prefab, category, Campaign, rectT(1f, 0.25f, parent));
|
||||||
var prefabLayout = prefabFrame.GetChild<GUILayoutGroup>();
|
var prefabLayout = prefabFrame.GetChild<GUILayoutGroup>();
|
||||||
GUILayoutGroup[] childLayouts = prefabLayout.GetAllChildren<GUILayoutGroup>().ToArray();
|
GUILayoutGroup[] childLayouts = prefabLayout.GetAllChildren<GUILayoutGroup>().ToArray();
|
||||||
@@ -723,7 +1030,7 @@ namespace Barotrauma
|
|||||||
var buyButtonLayout = childLayouts[2];
|
var buyButtonLayout = childLayouts[2];
|
||||||
var buyButton = buyButtonLayout.GetChild<GUIButton>();
|
var buyButton = buyButtonLayout.GetChild<GUIButton>();
|
||||||
|
|
||||||
if (!HasPermission || itemsOnSubmarine != null && !itemsOnSubmarine.Any(it => category.CanBeApplied(it, prefab)))
|
if (!HasPermission || (itemsOnSubmarine != null && !itemsOnSubmarine.Any(it => category.CanBeApplied(it, prefab))))
|
||||||
{
|
{
|
||||||
prefabFrame.Enabled = false;
|
prefabFrame.Enabled = false;
|
||||||
description.Enabled = false;
|
description.Enabled = false;
|
||||||
@@ -755,9 +1062,16 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CreateItemTooltip(MapEntity entity)
|
private void CreateItemTooltip(MapEntity entity)
|
||||||
{
|
{
|
||||||
GUITextBlock itemName = ItemInfoFrame.FindChild("itemname", true) as GUITextBlock;
|
int slotIndex = -1;
|
||||||
GUIListBox upgradeList = ItemInfoFrame.FindChild("upgradelist", true) as GUIListBox;
|
if (currentStoreLayout?.SelectedData is CategoryData categoryData)
|
||||||
GUITextBlock moreIndicator = ItemInfoFrame.FindChild("moreindicator", true) as GUITextBlock;
|
{
|
||||||
|
var entitiesOnSub = Submarine.MainSub.GetItems(true).Where(i => i.Prefab.SwappableItem != null && Submarine.MainSub.IsEntityFoundOnThisSub(i, true) && categoryData.Category.ItemTags.Any(t => i.HasTag(t))).ToList();
|
||||||
|
slotIndex = entitiesOnSub.IndexOf(entity) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GUITextBlock? itemName = ItemInfoFrame.FindChild("itemname", true) as GUITextBlock;
|
||||||
|
GUIListBox? upgradeList = ItemInfoFrame.FindChild("upgradelist", true) as GUIListBox;
|
||||||
|
GUITextBlock? moreIndicator = ItemInfoFrame.FindChild("moreindicator", true) as GUITextBlock;
|
||||||
GUILayoutGroup layout = ItemInfoFrame.GetChild<GUILayoutGroup>();
|
GUILayoutGroup layout = ItemInfoFrame.GetChild<GUILayoutGroup>();
|
||||||
Debug.Assert(itemName != null && upgradeList != null && moreIndicator != null && layout != null, "One ore more tooltip elements not found");
|
Debug.Assert(itemName != null && upgradeList != null && moreIndicator != null && layout != null, "One ore more tooltip elements not found");
|
||||||
|
|
||||||
@@ -766,6 +1080,10 @@ namespace Barotrauma
|
|||||||
const int maxUpgrades = 4;
|
const int maxUpgrades = 4;
|
||||||
|
|
||||||
itemName.Text = entity is Item ? entity.Name : TextManager.Get("upgradecategory.walls");
|
itemName.Text = entity is Item ? entity.Name : TextManager.Get("upgradecategory.walls");
|
||||||
|
if (slotIndex > -1)
|
||||||
|
{
|
||||||
|
itemName.Text = TextManager.GetWithVariables("weaponslotwithname", new string[] { "[number]", "[weaponname]" }, new string[] { slotIndex.ToString(), itemName.Text });
|
||||||
|
}
|
||||||
upgradeList.Content.ClearChildren();
|
upgradeList.Content.ClearChildren();
|
||||||
for (var i = 0; i < upgrades.Count && i < maxUpgrades; i++)
|
for (var i = 0; i < upgrades.Count && i < maxUpgrades; i++)
|
||||||
{
|
{
|
||||||
@@ -773,8 +1091,10 @@ namespace Barotrauma
|
|||||||
new GUITextBlock(rectT(1, 0.25f, upgradeList.Content), CreateListEntry(upgrade.Prefab.Name, upgrade.Level)) { AutoScaleHorizontal = true, UserData = Tuple.Create(upgrade.Level, upgrade.Prefab) };
|
new GUITextBlock(rectT(1, 0.25f, upgradeList.Content), CreateListEntry(upgrade.Prefab.Name, upgrade.Level)) { AutoScaleHorizontal = true, UserData = Tuple.Create(upgrade.Level, upgrade.Prefab) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(Campaign?.UpgradeManager is { } upgradeManager)) { return; }
|
||||||
|
|
||||||
// include pending upgrades into the tooltip
|
// include pending upgrades into the tooltip
|
||||||
foreach (var (prefab, category, level) in Campaign.UpgradeManager.PendingUpgrades)
|
foreach (var (prefab, category, level) in upgradeManager.PendingUpgrades)
|
||||||
{
|
{
|
||||||
if (entity is Item item && category.CanBeApplied(item, prefab) || entity is Structure && category.IsWallUpgrade)
|
if (entity is Item item && category.CanBeApplied(item, prefab) || entity is Structure && category.IsWallUpgrade)
|
||||||
{
|
{
|
||||||
@@ -856,16 +1176,14 @@ namespace Barotrauma
|
|||||||
if (GUIMessageBox.MessageBoxes[i] is GUIMessageBox msgBox && msgBox == currectConfirmation)
|
if (GUIMessageBox.MessageBoxes[i] is GUIMessageBox msgBox && msgBox == currectConfirmation)
|
||||||
{
|
{
|
||||||
// first button is the ok button
|
// first button is the ok button
|
||||||
GUIButton firstButton = msgBox.Buttons.FirstOrDefault();
|
GUIButton? firstButton = msgBox.Buttons.FirstOrDefault();
|
||||||
if (firstButton == null) { continue; }
|
if (firstButton is null) { continue; }
|
||||||
|
|
||||||
firstButton.OnClicked.Invoke(firstButton, firstButton.UserData);
|
firstButton.OnClicked.Invoke(firstButton, firstButton.UserData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemPreviews == null) { return; }
|
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
foreach (var (item, frame) in itemPreviews)
|
foreach (var (item, frame) in itemPreviews)
|
||||||
{
|
{
|
||||||
@@ -875,7 +1193,20 @@ namespace Barotrauma
|
|||||||
HoveredItem = item;
|
HoveredItem = item;
|
||||||
if (PlayerInput.PrimaryMouseButtonClicked() && selectedUpgradTab == UpgradeTab.Upgrade && currentStoreLayout != null)
|
if (PlayerInput.PrimaryMouseButtonClicked() && selectedUpgradTab == UpgradeTab.Upgrade && currentStoreLayout != null)
|
||||||
{
|
{
|
||||||
ScrollToCategory(data => data.Category.CanBeApplied(item, null));
|
if (customizeTabOpen)
|
||||||
|
{
|
||||||
|
if (selectedUpgradeCategoryLayout != null)
|
||||||
|
{
|
||||||
|
if (selectedUpgradeCategoryLayout.FindChild(c => c.UserData as Item == HoveredItem, recursive: true) is GUIButton itemElement && !itemElement.Selected)
|
||||||
|
{
|
||||||
|
itemElement.OnClicked(itemElement, itemElement.UserData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScrollToCategory(data => data.Category.CanBeApplied(item, null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
@@ -888,11 +1219,11 @@ namespace Barotrauma
|
|||||||
if (GUI.MouseOn == submarinePreviewComponent || GUI.MouseOn == subPreviewFrame)
|
if (GUI.MouseOn == submarinePreviewComponent || GUI.MouseOn == subPreviewFrame)
|
||||||
{
|
{
|
||||||
// Every wall should have the same upgrades so we can just display the first one in the tooltip
|
// Every wall should have the same upgrades so we can just display the first one in the tooltip
|
||||||
Structure firstStructure = submarineWalls.FirstOrDefault();
|
Structure? firstStructure = submarineWalls.FirstOrDefault();
|
||||||
// use pnpoly algorithm to detect if our mouse is within any of the hull polygons
|
// use pnpoly algorithm to detect if our mouse is within any of the hull polygons
|
||||||
if (subHullVerticies.Any(hullVertex => ToolBox.PointIntersectsWithPolygon(PlayerInput.MousePosition, hullVertex)))
|
if (subHullVerticies.Any(hullVertex => ToolBox.PointIntersectsWithPolygon(PlayerInput.MousePosition, hullVertex)))
|
||||||
{
|
{
|
||||||
if (HoveredItem != firstStructure) { CreateItemTooltip(firstStructure); }
|
if (HoveredItem != firstStructure && !(firstStructure is null)) { CreateItemTooltip(firstStructure); }
|
||||||
HoveredItem = firstStructure;
|
HoveredItem = firstStructure;
|
||||||
isMouseOnStructure = true;
|
isMouseOnStructure = true;
|
||||||
GUI.MouseCursor = CursorState.Hand;
|
GUI.MouseCursor = CursorState.Hand;
|
||||||
@@ -917,6 +1248,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CreateSubmarinePreview(Submarine submarine, GUIComponent parent)
|
private void CreateSubmarinePreview(Submarine submarine, GUIComponent parent)
|
||||||
{
|
{
|
||||||
|
if (mainStoreLayout == null) { return; }
|
||||||
|
|
||||||
if (submarineInfoFrame != null && mainStoreLayout == submarineInfoFrame.Parent)
|
if (submarineInfoFrame != null && mainStoreLayout == submarineInfoFrame.Parent)
|
||||||
{
|
{
|
||||||
mainStoreLayout.RemoveChild(submarineInfoFrame);
|
mainStoreLayout.RemoveChild(submarineInfoFrame);
|
||||||
@@ -961,15 +1294,32 @@ namespace Barotrauma
|
|||||||
GUIComponent component = parent.FindChild(entity, true);
|
GUIComponent component = parent.FindChild(entity, true);
|
||||||
if (component != null && entity is Item item)
|
if (component != null && entity is Item item)
|
||||||
{
|
{
|
||||||
Point size = new Point((int) (item.Rect.Width * item.Scale / dockedBorders.Width * hullContainer.Rect.Width), (int) (item.Rect.Height * item.Scale / dockedBorders.Height * hullContainer.Rect.Height));
|
GUIComponent itemFrame;
|
||||||
GUIFrame itemFrame = new GUIFrame(rectT(size, component, Anchor.Center), style: "ScanLines")
|
if (item.Prefab.UpgradePreviewSprite is { } icon)
|
||||||
{
|
{
|
||||||
SelectedColor = GUI.Style.Orange,
|
float spriteSize = 128f * item.Prefab.UpgradePreviewScale;
|
||||||
OutlineColor = previewWhite,
|
Point size = new Point((int) (spriteSize * item.Scale / dockedBorders.Width * hullContainer.Rect.Width));
|
||||||
Color = previewWhite,
|
itemFrame = new GUIImage(rectT(size, component, Anchor.Center), icon, scaleToFit: true)
|
||||||
OutlineThickness = 2,
|
{
|
||||||
HoverCursor = CursorState.Hand
|
SelectedColor = GUI.Style.Orange,
|
||||||
};
|
Color = previewWhite,
|
||||||
|
HoverCursor = CursorState.Hand,
|
||||||
|
SpriteEffects = item.Rotation > 90.0f && item.Rotation < 270.0f ? SpriteEffects.FlipVertically : SpriteEffects.None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Point size = new Point((int) (item.Rect.Width * item.Scale / dockedBorders.Width * hullContainer.Rect.Width), (int) (item.Rect.Height * item.Scale / dockedBorders.Height * hullContainer.Rect.Height));
|
||||||
|
itemFrame = new GUIFrame(rectT(size, component, Anchor.Center), style: "ScanLines")
|
||||||
|
{
|
||||||
|
SelectedColor = GUI.Style.Orange,
|
||||||
|
OutlineColor = previewWhite,
|
||||||
|
Color = previewWhite,
|
||||||
|
OutlineThickness = 2,
|
||||||
|
HoverCursor = CursorState.Hand
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (!itemPreviews.ContainsKey(item))
|
if (!itemPreviews.ContainsKey(item))
|
||||||
{
|
{
|
||||||
itemPreviews.Add(item, itemFrame);
|
itemPreviews.Add(item, itemFrame);
|
||||||
@@ -1093,7 +1443,7 @@ namespace Barotrauma
|
|||||||
List<UpgradePrefab> prefabs,
|
List<UpgradePrefab> prefabs,
|
||||||
UpgradeCategory category,
|
UpgradeCategory category,
|
||||||
CampaignMode campaign,
|
CampaignMode campaign,
|
||||||
Submarine drawnSubmarine,
|
Submarine? drawnSubmarine,
|
||||||
IEnumerable<UpgradeCategory> applicableCategories)
|
IEnumerable<UpgradeCategory> applicableCategories)
|
||||||
{
|
{
|
||||||
// Disables the parent and only re-enables if the submarine contains valid items
|
// Disables the parent and only re-enables if the submarine contains valid items
|
||||||
@@ -1148,6 +1498,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void ScrollToCategory(Predicate<CategoryData> predicate)
|
private void ScrollToCategory(Predicate<CategoryData> predicate)
|
||||||
{
|
{
|
||||||
|
if (currentStoreLayout == null) { return; }
|
||||||
|
|
||||||
foreach (GUIComponent child in currentStoreLayout.Content.Children)
|
foreach (GUIComponent child in currentStoreLayout.Content.Children)
|
||||||
{
|
{
|
||||||
if (child.UserData is CategoryData data && predicate(data))
|
if (child.UserData is CategoryData data && predicate(data))
|
||||||
@@ -1163,9 +1515,9 @@ namespace Barotrauma
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="category"></param>
|
/// <param name="category"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private GUIFrame[] GetFrames(UpgradeCategory category)
|
private GUIComponent[] GetFrames(UpgradeCategory category)
|
||||||
{
|
{
|
||||||
List<GUIFrame> frames = new List<GUIFrame>();
|
List<GUIComponent> frames = new List<GUIComponent>();
|
||||||
foreach (var (item, guiFrame) in itemPreviews)
|
foreach (var (item, guiFrame) in itemPreviews)
|
||||||
{
|
{
|
||||||
if (category.CanBeApplied(item, null))
|
if (category.CanBeApplied(item, null))
|
||||||
@@ -1185,9 +1537,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
// just a shortcut to create new RectTransforms since all the new RectTransform and new Vector2 confuses my IDE (and me)
|
// just a shortcut to create new RectTransforms since all the new RectTransform and new Vector2 confuses my IDE (and me)
|
||||||
private static RectTransform rectT(float x, float y, GUIComponent parentComponent, Anchor anchor = Anchor.TopLeft)
|
private static RectTransform rectT(float x, float y, GUIComponent parentComponent, Anchor anchor = Anchor.TopLeft, ScaleBasis scaleBasis = ScaleBasis.Normal)
|
||||||
{
|
{
|
||||||
return new RectTransform(new Vector2(x, y), parentComponent.RectTransform, anchor);
|
return new RectTransform(new Vector2(x, y), parentComponent.RectTransform, anchor, scaleBasis: scaleBasis);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RectTransform rectT(Point point, GUIComponent parentComponent, Anchor anchor = Anchor.TopLeft)
|
private static RectTransform rectT(Point point, GUIComponent parentComponent, Anchor anchor = Anchor.TopLeft)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ namespace Barotrauma
|
|||||||
public static bool ShowFPS = false;
|
public static bool ShowFPS = false;
|
||||||
public static bool ShowPerf = false;
|
public static bool ShowPerf = false;
|
||||||
public static bool DebugDraw;
|
public static bool DebugDraw;
|
||||||
|
public static bool IsSingleplayer => NetworkMember == null;
|
||||||
public static bool IsMultiplayer => NetworkMember != null;
|
public static bool IsMultiplayer => NetworkMember != null;
|
||||||
|
|
||||||
public static PerformanceCounter PerformanceCounter;
|
public static PerformanceCounter PerformanceCounter;
|
||||||
@@ -245,6 +246,23 @@ namespace Barotrauma
|
|||||||
FarseerPhysics.Settings.PositionIterations = 1;
|
FarseerPhysics.Settings.PositionIterations = 1;
|
||||||
|
|
||||||
MainThread = Thread.CurrentThread;
|
MainThread = Thread.CurrentThread;
|
||||||
|
|
||||||
|
Window.FileDropped += OnFileDropped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnFileDropped(object sender, FileDropEventArgs args)
|
||||||
|
{
|
||||||
|
if (!(Screen.Selected is { } screen)) { return; }
|
||||||
|
|
||||||
|
string filePath = args.FilePath;
|
||||||
|
if (string.IsNullOrWhiteSpace(filePath)) { return; }
|
||||||
|
|
||||||
|
string extension = Path.GetExtension(filePath).ToLower();
|
||||||
|
|
||||||
|
System.IO.FileInfo info = new System.IO.FileInfo(args.FilePath);
|
||||||
|
if (!info.Exists) { return; }
|
||||||
|
|
||||||
|
screen.OnFileDropped(filePath, extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyGraphicsSettings()
|
public void ApplyGraphicsSettings()
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ namespace Barotrauma
|
|||||||
: this(isSinglePlayer)
|
: this(isSinglePlayer)
|
||||||
{
|
{
|
||||||
AddCharacterElements(element);
|
AddCharacterElements(element);
|
||||||
|
ActiveOrdersElement = element.GetChildElement("activeorders");
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void InitProjectSpecific()
|
partial void InitProjectSpecific()
|
||||||
@@ -192,7 +193,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
AbsoluteSpacing = (int)(5 * GUI.Scale),
|
AbsoluteSpacing = (int)(5 * GUI.Scale),
|
||||||
UserData = "reportbuttons",
|
UserData = "reportbuttons",
|
||||||
CanBeFocused = false
|
CanBeFocused = false,
|
||||||
|
Visible = false
|
||||||
};
|
};
|
||||||
|
|
||||||
ReportButtonFrame.RectTransform.AbsoluteOffset = new Point(0, -chatBox.ToggleButton.Rect.Height);
|
ReportButtonFrame.RectTransform.AbsoluteOffset = new Point(0, -chatBox.ToggleButton.Rect.Height);
|
||||||
@@ -433,13 +435,20 @@ namespace Barotrauma
|
|||||||
Stretch = false
|
Stretch = false
|
||||||
};
|
};
|
||||||
|
|
||||||
var soundIcons = new GUIFrame(new RectTransform(new Vector2(0.8f * iconRelativeWidth, 0.8f), layoutGroup.RectTransform), style: null)
|
var extraIconFrame = new GUIFrame(new RectTransform(new Vector2(0.8f * iconRelativeWidth, 0.8f), layoutGroup.RectTransform), style: null)
|
||||||
{
|
{
|
||||||
CanBeFocused = false,
|
CanBeFocused = false,
|
||||||
UserData = "soundicons"
|
UserData = "extraicons"
|
||||||
|
};
|
||||||
|
|
||||||
|
var soundIconParent = new GUIFrame(new RectTransform(Vector2.One, extraIconFrame.RectTransform), style: null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false,
|
||||||
|
UserData = "soundicons",
|
||||||
|
Visible = character.IsPlayer
|
||||||
};
|
};
|
||||||
new GUIImage(
|
new GUIImage(
|
||||||
new RectTransform(Vector2.One, soundIcons.RectTransform),
|
new RectTransform(Vector2.One, soundIconParent.RectTransform),
|
||||||
GUI.Style.GetComponentStyle("GUISoundIcon").GetDefaultSprite(),
|
GUI.Style.GetComponentStyle("GUISoundIcon").GetDefaultSprite(),
|
||||||
scaleToFit: true)
|
scaleToFit: true)
|
||||||
{
|
{
|
||||||
@@ -448,7 +457,7 @@ namespace Barotrauma
|
|||||||
Visible = true
|
Visible = true
|
||||||
};
|
};
|
||||||
new GUIImage(
|
new GUIImage(
|
||||||
new RectTransform(Vector2.One, soundIcons.RectTransform),
|
new RectTransform(Vector2.One, soundIconParent.RectTransform),
|
||||||
"GUISoundIconDisabled",
|
"GUISoundIconDisabled",
|
||||||
scaleToFit: true)
|
scaleToFit: true)
|
||||||
{
|
{
|
||||||
@@ -457,6 +466,16 @@ namespace Barotrauma
|
|||||||
Visible = false
|
Visible = false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (character.IsBot)
|
||||||
|
{
|
||||||
|
new GUIFrame(new RectTransform(Vector2.One, extraIconFrame.RectTransform), style: null)
|
||||||
|
{
|
||||||
|
CanBeFocused = false,
|
||||||
|
UserData = "objectiveicon",
|
||||||
|
Visible = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
new GUIButton(new RectTransform(new Point((int)commandButtonAbsoluteHeight), background.RectTransform), style: "CrewListCommandButton")
|
new GUIButton(new RectTransform(new Point((int)commandButtonAbsoluteHeight), background.RectTransform), style: "CrewListCommandButton")
|
||||||
{
|
{
|
||||||
ToolTip = TextManager.Get("inputtype.command"),
|
ToolTip = TextManager.Get("inputtype.command"),
|
||||||
@@ -624,9 +643,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (client?.Character == null) { return; }
|
if (client?.Character == null) { return; }
|
||||||
|
|
||||||
if (crewList.Content.GetChildByUserData(client.Character)?
|
if (GetSoundIconParent(client.Character) is GUIComponent soundIcons)
|
||||||
.FindChild(c => c is GUILayoutGroup)?
|
|
||||||
.GetChildByUserData("soundicons") is GUIComponent soundIcons)
|
|
||||||
{
|
{
|
||||||
var soundIcon = soundIcons.FindChild(c => c.UserData is Pair<string, float> pair && pair.First == "soundicon");
|
var soundIcon = soundIcons.FindChild(c => c.UserData is Pair<string, float> pair && pair.First == "soundicon");
|
||||||
var soundIconDisabled = soundIcons.FindChild("soundicondisabled");
|
var soundIconDisabled = soundIcons.FindChild("soundicondisabled");
|
||||||
@@ -638,15 +655,17 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void SetClientSpeaking(Client client)
|
public void SetClientSpeaking(Client client)
|
||||||
{
|
{
|
||||||
if (client?.Character != null) { SetCharacterSpeaking(client.Character); }
|
if (client?.Character != null)
|
||||||
|
{
|
||||||
|
SetCharacterSpeaking(client.Character);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCharacterSpeaking(Character character)
|
public void SetCharacterSpeaking(Character character)
|
||||||
{
|
{
|
||||||
if (crewList.Content.GetChildByUserData(character)?
|
if (character == null || character.IsBot) { return; }
|
||||||
.FindChild(c => c is GUILayoutGroup)?
|
|
||||||
.GetChildByUserData("soundicons")?
|
if (GetSoundIconParent(character)?.FindChild(c => c.UserData is Pair<string, float> pair && pair.First == "soundicon") is GUIComponent soundIcon)
|
||||||
.FindChild(c => c.UserData is Pair<string, float> pair && pair.First == "soundicon") is GUIComponent soundIcon)
|
|
||||||
{
|
{
|
||||||
soundIcon.Color = Color.White;
|
soundIcon.Color = Color.White;
|
||||||
Pair<string, float> userdata = soundIcon.UserData as Pair<string, float>;
|
Pair<string, float> userdata = soundIcon.UserData as Pair<string, float>;
|
||||||
@@ -654,6 +673,19 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GUIComponent GetSoundIconParent(GUIComponent characterComponent)
|
||||||
|
{
|
||||||
|
return characterComponent?
|
||||||
|
.FindChild(c => c is GUILayoutGroup)?
|
||||||
|
.GetChildByUserData("extraicons")?
|
||||||
|
.GetChildByUserData("soundicons");
|
||||||
|
}
|
||||||
|
|
||||||
|
private GUIComponent GetSoundIconParent(Character character)
|
||||||
|
{
|
||||||
|
return GetSoundIconParent(crewList?.Content.GetChildByUserData(character));
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Crew List Order Displayment
|
#region Crew List Order Displayment
|
||||||
@@ -770,6 +802,7 @@ namespace Barotrauma
|
|||||||
if (icon is GUIImage image)
|
if (icon is GUIImage image)
|
||||||
{
|
{
|
||||||
image.Sprite = GetOrderIconSprite(order, option);
|
image.Sprite = GetOrderIconSprite(order, option);
|
||||||
|
image.ToolTip = CreateOrderTooltip(order, option);
|
||||||
}
|
}
|
||||||
updatedExistingIcon = true;
|
updatedExistingIcon = true;
|
||||||
}
|
}
|
||||||
@@ -835,7 +868,7 @@ namespace Barotrauma
|
|||||||
Visible = false
|
Visible = false
|
||||||
};
|
};
|
||||||
|
|
||||||
int hierarchyIndex = GetOrderIconHierarchyIndex(priority);
|
int hierarchyIndex = Math.Clamp(CharacterInfo.HighestManualOrderPriority - priority, 0, Math.Max(currentOrderIconList.Content.CountChildren - 1, 0));
|
||||||
if (hierarchyIndex != currentOrderIconList.Content.GetChildIndex(nodeIcon))
|
if (hierarchyIndex != currentOrderIconList.Content.GetChildIndex(nodeIcon))
|
||||||
{
|
{
|
||||||
nodeIcon.RectTransform.RepositionChildInHierarchy(hierarchyIndex);
|
nodeIcon.RectTransform.RepositionChildInHierarchy(hierarchyIndex);
|
||||||
@@ -878,11 +911,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GetOrderIconHierarchyIndex(int priority)
|
|
||||||
{
|
|
||||||
return CharacterInfo.HighestManualOrderPriority - priority;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCurrentOrderIcon(Character character, OrderInfo? orderInfo)
|
public void AddCurrentOrderIcon(Character character, OrderInfo? orderInfo)
|
||||||
@@ -1020,29 +1048,36 @@ namespace Barotrauma
|
|||||||
SetCharacterOrder(character, orderInfo.Order, orderInfo.OrderOption, priority, Character.Controlled);
|
SetCharacterOrder(character, orderInfo.Order, orderInfo.OrderOption, priority, Character.Controlled);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CreateOrderTooltip(Order order, string option)
|
private string CreateOrderTooltip(Order orderPrefab, string option, Entity targetEntity)
|
||||||
{
|
{
|
||||||
if (order == null) { return ""; }
|
if (orderPrefab == null) { return ""; }
|
||||||
if (!string.IsNullOrEmpty(option))
|
if (!string.IsNullOrEmpty(option))
|
||||||
{
|
{
|
||||||
return TextManager.GetWithVariables("crewlistordericontooltip",
|
return TextManager.GetWithVariables("crewlistordericontooltip",
|
||||||
new string[2] { "[ordername]", "[orderoption]" },
|
new string[2] { "[ordername]", "[orderoption]" },
|
||||||
new string[2] { order.Name, order.GetOptionName(option) });
|
new string[2] { orderPrefab.Name, orderPrefab.GetOptionName(option) });
|
||||||
}
|
}
|
||||||
else if (order.TargetEntity is Item targetItem && order.MinimapIcons.ContainsKey(targetItem.Prefab.Identifier))
|
else if (targetEntity is Item targetItem && targetItem.Prefab.MinimapIcon != null)
|
||||||
{
|
{
|
||||||
return TextManager.GetWithVariables("crewlistordericontooltip",
|
return TextManager.GetWithVariables("crewlistordericontooltip",
|
||||||
new string[2] { "[ordername]", "[orderoption]" },
|
new string[2] { "[ordername]", "[orderoption]" },
|
||||||
new string[2] { order.Name, targetItem.Name });
|
new string[2] { orderPrefab.Name, targetItem.Name });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return order.Name;
|
return orderPrefab.Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CreateOrderTooltip(OrderInfo orderInfo) =>
|
private string CreateOrderTooltip(Order order, string option)
|
||||||
CreateOrderTooltip(orderInfo.Order, orderInfo.OrderOption);
|
{
|
||||||
|
return CreateOrderTooltip(order?.Prefab ?? order, option, order?.TargetEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CreateOrderTooltip(OrderInfo orderInfo)
|
||||||
|
{
|
||||||
|
return CreateOrderTooltip(orderInfo.Order?.Prefab ?? orderInfo.Order, orderInfo.OrderOption, orderInfo.Order?.TargetEntity);
|
||||||
|
}
|
||||||
|
|
||||||
private Sprite GetOrderIconSprite(Order order, string option)
|
private Sprite GetOrderIconSprite(Order order, string option)
|
||||||
{
|
{
|
||||||
@@ -1052,9 +1087,9 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
order.Prefab.OptionSprites.TryGetValue(option, out sprite);
|
order.Prefab.OptionSprites.TryGetValue(option, out sprite);
|
||||||
}
|
}
|
||||||
if (sprite == null && order.TargetEntity is Item targetItem && order.MinimapIcons.Any())
|
if (sprite == null && order.TargetEntity is Item targetItem && targetItem.Prefab.MinimapIcon != null)
|
||||||
{
|
{
|
||||||
order.MinimapIcons.TryGetValue(targetItem.Prefab.Identifier, out sprite);
|
sprite = targetItem.Prefab.MinimapIcon;
|
||||||
}
|
}
|
||||||
return sprite ?? order.SymbolSprite;
|
return sprite ?? order.SymbolSprite;
|
||||||
}
|
}
|
||||||
@@ -1272,7 +1307,7 @@ namespace Barotrauma
|
|||||||
partial void UpdateProjectSpecific(float deltaTime)
|
partial void UpdateProjectSpecific(float deltaTime)
|
||||||
{
|
{
|
||||||
// Quick selection
|
// Quick selection
|
||||||
if (!GameMain.IsMultiplayer && GUI.KeyboardDispatcher.Subscriber == null)
|
if (GameMain.IsSingleplayer && GUI.KeyboardDispatcher.Subscriber == null)
|
||||||
{
|
{
|
||||||
if (PlayerInput.KeyHit(InputType.SelectNextCharacter))
|
if (PlayerInput.KeyHit(InputType.SelectNextCharacter))
|
||||||
{
|
{
|
||||||
@@ -1294,7 +1329,7 @@ namespace Barotrauma
|
|||||||
(GUI.KeyboardDispatcher.Subscriber == null || (GUI.KeyboardDispatcher.Subscriber is GUIComponent component && (component == crewList || component.IsChildOf(crewList)))) &&
|
(GUI.KeyboardDispatcher.Subscriber == null || (GUI.KeyboardDispatcher.Subscriber is GUIComponent component && (component == crewList || component.IsChildOf(crewList)))) &&
|
||||||
commandFrame == null && !clicklessSelectionActive && CanIssueOrders && !(GameMain.GameSession?.Campaign?.ShowCampaignUI ?? false))
|
commandFrame == null && !clicklessSelectionActive && CanIssueOrders && !(GameMain.GameSession?.Campaign?.ShowCampaignUI ?? false))
|
||||||
{
|
{
|
||||||
if (PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift))
|
if (PlayerInput.IsShiftDown())
|
||||||
{
|
{
|
||||||
CreateCommandUI(FindEntityContext(), true);
|
CreateCommandUI(FindEntityContext(), true);
|
||||||
}
|
}
|
||||||
@@ -1521,19 +1556,44 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
crewList.Select(character, force: true);
|
crewList.Select(character, force: true);
|
||||||
}
|
}
|
||||||
if (character.AIController is HumanAIController controller)
|
if (GameMain.IsSingleplayer && character.IsBot && character.AIController is HumanAIController controller &&
|
||||||
|
controller.ObjectiveManager is AIObjectiveManager objectiveManager)
|
||||||
{
|
{
|
||||||
OrderInfo? currentOrderInfo = controller.ObjectiveManager?.GetCurrentOrderInfo();
|
// In multiplayer, these are set through character networking (the server lets the clients now when these are updated)
|
||||||
if (currentOrderInfo.HasValue)
|
if (objectiveManager.CurrentObjective is AIObjective currentObjective)
|
||||||
{
|
{
|
||||||
SetHighlightedOrderIcon(characterComponent, currentOrderInfo.Value.Order?.Identifier, currentOrderInfo.Value.OrderOption);
|
if (objectiveManager.IsOrder(currentObjective))
|
||||||
|
{
|
||||||
|
var orderInfo = objectiveManager.CurrentOrders.FirstOrDefault(o => o.Objective == currentObjective);
|
||||||
|
SetOrderHighlight(characterComponent, orderInfo.Order?.Identifier, orderInfo.OrderOption);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CreateObjectiveIcon(characterComponent, currentObjective);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (characterComponent.GetChild<GUILayoutGroup>().GetChildByUserData("soundicons") is GUIComponent soundIconParent)
|
// Order highlighting and objective icons are intended to communicate bot behavior so they should be disabled for player characters
|
||||||
|
if (character.IsPlayer)
|
||||||
|
{
|
||||||
|
DisableOrderHighlight(characterComponent);
|
||||||
|
RemoveObjectiveIcon(characterComponent);
|
||||||
|
}
|
||||||
|
if (GetSoundIconParent(characterComponent) is GUIComponent soundIconParent)
|
||||||
{
|
{
|
||||||
if (soundIconParent.FindChild(c => c.UserData is Pair<string, float> pair && pair.First == "soundicon") is GUIImage soundIcon)
|
if (soundIconParent.FindChild(c => c.UserData is Pair<string, float> pair && pair.First == "soundicon") is GUIImage soundIcon)
|
||||||
{
|
{
|
||||||
VoipClient.UpdateVoiceIndicator(soundIcon, 0.0f, deltaTime);
|
if (character.IsPlayer)
|
||||||
|
{
|
||||||
|
soundIconParent.Visible = true;
|
||||||
|
VoipClient.UpdateVoiceIndicator(soundIcon, 0.0f, deltaTime);
|
||||||
|
}
|
||||||
|
else if(soundIcon.Visible)
|
||||||
|
{
|
||||||
|
var userdata = soundIcon.UserData as Pair<string, float>;
|
||||||
|
userdata.Second = 0.0f;
|
||||||
|
soundIconParent.Visible = soundIcon.Visible = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1559,31 +1619,127 @@ namespace Barotrauma
|
|||||||
UpdateReports();
|
UpdateReports();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetHighlightedOrderIcon(GUIComponent characterComponent, string orderIdentifier, string orderOption)
|
private void SetOrderHighlight(GUIComponent characterComponent, string orderIdentifier, string orderOption)
|
||||||
{
|
{
|
||||||
var currentOrderIconList = GetCurrentOrderIconList(characterComponent);
|
if (characterComponent == null) { return; }
|
||||||
if (currentOrderIconList == null) { return; }
|
RemoveObjectiveIcon(characterComponent);
|
||||||
bool foundMatch = false;
|
if (GetCurrentOrderIconList(characterComponent) is GUIListBox currentOrderIconList)
|
||||||
foreach (var orderIcon in currentOrderIconList.Content.Children)
|
|
||||||
{
|
{
|
||||||
var glowComponent = orderIcon.GetChildByUserData("glow");
|
bool foundMatch = false;
|
||||||
if (glowComponent == null) { continue; }
|
foreach (var orderIcon in currentOrderIconList.Content.Children)
|
||||||
if (foundMatch)
|
|
||||||
{
|
{
|
||||||
glowComponent.Visible = false;
|
var glowComponent = orderIcon.GetChildByUserData("glow");
|
||||||
continue;
|
if (glowComponent == null) { continue; }
|
||||||
|
if (foundMatch)
|
||||||
|
{
|
||||||
|
glowComponent.Visible = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var orderInfo = (OrderInfo)orderIcon.UserData;
|
||||||
|
foundMatch = orderInfo.MatchesOrder(orderIdentifier, orderOption);
|
||||||
|
glowComponent.Visible = foundMatch;
|
||||||
}
|
}
|
||||||
var orderInfo = (OrderInfo)orderIcon.UserData;
|
|
||||||
foundMatch = orderInfo.MatchesOrder(orderIdentifier, orderOption);
|
|
||||||
glowComponent.Visible = foundMatch;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetHighlightedOrderIcon(Character character, string orderIdentifier, string orderOption)
|
public void SetOrderHighlight(Character character, string orderIdentifier, string orderOption)
|
||||||
{
|
{
|
||||||
if (crewList == null) { return; }
|
if (crewList == null) { return; }
|
||||||
var characterComponent = crewList.Content.GetChildByUserData(character);
|
var characterComponent = crewList.Content.GetChildByUserData(character);
|
||||||
SetHighlightedOrderIcon(characterComponent, orderIdentifier, orderOption);
|
SetOrderHighlight(characterComponent, orderIdentifier, orderOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisableOrderHighlight(GUIComponent characterComponent)
|
||||||
|
{
|
||||||
|
if (GetCurrentOrderIconList(characterComponent) is GUIListBox currentOrderIconList)
|
||||||
|
{
|
||||||
|
foreach (var orderIcon in currentOrderIconList.Content.Children)
|
||||||
|
{
|
||||||
|
var glowComponent = orderIcon.GetChildByUserData("glow");
|
||||||
|
if (glowComponent == null) { continue; }
|
||||||
|
glowComponent.Visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateObjectiveIcon(GUIComponent characterComponent, Sprite sprite, string tooltip)
|
||||||
|
{
|
||||||
|
if (characterComponent == null || !(characterComponent.UserData is Character character) || character.IsPlayer) { return; }
|
||||||
|
DisableOrderHighlight(characterComponent);
|
||||||
|
if (GetObjectiveIconParent(characterComponent) is GUIFrame objectiveIconFrame)
|
||||||
|
{
|
||||||
|
var existingObjectiveIcon = objectiveIconFrame.GetChild<GUIImage>();
|
||||||
|
if (existingObjectiveIcon == null || existingObjectiveIcon.Sprite != sprite || existingObjectiveIcon.ToolTip != tooltip)
|
||||||
|
{
|
||||||
|
objectiveIconFrame.ClearChildren();
|
||||||
|
if (sprite != null)
|
||||||
|
{
|
||||||
|
var objectiveIcon = CreateNodeIcon(Vector2.One, objectiveIconFrame.RectTransform, sprite, Color.LightGray, tooltip: tooltip);
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.5f), objectiveIcon.RectTransform, anchor: Anchor.Center), style: "OuterGlowCircular")
|
||||||
|
{
|
||||||
|
CanBeFocused = false,
|
||||||
|
Color = Color.LightGray
|
||||||
|
};
|
||||||
|
objectiveIconFrame.Visible = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
objectiveIconFrame.Visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateObjectiveIcon(Character character, string identifier, string option, Entity targetEntity)
|
||||||
|
{
|
||||||
|
CreateObjectiveIcon(crewList?.Content.GetChildByUserData(character),
|
||||||
|
AIObjective.GetSprite(identifier, option, targetEntity),
|
||||||
|
GetObjectiveIconTooltip(identifier, option, targetEntity));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateObjectiveIcon(GUIComponent characterComponent, AIObjective objective)
|
||||||
|
{
|
||||||
|
CreateObjectiveIcon(characterComponent,
|
||||||
|
objective?.GetSprite(),
|
||||||
|
GetObjectiveIconTooltip(objective));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetObjectiveIconTooltip(string identifier, string option, Entity targetEntity)
|
||||||
|
{
|
||||||
|
string variableValue;
|
||||||
|
identifier = identifier.RemoveWhitespace();
|
||||||
|
if (Order.Prefabs.TryGetValue(identifier, out Order orderPrefab))
|
||||||
|
{
|
||||||
|
variableValue = CreateOrderTooltip(orderPrefab, option, targetEntity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
variableValue = TextManager.Get($"objective.{identifier}", returnNull: true) ?? "";
|
||||||
|
}
|
||||||
|
return string.IsNullOrEmpty(variableValue) ? variableValue : TextManager.GetWithVariable("crewlistobjectivetooltip", "[objective]", variableValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetObjectiveIconTooltip(AIObjective objective)
|
||||||
|
{
|
||||||
|
return objective == null ? "" :
|
||||||
|
GetObjectiveIconTooltip(objective.Identifier, objective.Option, (objective as AIObjectiveOperateItem)?.OperateTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GUIComponent GetObjectiveIconParent(GUIComponent characterComponent)
|
||||||
|
{
|
||||||
|
return characterComponent?
|
||||||
|
.GetChild<GUILayoutGroup>()?
|
||||||
|
.GetChildByUserData("extraicons")?
|
||||||
|
.GetChildByUserData("objectiveicon");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveObjectiveIcon(GUIComponent characterComponent)
|
||||||
|
{
|
||||||
|
if (GetObjectiveIconParent(characterComponent) is GUIFrame objectiveIconFrame)
|
||||||
|
{
|
||||||
|
objectiveIconFrame.ClearChildren();
|
||||||
|
objectiveIconFrame.Visible = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -2126,6 +2282,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CreateShortcutNodes()
|
private void CreateShortcutNodes()
|
||||||
{
|
{
|
||||||
|
bool HasAppropriateJob(Character c, string jobId) => c.Info?.Job != null && c.Info.Job.Prefab.AppropriateOrders.Contains(jobId);
|
||||||
|
|
||||||
Submarine sub = GetTargetSubmarine();
|
Submarine sub = GetTargetSubmarine();
|
||||||
|
|
||||||
if (sub == null) { return; }
|
if (sub == null) { return; }
|
||||||
@@ -2138,7 +2296,7 @@ namespace Barotrauma
|
|||||||
var reactorOutput = -reactor.CurrPowerConsumption;
|
var reactorOutput = -reactor.CurrPowerConsumption;
|
||||||
// If player is not an engineer AND the reactor is not powered up AND nobody is using the reactor
|
// If player is not an engineer AND the reactor is not powered up AND nobody is using the reactor
|
||||||
// ---> Create shortcut node for "Operate Reactor" order's "Power Up" option
|
// ---> Create shortcut node for "Operate Reactor" order's "Power Up" option
|
||||||
if ((Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("engineer")) &&
|
if ((Character.Controlled == null || !HasAppropriateJob(Character.Controlled, "operatereactor")) &&
|
||||||
reactorOutput < float.Epsilon && characters.None(c => c.SelectedConstruction == reactor.Item))
|
reactorOutput < float.Epsilon && characters.None(c => c.SelectedConstruction == reactor.Item))
|
||||||
{
|
{
|
||||||
var order = new Order(Order.GetPrefab("operatereactor"), reactor.Item, reactor, Character.Controlled);
|
var order = new Order(Order.GetPrefab("operatereactor"), reactor.Item, reactor, Character.Controlled);
|
||||||
@@ -2151,7 +2309,7 @@ namespace Barotrauma
|
|||||||
// TODO: Reconsider the conditions as bot captain can have the nav term selected without operating it
|
// TODO: Reconsider the conditions as bot captain can have the nav term selected without operating it
|
||||||
// If player is not a captain AND nobody is using the nav terminal AND the nav terminal is powered up
|
// If player is not a captain AND nobody is using the nav terminal AND the nav terminal is powered up
|
||||||
// --> Create shortcut node for Steer order
|
// --> Create shortcut node for Steer order
|
||||||
if (shortcutNodes.Count < maxShortCutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("captain")) &&
|
if (shortcutNodes.Count < maxShortCutNodeCount && (Character.Controlled == null || !HasAppropriateJob(Character.Controlled, "steer")) &&
|
||||||
sub.GetItems(false).Find(i => i.HasTag("navterminal") && i.IsPlayerTeamInteractable) is Item nav && characters.None(c => c.SelectedConstruction == nav) &&
|
sub.GetItems(false).Find(i => i.HasTag("navterminal") && i.IsPlayerTeamInteractable) is Item nav && characters.None(c => c.SelectedConstruction == nav) &&
|
||||||
nav.GetComponent<Steering>() is Steering steering && steering.Voltage > steering.MinVoltage)
|
nav.GetComponent<Steering>() is Steering steering && steering.Voltage > steering.MinVoltage)
|
||||||
{
|
{
|
||||||
@@ -2161,8 +2319,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
// If player is not a security officer AND invaders are reported
|
// If player is not a security officer AND invaders are reported
|
||||||
// --> Create shorcut node for Fight Intruders order
|
// --> Create shorcut node for Fight Intruders order
|
||||||
if (shortcutNodes.Count < maxShortCutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("securityofficer")) &&
|
if (shortcutNodes.Count < maxShortCutNodeCount && (Character.Controlled == null || !HasAppropriateJob(Character.Controlled, "fightintruders")) &&
|
||||||
(Order.GetPrefab("reportintruders") is Order reportIntruders && ActiveOrders.Any(o => o.First.Prefab == reportIntruders)))
|
Order.GetPrefab("reportintruders") is Order reportIntruders && ActiveOrders.Any(o => o.First.Prefab == reportIntruders))
|
||||||
{
|
{
|
||||||
shortcutNodes.Add(
|
shortcutNodes.Add(
|
||||||
CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab("fightintruders"), -1));
|
CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab("fightintruders"), -1));
|
||||||
@@ -2170,25 +2328,43 @@ namespace Barotrauma
|
|||||||
|
|
||||||
// If player is not a mechanic AND a breach has been reported
|
// If player is not a mechanic AND a breach has been reported
|
||||||
// --> Create shorcut node for Fix Leaks order
|
// --> Create shorcut node for Fix Leaks order
|
||||||
if (shortcutNodes.Count < maxShortCutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("mechanic")) &&
|
if (shortcutNodes.Count < maxShortCutNodeCount && (Character.Controlled == null || !HasAppropriateJob(Character.Controlled, "fixleaks")) &&
|
||||||
(Order.GetPrefab("reportbreach") is Order reportBreach && ActiveOrders.Any(o => o.First.Prefab == reportBreach)))
|
Order.GetPrefab("reportbreach") is Order reportBreach && ActiveOrders.Any(o => o.First.Prefab == reportBreach))
|
||||||
{
|
{
|
||||||
shortcutNodes.Add(
|
shortcutNodes.Add(
|
||||||
CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab("fixleaks"), -1));
|
CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab("fixleaks"), -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If player is not an engineer AND broken devices have been reported
|
// --> Create shortcut nodes for the Repair orders
|
||||||
// --> Create shortcut node for Repair Damaged Systems order
|
if (shortcutNodes.Count < maxShortCutNodeCount && Order.GetPrefab("reportbrokendevices") is Order reportBrokenDevices && ActiveOrders.Any(o => o.First.Prefab == reportBrokenDevices))
|
||||||
if (shortcutNodes.Count < maxShortCutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("engineer")) &&
|
|
||||||
(Order.GetPrefab("reportbrokendevices") is Order reportBrokenDevices && ActiveOrders.Any(o => o.First.Prefab == reportBrokenDevices)))
|
|
||||||
{
|
{
|
||||||
shortcutNodes.Add(
|
// TODO: Doesn't work for player issued reports, because they don't have a target.
|
||||||
CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab("repairsystems"), -1));
|
int repairNodes = 0;
|
||||||
|
string tag = "repairelectrical";
|
||||||
|
if (shortcutNodes.Count < maxShortCutNodeCount && (Character.Controlled == null || !HasAppropriateJob(Character.Controlled, tag)) && ActiveOrders.Any(o => o.First.Prefab == reportBrokenDevices && o.First.TargetItemComponent is Repairable r && r.requiredSkills.Any(s => s.Identifier == "electrical")))
|
||||||
|
{
|
||||||
|
shortcutNodes.Add(CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab(tag), -1));
|
||||||
|
repairNodes++;
|
||||||
|
}
|
||||||
|
tag = "repairmechanical";
|
||||||
|
if (shortcutNodes.Count < maxShortCutNodeCount && (Character.Controlled == null || !HasAppropriateJob(Character.Controlled, tag)) && ActiveOrders.Any(o => o.First.Prefab == reportBrokenDevices && o.First.TargetItemComponent is Repairable r && r.requiredSkills.Any(s => s.Identifier == "mechanical")))
|
||||||
|
{
|
||||||
|
shortcutNodes.Add(CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab(tag), -1));
|
||||||
|
repairNodes++;
|
||||||
|
}
|
||||||
|
if (repairNodes == 0 && shortcutNodes.Count < maxShortCutNodeCount)
|
||||||
|
{
|
||||||
|
tag = "repairsystems";
|
||||||
|
if (Character.Controlled == null || !HasAppropriateJob(Character.Controlled, tag))
|
||||||
|
{
|
||||||
|
shortcutNodes.Add(CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab(tag), -1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If fire is reported
|
// If fire is reported
|
||||||
// --> Create shortcut node for Extinguish Fires order
|
// --> Create shortcut node for Extinguish Fires order
|
||||||
if (shortcutNodes.Count < maxShortCutNodeCount && ActiveOrders.Any(o=> o.First.Prefab == Order.GetPrefab("reportfire")))
|
if (shortcutNodes.Count < maxShortCutNodeCount && ActiveOrders.Any(o => o.First.Prefab == Order.GetPrefab("reportfire")))
|
||||||
{
|
{
|
||||||
shortcutNodes.Add(
|
shortcutNodes.Add(
|
||||||
CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab("extinguishfires"), -1));
|
CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab("extinguishfires"), -1));
|
||||||
@@ -2645,16 +2821,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
optionElement.OnSecondaryClicked = (button, _) => CreateAssignmentNodes(button);
|
optionElement.OnSecondaryClicked = (button, _) => CreateAssignmentNodes(button);
|
||||||
}
|
}
|
||||||
Sprite icon = null;
|
|
||||||
order.MinimapIcons?.TryGetValue(item.Prefab.Identifier, out icon);
|
|
||||||
if (item.Prefab.MinimapIcon != null)
|
|
||||||
{
|
|
||||||
icon = item.Prefab.MinimapIcon;
|
|
||||||
}
|
|
||||||
var colorMultiplier = characters.Any(c => c.CurrentOrders.Any(o => o.Order != null &&
|
var colorMultiplier = characters.Any(c => c.CurrentOrders.Any(o => o.Order != null &&
|
||||||
o.Order.Identifier == userData.Item1.Identifier &&
|
o.Order.Identifier == userData.Item1.Identifier &&
|
||||||
o.Order.TargetEntity == userData.Item1.TargetEntity)) ? 0.5f : 1f;
|
o.Order.TargetEntity == userData.Item1.TargetEntity)) ? 0.5f : 1f;
|
||||||
CreateNodeIcon(Vector2.One, optionElement.RectTransform, icon ?? order.SymbolSprite, order.Color * colorMultiplier);
|
CreateNodeIcon(Vector2.One, optionElement.RectTransform, item.Prefab.MinimapIcon ?? order.SymbolSprite, order.Color * colorMultiplier);
|
||||||
optionNodes.Add(new Tuple<GUIComponent, Keys>(optionElement, Keys.None));
|
optionNodes.Add(new Tuple<GUIComponent, Keys>(optionElement, Keys.None));
|
||||||
}
|
}
|
||||||
optionElements.Add(optionElement);
|
optionElements.Add(optionElement);
|
||||||
@@ -3182,16 +3352,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private Character GetCharacterForQuickAssignment(Order order)
|
private Character GetCharacterForQuickAssignment(Order order)
|
||||||
{
|
{
|
||||||
var controllingCharacter = Character.Controlled != null;
|
return GetCharacterForQuickAssignment(order, Character.Controlled, characters);
|
||||||
#if !DEBUG
|
|
||||||
if (!controllingCharacter) { return null; }
|
|
||||||
#endif
|
|
||||||
if (order.Category == OrderCategory.Operate && HumanAIController.IsItemOperatedByAnother(null, order.TargetItemComponent, out Character operatingCharacter) &&
|
|
||||||
(!controllingCharacter || operatingCharacter.CanHearCharacter(Character.Controlled)))
|
|
||||||
{
|
|
||||||
return operatingCharacter;
|
|
||||||
}
|
|
||||||
return GetCharactersSortedForOrder(order, false).FirstOrDefault(c => !controllingCharacter || c.CanHearCharacter(Character.Controlled)) ?? Character.Controlled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Character> GetCharactersForManualAssignment(Order order)
|
private List<Character> GetCharactersForManualAssignment(Order order)
|
||||||
@@ -3203,34 +3364,15 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
return characters.Union(GetOrderableFriendlyNPCs()).Where(c => !c.IsDismissed).OrderBy(c => c.Info.DisplayName).ToList();
|
return characters.Union(GetOrderableFriendlyNPCs()).Where(c => !c.IsDismissed).OrderBy(c => c.Info.DisplayName).ToList();
|
||||||
}
|
}
|
||||||
return GetCharactersSortedForOrder(order, order.Identifier != "follow").ToList();
|
return GetCharactersSortedForOrder(order, characters, Character.Controlled, order.Identifier != "follow", extraCharacters: GetOrderableFriendlyNPCs()).ToList();
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<Character> GetCharactersSortedForOrder(Order order, bool includeSelf)
|
|
||||||
{
|
|
||||||
return characters.Where(c => Character.Controlled == null || ((includeSelf || c != Character.Controlled) && c.TeamID == Character.Controlled.TeamID)).Union(GetOrderableFriendlyNPCs())
|
|
||||||
// 1. Prioritize those who are on the same submarine than the controlled character
|
|
||||||
.OrderByDescending(c => Character.Controlled == null || c.Submarine == Character.Controlled.Submarine)
|
|
||||||
// 2. Prioritize those who have been given the same maintenance or operate order as now issued
|
|
||||||
.ThenByDescending(c => c.CurrentOrders.Any(o =>
|
|
||||||
o.Order != null && o.Order.Identifier == order.Identifier &&
|
|
||||||
(order.Category == OrderCategory.Maintenance || order.Category == OrderCategory.Operate)))
|
|
||||||
// 3. Prioritize those with the appropriate job for the order
|
|
||||||
.ThenByDescending(c => order.HasAppropriateJob(c))
|
|
||||||
// 4. Prioritize bots over player controlled characters
|
|
||||||
.ThenByDescending(c => c.IsBot)
|
|
||||||
// 5. Use the priority value of the current objective
|
|
||||||
.ThenBy(c => c.AIController is HumanAIController humanAI ? humanAI.ObjectiveManager.CurrentObjective?.Priority : 0)
|
|
||||||
// 6. Prioritize those with the best skill for the order
|
|
||||||
.ThenByDescending(c => c.GetSkillLevel(order.AppropriateSkill));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<Character> GetOrderableFriendlyNPCs()
|
private IEnumerable<Character> GetOrderableFriendlyNPCs()
|
||||||
{
|
{
|
||||||
|
// TODO: change this so that we can get the data without having to rely on ui elements.
|
||||||
return crewList.Content.Children.Where(c => c.UserData is Character character && character.TeamID == CharacterTeamType.FriendlyNPC).Select(c => (Character)c.UserData);
|
return crewList.Content.Children.Where(c => c.UserData is Character character && character.TeamID == CharacterTeamType.FriendlyNPC).Select(c => (Character)c.UserData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -3325,15 +3467,76 @@ namespace Barotrauma
|
|||||||
public void Save(XElement parentElement)
|
public void Save(XElement parentElement)
|
||||||
{
|
{
|
||||||
XElement element = new XElement("crew");
|
XElement element = new XElement("crew");
|
||||||
|
|
||||||
foreach (CharacterInfo ci in characterInfos)
|
foreach (CharacterInfo ci in characterInfos)
|
||||||
{
|
{
|
||||||
var infoElement = ci.Save(element);
|
var infoElement = ci.Save(element);
|
||||||
if (ci.InventoryData != null) { infoElement.Add(ci.InventoryData); }
|
if (ci.InventoryData != null) { infoElement.Add(ci.InventoryData); }
|
||||||
if (ci.HealthData != null) { infoElement.Add(ci.HealthData); }
|
if (ci.HealthData != null) { infoElement.Add(ci.HealthData); }
|
||||||
|
if (ci.OrderData != null) { infoElement.Add(ci.OrderData); }
|
||||||
if (ci.LastControlled) { infoElement.Add(new XAttribute("lastcontrolled", true)); }
|
if (ci.LastControlled) { infoElement.Add(new XAttribute("lastcontrolled", true)); }
|
||||||
}
|
}
|
||||||
|
SaveActiveOrders(element);
|
||||||
parentElement.Add(element);
|
parentElement.Add(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ClientReadActiveOrders(IReadMessage inc)
|
||||||
|
{
|
||||||
|
ushort count = inc.ReadUInt16();
|
||||||
|
if (count < 1) { return; }
|
||||||
|
var activeOrders = new List<(Order, float?)>();
|
||||||
|
for (ushort i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var orderMessageInfo = OrderChatMessage.ReadOrder(inc);
|
||||||
|
Character orderGiver = null;
|
||||||
|
if (inc.ReadBoolean())
|
||||||
|
{
|
||||||
|
ushort orderGiverId = inc.ReadUInt16();
|
||||||
|
orderGiver = orderGiverId != Entity.NullEntityID ? Entity.FindEntityByID(orderGiverId) as Character : null;
|
||||||
|
}
|
||||||
|
if (orderMessageInfo.OrderIndex < 0 || orderMessageInfo.OrderIndex >= Order.PrefabList.Count)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Invalid active order - order index out of bounds.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Order orderPrefab = orderMessageInfo.OrderPrefab ?? Order.PrefabList[orderMessageInfo.OrderIndex];
|
||||||
|
Order order = orderMessageInfo.TargetType switch
|
||||||
|
{
|
||||||
|
Order.OrderTargetType.Entity =>
|
||||||
|
new Order(orderPrefab, orderMessageInfo.TargetEntity, orderPrefab.GetTargetItemComponent(orderMessageInfo.TargetEntity as Item), orderGiver: orderGiver),
|
||||||
|
Order.OrderTargetType.Position =>
|
||||||
|
new Order(orderPrefab, orderMessageInfo.TargetPosition, orderGiver: orderGiver),
|
||||||
|
Order.OrderTargetType.WallSection =>
|
||||||
|
new Order(orderPrefab, orderMessageInfo.TargetEntity as Structure, orderMessageInfo.WallSectionIndex, orderGiver: orderGiver),
|
||||||
|
_ => throw new NotImplementedException()
|
||||||
|
};
|
||||||
|
if (order != null && order.TargetAllCharacters)
|
||||||
|
{
|
||||||
|
var fadeOutTime = !orderPrefab.IsIgnoreOrder ? (float?)orderPrefab.FadeOutTime : null;
|
||||||
|
activeOrders.Add((order, fadeOutTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var (order, fadeOutTime) in activeOrders)
|
||||||
|
{
|
||||||
|
if (order.IsIgnoreOrder)
|
||||||
|
{
|
||||||
|
switch (order.TargetType)
|
||||||
|
{
|
||||||
|
case Order.OrderTargetType.Entity:
|
||||||
|
if (!(order.TargetEntity is IIgnorable ignorableEntity)) { break; }
|
||||||
|
ignorableEntity.OrderedToBeIgnored = order.Identifier == "ignorethis";
|
||||||
|
break;
|
||||||
|
case Order.OrderTargetType.Position:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
case Order.OrderTargetType.WallSection:
|
||||||
|
if (!order.WallSectionIndex.HasValue) { break; }
|
||||||
|
if (!(order.TargetEntity is Structure s)) { break; }
|
||||||
|
if (!(s.GetSection(order.WallSectionIndex.Value) is IIgnorable ignorableWall)) { break; }
|
||||||
|
ignorableWall.OrderedToBeIgnored = order.Identifier == "ignorethis";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GameMain.GameSession?.CrewManager?.AddOrder(order, fadeOutTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ namespace Barotrauma
|
|||||||
case TransitionType.None:
|
case TransitionType.None:
|
||||||
default:
|
default:
|
||||||
if (Level.Loaded.Type == LevelData.LevelType.Outpost &&
|
if (Level.Loaded.Type == LevelData.LevelType.Outpost &&
|
||||||
(Character.Controlled?.Submarine?.Info.Type == SubmarineType.Player || (Character.Controlled?.CurrentHull?.OutpostModuleTags?.Contains("airlock") ?? false)))
|
(Character.Controlled?.Submarine?.Info.Type == SubmarineType.Player || (Character.Controlled?.CurrentHull?.OutpostModuleTags.Contains("airlock") ?? false)))
|
||||||
{
|
{
|
||||||
buttonText = TextManager.GetWithVariable("LeaveLocation", "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
|
buttonText = TextManager.GetWithVariable("LeaveLocation", "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
|
||||||
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
||||||
@@ -287,6 +287,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
case InteractionType.None:
|
case InteractionType.None:
|
||||||
case InteractionType.Talk:
|
case InteractionType.Talk:
|
||||||
|
case InteractionType.Examine:
|
||||||
return;
|
return;
|
||||||
case InteractionType.Upgrade when !UpgradeManager.CanUpgradeSub():
|
case InteractionType.Upgrade when !UpgradeManager.CanUpgradeSub():
|
||||||
UpgradeManager.CreateUpgradeErrorMessage(TextManager.Get("Dialog.CantUpgrade"), IsSinglePlayer, npc);
|
UpgradeManager.CreateUpgradeErrorMessage(TextManager.Get("Dialog.CantUpgrade"), IsSinglePlayer, npc);
|
||||||
|
|||||||
+44
-1
@@ -326,7 +326,6 @@ namespace Barotrauma
|
|||||||
Level prevLevel = Level.Loaded;
|
Level prevLevel = Level.Loaded;
|
||||||
|
|
||||||
bool success = CrewManager.GetCharacters().Any(c => !c.IsDead);
|
bool success = CrewManager.GetCharacters().Any(c => !c.IsDead);
|
||||||
GUI.SetSavingIndicatorState(success);
|
|
||||||
crewDead = false;
|
crewDead = false;
|
||||||
|
|
||||||
var continueButton = GameMain.GameSession.RoundSummary?.ContinueButton;
|
var continueButton = GameMain.GameSession.RoundSummary?.ContinueButton;
|
||||||
@@ -484,6 +483,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
IsFirstRound = false;
|
IsFirstRound = false;
|
||||||
CoroutineManager.StartCoroutine(DoLevelTransition(), "LevelTransition");
|
CoroutineManager.StartCoroutine(DoLevelTransition(), "LevelTransition");
|
||||||
|
bool success = CrewManager.GetCharacters().Any(c => !c.IsDead);
|
||||||
|
GUI.SetSavingIndicatorState(success && (Level.IsLoadedOutpost || transitionType != TransitionType.None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,6 +570,13 @@ namespace Barotrauma
|
|||||||
msg.Write(category.Identifier);
|
msg.Write(category.Identifier);
|
||||||
msg.Write((byte)level);
|
msg.Write((byte)level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msg.Write((ushort)UpgradeManager.PurchasedItemSwaps.Count);
|
||||||
|
foreach (var itemSwap in UpgradeManager.PurchasedItemSwaps)
|
||||||
|
{
|
||||||
|
msg.Write(itemSwap.ItemToRemove.ID);
|
||||||
|
msg.Write(itemSwap.ItemToInstall?.Identifier ?? string.Empty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//static because we may need to instantiate the campaign if it hasn't been done yet
|
//static because we may need to instantiate the campaign if it hasn't been done yet
|
||||||
@@ -657,6 +665,21 @@ namespace Barotrauma
|
|||||||
pendingUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
|
pendingUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ushort purchasedItemSwapCount = msg.ReadUInt16();
|
||||||
|
List<PurchasedItemSwap> purchasedItemSwaps = new List<PurchasedItemSwap>();
|
||||||
|
for (int i = 0; i < purchasedItemSwapCount; i++)
|
||||||
|
{
|
||||||
|
UInt16 itemToRemoveID = msg.ReadUInt16();
|
||||||
|
Item itemToRemove = Entity.FindEntityByID(itemToRemoveID) as Item;
|
||||||
|
|
||||||
|
string itemToInstallIdentifier = msg.ReadString();
|
||||||
|
ItemPrefab itemToInstall = string.IsNullOrEmpty(itemToInstallIdentifier) ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier);
|
||||||
|
|
||||||
|
if (itemToRemove == null) { continue; }
|
||||||
|
|
||||||
|
purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall));
|
||||||
|
}
|
||||||
|
|
||||||
bool hasCharacterData = msg.ReadBoolean();
|
bool hasCharacterData = msg.ReadBoolean();
|
||||||
CharacterInfo myCharacterInfo = null;
|
CharacterInfo myCharacterInfo = null;
|
||||||
if (hasCharacterData)
|
if (hasCharacterData)
|
||||||
@@ -703,6 +726,26 @@ namespace Barotrauma
|
|||||||
campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades);
|
campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades);
|
||||||
campaign.UpgradeManager.PurchasedUpgrades.Clear();
|
campaign.UpgradeManager.PurchasedUpgrades.Clear();
|
||||||
|
|
||||||
|
campaign.UpgradeManager.PurchasedUpgrades.Clear();
|
||||||
|
foreach (var purchasedItemSwap in purchasedItemSwaps)
|
||||||
|
{
|
||||||
|
if (purchasedItemSwap.ItemToInstall == null)
|
||||||
|
{
|
||||||
|
campaign.UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove, force: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
campaign.UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall, force: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (Item item in Item.ItemList)
|
||||||
|
{
|
||||||
|
if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item))
|
||||||
|
{
|
||||||
|
item.PendingItemSwap = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var (identifier, rep) in factionReps)
|
foreach (var (identifier, rep) in factionReps)
|
||||||
{
|
{
|
||||||
Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase));
|
Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|||||||
+8
-3
@@ -101,7 +101,8 @@ namespace Barotrauma
|
|||||||
case "cargo":
|
case "cargo":
|
||||||
CargoManager.LoadPurchasedItems(subElement);
|
CargoManager.LoadPurchasedItems(subElement);
|
||||||
break;
|
break;
|
||||||
case "pendingupgrades":
|
case "pendingupgrades": //backwards compatibility
|
||||||
|
case "upgrademanager":
|
||||||
UpgradeManager = new UpgradeManager(this, subElement, isSingleplayer: true);
|
UpgradeManager = new UpgradeManager(this, subElement, isSingleplayer: true);
|
||||||
break;
|
break;
|
||||||
case "pets":
|
case "pets":
|
||||||
@@ -229,6 +230,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
PetBehavior.LoadPets(petsElement);
|
PetBehavior.LoadPets(petsElement);
|
||||||
}
|
}
|
||||||
|
CrewManager.LoadActiveOrders();
|
||||||
|
|
||||||
GUI.DisableSavingIndicatorDelayed();
|
GUI.DisableSavingIndicatorDelayed();
|
||||||
}
|
}
|
||||||
@@ -480,6 +482,8 @@ namespace Barotrauma
|
|||||||
EnableRoundSummaryGameOverState();
|
EnableRoundSummaryGameOverState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CrewManager?.ClearCurrentOrders();
|
||||||
|
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
|
|
||||||
SelectSummaryScreen(roundSummary, newLevel, mirror, () =>
|
SelectSummaryScreen(roundSummary, newLevel, mirror, () =>
|
||||||
@@ -735,9 +739,10 @@ namespace Barotrauma
|
|||||||
if (c.Inventory != null)
|
if (c.Inventory != null)
|
||||||
{
|
{
|
||||||
c.Info.InventoryData = new XElement("inventory");
|
c.Info.InventoryData = new XElement("inventory");
|
||||||
c.SaveInventory(c.Inventory, c.Info.InventoryData);
|
c.SaveInventory();
|
||||||
c.Inventory?.DeleteAllItems();
|
c.Inventory?.DeleteAllItems();
|
||||||
}
|
}
|
||||||
|
c.Info.SaveOrderData();
|
||||||
}
|
}
|
||||||
|
|
||||||
petsElement = new XElement("pets");
|
petsElement = new XElement("pets");
|
||||||
@@ -748,7 +753,7 @@ namespace Barotrauma
|
|||||||
CampaignMetadata.Save(modeElement);
|
CampaignMetadata.Save(modeElement);
|
||||||
Map.Save(modeElement);
|
Map.Save(modeElement);
|
||||||
CargoManager?.SavePurchasedItems(modeElement);
|
CargoManager?.SavePurchasedItems(modeElement);
|
||||||
UpgradeManager?.SavePendingUpgrades(modeElement, UpgradeManager?.PendingUpgrades);
|
UpgradeManager?.Save(modeElement);
|
||||||
element.Add(modeElement);
|
element.Add(modeElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -531,7 +531,7 @@ namespace Barotrauma.Tutorials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
yield return null;
|
yield return null;
|
||||||
} while (!mechanic.HasEquippedItem("divingsuit"));
|
} while (!mechanic.HasEquippedItem("divingsuit", slotType: InvSlotType.OuterClothes));
|
||||||
SetHighlight(mechanic_divingSuitContainer.Item, false);
|
SetHighlight(mechanic_divingSuitContainer.Item, false);
|
||||||
RemoveCompletedObjective(segments[8]);
|
RemoveCompletedObjective(segments[8]);
|
||||||
SetDoorAccess(tutorial_mechanicFinalDoor, tutorial_mechanicFinalDoorLight, true);
|
SetDoorAccess(tutorial_mechanicFinalDoor, tutorial_mechanicFinalDoorLight, true);
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ namespace Barotrauma
|
|||||||
private static void CheckIfDivingGearOutOfOxygen()
|
private static void CheckIfDivingGearOutOfOxygen()
|
||||||
{
|
{
|
||||||
if (!CanDisplayHints()) { return; }
|
if (!CanDisplayHints()) { return; }
|
||||||
var divingGear = Character.Controlled.GetEquippedItem("diving");
|
var divingGear = Character.Controlled.GetEquippedItem("diving", InvSlotType.OuterClothes);
|
||||||
if (divingGear?.OwnInventory == null) { return; }
|
if (divingGear?.OwnInventory == null) { return; }
|
||||||
if (divingGear.GetContainedItemConditionPercentage() > 0.0f) { return; }
|
if (divingGear.GetContainedItemConditionPercentage() > 0.0f) { return; }
|
||||||
DisplayHint("ondivinggearoutofoxygen", onUpdate: () =>
|
DisplayHint("ondivinggearoutofoxygen", onUpdate: () =>
|
||||||
|
|||||||
@@ -311,10 +311,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform),
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform),
|
||||||
missionMessage, wrap: true, parseRichText: true);
|
missionMessage, wrap: true, parseRichText: true);
|
||||||
if (selectedMissions.Contains(displayedMission) && displayedMission.Completed && displayedMission.Reward > 0)
|
int reward = displayedMission.GetReward(Submarine.MainSub);
|
||||||
|
if (selectedMissions.Contains(displayedMission) && displayedMission.Completed && reward > 0)
|
||||||
{
|
{
|
||||||
string rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", displayedMission.Reward));
|
string rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", reward));
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), displayedMission.GetMissionRewardText(), parseRichText: true);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), displayedMission.GetMissionRewardText(Submarine.MainSub), parseRichText: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displayedMission != missionsToDisplay.Last())
|
if (displayedMission != missionsToDisplay.Last())
|
||||||
|
|||||||
@@ -910,7 +910,7 @@ namespace Barotrauma
|
|||||||
else if (allowEquip) //doubleclicked and no other inventory is selected
|
else if (allowEquip) //doubleclicked and no other inventory is selected
|
||||||
{
|
{
|
||||||
//not equipped -> attempt to equip
|
//not equipped -> attempt to equip
|
||||||
if (!character.HasEquippedItem(item))
|
if (!character.HasEquippedItem(item) || item.GetComponents<Pickable>().Count() > 1)
|
||||||
{
|
{
|
||||||
return QuickUseAction.Equip;
|
return QuickUseAction.Equip;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private GUICustomComponent guiCustomComponent;
|
private GUICustomComponent guiCustomComponent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Can be used to set the sprite depth individually for each contained item
|
||||||
|
/// </summary>
|
||||||
|
private float[] containedSpriteDepths;
|
||||||
|
|
||||||
public Sprite InventoryTopSprite
|
public Sprite InventoryTopSprite
|
||||||
{
|
{
|
||||||
get { return inventoryTopSprite; }
|
get { return inventoryTopSprite; }
|
||||||
@@ -153,6 +158,8 @@ namespace Barotrauma.Items.Components
|
|||||||
//if a GUIFrame has been defined, draw the inventory inside it
|
//if a GUIFrame has been defined, draw the inventory inside it
|
||||||
CreateGUI();
|
CreateGUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
containedSpriteDepths = element.GetAttributeFloatArray("containedspritedepths", new float[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateGUI()
|
protected override void CreateGUI()
|
||||||
@@ -316,6 +323,10 @@ namespace Barotrauma.Items.Components
|
|||||||
if (item.FlippedY) { origin.Y = containedItem.Sprite.SourceRect.Height - origin.Y; }
|
if (item.FlippedY) { origin.Y = containedItem.Sprite.SourceRect.Height - origin.Y; }
|
||||||
|
|
||||||
float containedSpriteDepth = ContainedSpriteDepth < 0.0f ? containedItem.Sprite.Depth : ContainedSpriteDepth;
|
float containedSpriteDepth = ContainedSpriteDepth < 0.0f ? containedItem.Sprite.Depth : ContainedSpriteDepth;
|
||||||
|
if (i < containedSpriteDepths.Length)
|
||||||
|
{
|
||||||
|
containedSpriteDepth = containedSpriteDepths[i];
|
||||||
|
}
|
||||||
containedSpriteDepth = itemDepth + (containedSpriteDepth - (item.Sprite?.Depth ?? item.SpriteDepth)) / 10000.0f;
|
containedSpriteDepth = itemDepth + (containedSpriteDepth - (item.Sprite?.Depth ?? item.SpriteDepth)) / 10000.0f;
|
||||||
|
|
||||||
containedItem.Sprite.Draw(
|
containedItem.Sprite.Draw(
|
||||||
|
|||||||
@@ -199,13 +199,9 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
Color neutralColor = Color.DarkCyan;
|
Color neutralColor = Color.DarkCyan;
|
||||||
if (hull.RoomName != null)
|
if (hull.IsWetRoom)
|
||||||
{
|
{
|
||||||
if (hull.RoomName.Contains("ballast") || hull.RoomName.Contains("Ballast") ||
|
neutralColor = new Color(9, 80, 159);
|
||||||
hull.RoomName.Contains("airlock") || hull.RoomName.Contains("Airlock"))
|
|
||||||
{
|
|
||||||
neutralColor = new Color(9, 80, 159);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hullData.Distort)
|
if (hullData.Distort)
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private GUIFrame inventoryContainer;
|
private GUIFrame inventoryContainer;
|
||||||
|
|
||||||
|
private GUILayoutGroup paddedFrame;
|
||||||
|
|
||||||
private readonly Dictionary<string, GUIButton> warningButtons = new Dictionary<string, GUIButton>();
|
private readonly Dictionary<string, GUIButton> warningButtons = new Dictionary<string, GUIButton>();
|
||||||
|
|
||||||
private static readonly string[] warningTexts = new string[]
|
private static readonly string[] warningTexts = new string[]
|
||||||
@@ -74,7 +76,7 @@ namespace Barotrauma.Items.Components
|
|||||||
tempRangeIndicator = new Sprite(element.GetChildElement("temprangeindicator")?.GetChildElement("sprite"));
|
tempRangeIndicator = new Sprite(element.GetChildElement("temprangeindicator")?.GetChildElement("sprite"));
|
||||||
graphLine = new Sprite(element.GetChildElement("graphline")?.GetChildElement("sprite"));
|
graphLine = new Sprite(element.GetChildElement("graphline")?.GetChildElement("sprite"));
|
||||||
|
|
||||||
var paddedFrame = new GUILayoutGroup(new RectTransform(
|
paddedFrame = new GUILayoutGroup(new RectTransform(
|
||||||
GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center)
|
GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center)
|
||||||
{ AbsoluteOffset = GUIStyle.ItemFrameOffset },
|
{ AbsoluteOffset = GUIStyle.ItemFrameOffset },
|
||||||
isHorizontal: true)
|
isHorizontal: true)
|
||||||
@@ -128,27 +130,27 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
|
|
||||||
Point maxIndicatorSize = new Point(int.MaxValue, (int)(40 * GUI.Scale));
|
Point maxIndicatorSize = new Point(int.MaxValue, (int)(40 * GUI.Scale));
|
||||||
criticalHeatWarning = new GUITickBox(new RectTransform(new Vector2(0.33f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize },
|
criticalHeatWarning = new GUITickBox(new RectTransform(new Vector2(0.3f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize },
|
||||||
TextManager.Get("ReactorWarningCriticalTemp"), font: GUI.SubHeadingFont, style: "IndicatorLightRed")
|
TextManager.Get("ReactorWarningCriticalTemp"), font: GUI.SubHeadingFont, style: "IndicatorLightRed")
|
||||||
{
|
{
|
||||||
Selected = false,
|
Selected = false,
|
||||||
Enabled = false,
|
Enabled = false,
|
||||||
ToolTip = TextManager.Get("ReactorHeatTip")
|
ToolTip = TextManager.Get("ReactorHeatTip")
|
||||||
};
|
};
|
||||||
lowTemperatureWarning = new GUITickBox(new RectTransform(new Vector2(0.33f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize },
|
criticalOutputWarning = new GUITickBox(new RectTransform(new Vector2(0.3f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize },
|
||||||
TextManager.Get("ReactorWarningCriticalLowTemp"), font: GUI.SubHeadingFont, style: "IndicatorLightRed")
|
|
||||||
{
|
|
||||||
Selected = false,
|
|
||||||
Enabled = false,
|
|
||||||
ToolTip = TextManager.Get("ReactorTempTip")
|
|
||||||
};
|
|
||||||
criticalOutputWarning = new GUITickBox(new RectTransform(new Vector2(0.33f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize },
|
|
||||||
TextManager.Get("ReactorWarningCriticalOutput"), font: GUI.SubHeadingFont, style: "IndicatorLightRed")
|
TextManager.Get("ReactorWarningCriticalOutput"), font: GUI.SubHeadingFont, style: "IndicatorLightRed")
|
||||||
{
|
{
|
||||||
Selected = false,
|
Selected = false,
|
||||||
Enabled = false,
|
Enabled = false,
|
||||||
ToolTip = TextManager.Get("ReactorOutputTip")
|
ToolTip = TextManager.Get("ReactorOutputTip")
|
||||||
};
|
};
|
||||||
|
lowTemperatureWarning = new GUITickBox(new RectTransform(new Vector2(0.4f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize },
|
||||||
|
TextManager.Get("ReactorWarningCriticalLowTemp"), font: GUI.SubHeadingFont, style: "IndicatorLightRed")
|
||||||
|
{
|
||||||
|
Selected = false,
|
||||||
|
Enabled = false,
|
||||||
|
ToolTip = TextManager.Get("ReactorTempTip")
|
||||||
|
};
|
||||||
List<GUITickBox> indicatorLights = new List<GUITickBox>() { criticalHeatWarning, lowTemperatureWarning, criticalOutputWarning };
|
List<GUITickBox> indicatorLights = new List<GUITickBox>() { criticalHeatWarning, lowTemperatureWarning, criticalOutputWarning };
|
||||||
indicatorLights.ForEach(l => l.TextBlock.OverrideTextColor(GUI.Style.TextColor));
|
indicatorLights.ForEach(l => l.TextBlock.OverrideTextColor(GUI.Style.TextColor));
|
||||||
topLeftArea.Recalculate();
|
topLeftArea.Recalculate();
|
||||||
@@ -334,8 +336,9 @@ namespace Barotrauma.Items.Components
|
|||||||
};
|
};
|
||||||
|
|
||||||
topRightArea.Recalculate();
|
topRightArea.Recalculate();
|
||||||
autoTempLight.TextBlock.Wrap = true;
|
autoTempLight.TextBlock.Padding = new Vector4(autoTempLight.TextBlock.Padding.X, 0.0f, 0.0f, 0.0f);
|
||||||
indicatorLights.Add(autoTempLight);
|
autoTempLight.TextBlock.Text = autoTempLight.TextBlock.Text.Replace(' ', '\n');
|
||||||
|
autoTempLight.TextBlock.AutoScaleHorizontal = true;
|
||||||
GUITextBlock.AutoScaleAndNormalize(indicatorLights.Select(l => l.TextBlock));
|
GUITextBlock.AutoScaleAndNormalize(indicatorLights.Select(l => l.TextBlock));
|
||||||
|
|
||||||
// right bottom (graph area) -----------------------
|
// right bottom (graph area) -----------------------
|
||||||
@@ -533,8 +536,7 @@ namespace Barotrauma.Items.Components
|
|||||||
warningButtons["ReactorWarningMeltdown"].Selected = meltDownTimer > MeltdownDelay * 0.5f || item.Condition == 0.0f && lightOn;
|
warningButtons["ReactorWarningMeltdown"].Selected = meltDownTimer > MeltdownDelay * 0.5f || item.Condition == 0.0f && lightOn;
|
||||||
warningButtons["ReactorWarningSCRAM"].Selected = temperature > 0.1f && !PowerOn;
|
warningButtons["ReactorWarningSCRAM"].Selected = temperature > 0.1f && !PowerOn;
|
||||||
|
|
||||||
if ((FissionRateScrollBar.Rect.Contains(PlayerInput.MousePosition) || FissionRateScrollBar.Children.Contains(GUIScrollBar.DraggingBar) ||
|
if (paddedFrame.Rect.Contains(PlayerInput.MousePosition) &&
|
||||||
TurbineOutputScrollBar.Rect.Contains(PlayerInput.MousePosition) || TurbineOutputScrollBar.Children.Contains(GUIScrollBar.DraggingBar)) &&
|
|
||||||
!PlayerInput.KeyDown(InputType.Deselect) && !PlayerInput.KeyHit(InputType.Deselect))
|
!PlayerInput.KeyDown(InputType.Deselect) && !PlayerInput.KeyHit(InputType.Deselect))
|
||||||
{
|
{
|
||||||
Character.DisableControls = true;
|
Character.DisableControls = true;
|
||||||
|
|||||||
@@ -87,21 +87,6 @@ namespace Barotrauma.Items.Components
|
|||||||
//float = strength of the disruption, between 0-1
|
//float = strength of the disruption, between 0-1
|
||||||
private readonly List<Pair<Vector2, float>> disruptedDirections = new List<Pair<Vector2, float>>();
|
private readonly List<Pair<Vector2, float>> disruptedDirections = new List<Pair<Vector2, float>>();
|
||||||
|
|
||||||
class CachedDistance
|
|
||||||
{
|
|
||||||
public readonly Vector2 TransducerWorldPos;
|
|
||||||
public readonly Vector2 WorldPos;
|
|
||||||
public readonly float Distance;
|
|
||||||
public double RecalculationTime;
|
|
||||||
|
|
||||||
public CachedDistance(Vector2 transducerWorldPos, Vector2 worldPos, float dist)
|
|
||||||
{
|
|
||||||
TransducerWorldPos = transducerWorldPos;
|
|
||||||
WorldPos = worldPos;
|
|
||||||
Distance = dist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Dictionary<object, CachedDistance> markerDistances = new Dictionary<object, CachedDistance>();
|
private readonly Dictionary<object, CachedDistance> markerDistances = new Dictionary<object, CachedDistance>();
|
||||||
|
|
||||||
private readonly Color positiveColor = Color.Green;
|
private readonly Color positiveColor = Color.Green;
|
||||||
@@ -459,8 +444,13 @@ namespace Barotrauma.Items.Components
|
|||||||
zoomSlider.BarScroll += PlayerInput.ScrollWheelSpeed / 1000.0f;
|
zoomSlider.BarScroll += PlayerInput.ScrollWheelSpeed / 1000.0f;
|
||||||
zoomSlider.OnMoved(zoomSlider, zoomSlider.BarScroll);
|
zoomSlider.OnMoved(zoomSlider, zoomSlider.BarScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PlayerInput.KeyHit(InputType.Run))
|
||||||
|
{
|
||||||
|
SonarModeSwitch.OnClicked(SonarModeSwitch, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float distort = 1.0f - item.Condition / item.MaxCondition;
|
float distort = 1.0f - item.Condition / item.MaxCondition;
|
||||||
for (int i = sonarBlips.Count - 1; i >= 0; i--)
|
for (int i = sonarBlips.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
@@ -1101,19 +1091,14 @@ namespace Barotrauma.Items.Components
|
|||||||
if (Level.Loaded != null && dockingPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
|
if (Level.Loaded != null && dockingPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
|
||||||
if (dockingPort.Item.Submarine == null) { continue; }
|
if (dockingPort.Item.Submarine == null) { continue; }
|
||||||
if (dockingPort.Item.Submarine.Info.IsWreck) { continue; }
|
if (dockingPort.Item.Submarine.Info.IsWreck) { continue; }
|
||||||
if (!dockingPort.Item.Submarine.ShowSonarMarker && !dockingPort.Item.Submarine.Info.IsOutpost) { continue; }
|
// docking ports should be shown even if defined as not, if the submarine is the same as the sonar's
|
||||||
|
if (!dockingPort.Item.Submarine.ShowSonarMarker && dockingPort.Item.Submarine != item.Submarine && !dockingPort.Item.Submarine.Info.IsOutpost) { continue; }
|
||||||
|
|
||||||
//don't show the docking ports of the opposing team on the sonar
|
//don't show the docking ports of the opposing team on the sonar
|
||||||
if (item.Submarine != null)
|
if (item.Submarine != null)
|
||||||
{
|
{
|
||||||
if (dockingPort.Item.Submarine.TeamID == CharacterTeamType.Team1 && (item.Submarine.TeamID == CharacterTeamType.Team2 || Character.Controlled?.TeamID == CharacterTeamType.Team2))
|
// specifically checking for friendlyNPC seems more logical here
|
||||||
{
|
if (dockingPort.Item.Submarine.TeamID != item.Submarine.TeamID && dockingPort.Item.Submarine.TeamID != CharacterTeamType.FriendlyNPC) { continue; }
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (dockingPort.Item.Submarine.TeamID == CharacterTeamType.Team2 && (item.Submarine.TeamID == CharacterTeamType.Team1 || Character.Controlled?.TeamID == CharacterTeamType.Team1))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 offset = (dockingPort.Item.WorldPosition - transducerCenter) * scale;
|
Vector2 offset = (dockingPort.Item.WorldPosition - transducerCenter) * scale;
|
||||||
@@ -1629,9 +1614,7 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
if (markerDistances.TryGetValue(targetIdentifier, out CachedDistance cachedDistance))
|
if (markerDistances.TryGetValue(targetIdentifier, out CachedDistance cachedDistance))
|
||||||
{
|
{
|
||||||
if (Timing.TotalTime > cachedDistance.RecalculationTime &&
|
if (cachedDistance.ShouldUpdateDistance(transducerPosition, worldPosition))
|
||||||
(Vector2.DistanceSquared(cachedDistance.TransducerWorldPos, transducerPosition) > 500 * 500 ||
|
|
||||||
Vector2.DistanceSquared(cachedDistance.WorldPos, worldPosition) > 500 * 500))
|
|
||||||
{
|
{
|
||||||
markerDistances.Remove(targetIdentifier);
|
markerDistances.Remove(targetIdentifier);
|
||||||
CalculateDistance();
|
CalculateDistance();
|
||||||
@@ -1653,10 +1636,7 @@ namespace Barotrauma.Items.Components
|
|||||||
var path = pathFinder.FindPath(ConvertUnits.ToSimUnits(transducerPosition), ConvertUnits.ToSimUnits(worldPosition));
|
var path = pathFinder.FindPath(ConvertUnits.ToSimUnits(transducerPosition), ConvertUnits.ToSimUnits(worldPosition));
|
||||||
if (!path.Unreachable)
|
if (!path.Unreachable)
|
||||||
{
|
{
|
||||||
var cachedDistance = new CachedDistance(transducerPosition, worldPosition, path.TotalLength)
|
var cachedDistance = new CachedDistance(transducerPosition, worldPosition, path.TotalLength, Timing.TotalTime + Rand.Range(1.0f, 5.0f));
|
||||||
{
|
|
||||||
RecalculationTime = Timing.TotalTime + Rand.Range(1.0f, 5.0f)
|
|
||||||
};
|
|
||||||
markerDistances.Add(targetIdentifier, cachedDistance);
|
markerDistances.Add(targetIdentifier, cachedDistance);
|
||||||
dist = path.TotalLength;
|
dist = path.TotalLength;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
|
using Barotrauma.Particles;
|
||||||
|
using FarseerPhysics;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class Projectile : ItemComponent
|
partial class Projectile : ItemComponent
|
||||||
{
|
{
|
||||||
|
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||||
|
|
||||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||||
{
|
{
|
||||||
bool launch = msg.ReadBoolean();
|
bool launch = msg.ReadBoolean();
|
||||||
@@ -96,5 +102,30 @@ namespace Barotrauma.Items.Components
|
|||||||
Unstick();
|
Unstick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void LaunchProjSpecific(Vector2 startLocation, Vector2 endLocation)
|
||||||
|
{
|
||||||
|
Vector2 particlePos = item.WorldPosition;
|
||||||
|
float rotation = -item.body.Rotation;
|
||||||
|
if (item.body.Dir < 0.0f) { rotation += MathHelper.Pi; }
|
||||||
|
Tuple<Vector2, Vector2> tracerPoints = new Tuple<Vector2, Vector2>(startLocation, endLocation);
|
||||||
|
foreach (ParticleEmitter emitter in particleEmitters)
|
||||||
|
{
|
||||||
|
emitter.Emit(1.0f, particlePos, hullGuess: null, angle: rotation, particleRotation: rotation, colorMultiplier: emitter.Prefab.ColorMultiplier, tracerPoints: tracerPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void InitProjSpecific(XElement element)
|
||||||
|
{
|
||||||
|
foreach (XElement subElement in element.Elements())
|
||||||
|
{
|
||||||
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case "particleemitter":
|
||||||
|
particleEmitters.Add(new ParticleEmitter(subElement));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,12 +36,30 @@ namespace Barotrauma.Items.Components
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (target == null || source == null) { return Vector2.Zero; }
|
if (target == null || source == null) { return Vector2.Zero; }
|
||||||
|
|
||||||
|
Vector2 sourcePos = GetSourcePos();
|
||||||
|
|
||||||
return new Vector2(
|
return new Vector2(
|
||||||
Math.Abs(target.DrawPosition.X - source.DrawPosition.X),
|
Math.Abs(target.DrawPosition.X - sourcePos.X),
|
||||||
Math.Abs(target.DrawPosition.Y - source.DrawPosition.Y)) * 1.5f;
|
Math.Abs(target.DrawPosition.Y - sourcePos.Y)) * 1.5f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Vector2 GetSourcePos()
|
||||||
|
{
|
||||||
|
Vector2 sourcePos = source.WorldPosition;
|
||||||
|
if (source is Item sourceItem)
|
||||||
|
{
|
||||||
|
sourcePos = sourceItem.DrawPosition;
|
||||||
|
}
|
||||||
|
else if (source is Limb sourceLimb && sourceLimb.body != null)
|
||||||
|
{
|
||||||
|
sourcePos = sourceLimb.body.DrawPosition;
|
||||||
|
}
|
||||||
|
return sourcePos;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
partial void InitProjSpecific(XElement element)
|
partial void InitProjSpecific(XElement element)
|
||||||
{
|
{
|
||||||
foreach (XElement subElement in element.Elements())
|
foreach (XElement subElement in element.Elements())
|
||||||
@@ -65,14 +83,18 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
if (target == null) { return; }
|
if (target == null) { return; }
|
||||||
|
|
||||||
Vector2 startPos = new Vector2(source.DrawPosition.X, -source.DrawPosition.Y);
|
Vector2 startPos = GetSourcePos();
|
||||||
var turret = source?.GetComponent<Turret>();
|
startPos.Y = -startPos.Y;
|
||||||
if (turret != null)
|
if (source is Item sourceItem)
|
||||||
{
|
{
|
||||||
startPos = new Vector2(source.WorldRect.X + turret.TransformedBarrelPos.X, -(source.WorldRect.Y - turret.TransformedBarrelPos.Y));
|
var turret = sourceItem?.GetComponent<Turret>();
|
||||||
if (turret.BarrelSprite != null)
|
if (turret != null)
|
||||||
{
|
{
|
||||||
startPos += new Vector2((float)Math.Cos(turret.Rotation), (float)Math.Sin(turret.Rotation)) * turret.BarrelSprite.size.Y * turret.BarrelSprite.RelativeOrigin.Y * item.Scale * 0.9f;
|
startPos = new Vector2(sourceItem.WorldRect.X + turret.TransformedBarrelPos.X, -(sourceItem.WorldRect.Y - turret.TransformedBarrelPos.Y));
|
||||||
|
if (turret.BarrelSprite != null)
|
||||||
|
{
|
||||||
|
startPos += new Vector2((float)Math.Cos(turret.Rotation), (float)Math.Sin(turret.Rotation)) * turret.BarrelSprite.size.Y * turret.BarrelSprite.RelativeOrigin.Y * item.Scale * 0.9f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Vector2 endPos = new Vector2(target.DrawPosition.X, -target.DrawPosition.Y);
|
Vector2 endPos = new Vector2(target.DrawPosition.X, -target.DrawPosition.Y);
|
||||||
@@ -80,7 +102,7 @@ namespace Barotrauma.Items.Components
|
|||||||
if (Snapped)
|
if (Snapped)
|
||||||
{
|
{
|
||||||
float snapState = 1.0f - snapTimer / SnapAnimDuration;
|
float snapState = 1.0f - snapTimer / SnapAnimDuration;
|
||||||
Vector2 diff = target.DrawPosition - source.DrawPosition;
|
Vector2 diff = target.DrawPosition - new Vector2(startPos.X, -startPos.Y);
|
||||||
diff.Y = -diff.Y;
|
diff.Y = -diff.Y;
|
||||||
|
|
||||||
int width = (int)(SpriteWidth * snapState);
|
int width = (int)(SpriteWidth * snapState);
|
||||||
|
|||||||
@@ -17,15 +17,6 @@ namespace Barotrauma.Items.Components
|
|||||||
TextManager.Get("CatastrophicBleeding")
|
TextManager.Get("CatastrophicBleeding")
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly string[] HealthTexts =
|
|
||||||
{
|
|
||||||
TextManager.Get("NoInjuries"),
|
|
||||||
TextManager.Get("MinorInjuries"),
|
|
||||||
TextManager.Get("Injuries"),
|
|
||||||
TextManager.Get("MajorInjuries"),
|
|
||||||
TextManager.Get("CriticalInjuries")
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly string[] OxygenTexts =
|
private static readonly string[] OxygenTexts =
|
||||||
{
|
{
|
||||||
TextManager.Get("OxygenNormal"),
|
TextManager.Get("OxygenNormal"),
|
||||||
@@ -147,9 +138,13 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
List<string> texts = new List<string>();
|
List<string> texts = new List<string>();
|
||||||
List<Color> textColors = new List<Color>();
|
List<Color> textColors = new List<Color>();
|
||||||
|
|
||||||
texts.Add(target.Info == null ? target.DisplayName : target.Info.DisplayName);
|
texts.Add(target.Info == null ? target.DisplayName : target.Info.DisplayName);
|
||||||
textColors.Add(GUI.Style.TextColor);
|
Color nameColor = GUI.Style.TextColor;
|
||||||
|
if (Character.Controlled != null && target.TeamID != Character.Controlled.TeamID)
|
||||||
|
{
|
||||||
|
nameColor = target.TeamID == CharacterTeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
|
||||||
|
}
|
||||||
|
textColors.Add(nameColor);
|
||||||
|
|
||||||
if (target.IsDead)
|
if (target.IsDead)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,7 +34,9 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private RoundSound startMoveSound, endMoveSound, moveSound;
|
private RoundSound startMoveSound, endMoveSound, moveSound;
|
||||||
|
|
||||||
private SoundChannel moveSoundChannel;
|
private RoundSound chargeSound;
|
||||||
|
|
||||||
|
private SoundChannel moveSoundChannel, chargeSoundChannel;
|
||||||
private Vector2 oldRotation = Vector2.Zero;
|
private Vector2 oldRotation = Vector2.Zero;
|
||||||
|
|
||||||
private Vector2 crosshairPos, crosshairPointerPos;
|
private Vector2 crosshairPos, crosshairPointerPos;
|
||||||
@@ -43,11 +45,16 @@ namespace Barotrauma.Items.Components
|
|||||||
private float prevAngle;
|
private float prevAngle;
|
||||||
|
|
||||||
private bool flashLowPower;
|
private bool flashLowPower;
|
||||||
private bool flashNoAmmo;
|
private bool flashNoAmmo, flashLoaderBroken;
|
||||||
private float flashTimer;
|
private float flashTimer;
|
||||||
private float flashLength = 1;
|
private readonly float flashLength = 1;
|
||||||
|
|
||||||
|
private const float MaxCircle = 360f;
|
||||||
|
private const float HalfCircle = 180f;
|
||||||
|
private const float QuarterCircle = 90f;
|
||||||
|
|
||||||
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||||
|
private readonly List<ParticleEmitter> particleEmitterCharges = new List<ParticleEmitter>();
|
||||||
|
|
||||||
[Editable, Serialize("0,0,0,0", true, description: "Optional screen tint color when the item is being operated (R,G,B,A).")]
|
[Editable, Serialize("0,0,0,0", true, description: "Optional screen tint color when the item is being operated (R,G,B,A).")]
|
||||||
public Color HudTint
|
public Color HudTint
|
||||||
@@ -77,6 +84,21 @@ namespace Barotrauma.Items.Components
|
|||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serialize(0.0f, false, description: "The distance in which the spinning barrels rotate. Only used if spinning barrels are created.")]
|
||||||
|
public float SpinningBarrelDistance
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serialize(false, false, description: "Use firing offset for muzzleflash? This field shouldn't be needed but I'm using it for prototyping")]
|
||||||
|
public bool UseFiringOffsetForMuzzleFlash
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Vector2 DrawSize
|
public Vector2 DrawSize
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -124,9 +146,15 @@ namespace Barotrauma.Items.Components
|
|||||||
case "movesound":
|
case "movesound":
|
||||||
moveSound = Submarine.LoadRoundSound(subElement, false);
|
moveSound = Submarine.LoadRoundSound(subElement, false);
|
||||||
break;
|
break;
|
||||||
|
case "chargesound":
|
||||||
|
chargeSound = Submarine.LoadRoundSound(subElement, false);
|
||||||
|
break;
|
||||||
case "particleemitter":
|
case "particleemitter":
|
||||||
particleEmitters.Add(new ParticleEmitter(subElement));
|
particleEmitters.Add(new ParticleEmitter(subElement));
|
||||||
break;
|
break;
|
||||||
|
case "particleemittercharge":
|
||||||
|
particleEmitterCharges.Add(new ParticleEmitter(subElement));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +178,7 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
recoilTimer = RetractionTime;
|
recoilTimer = RetractionTime;
|
||||||
PlaySound(ActionType.OnUse);
|
PlaySound(ActionType.OnUse);
|
||||||
Vector2 particlePos = new Vector2(item.WorldRect.X + transformedBarrelPos.X, item.WorldRect.Y - transformedBarrelPos.Y);
|
Vector2 particlePos = GetRelativeFiringPosition(UseFiringOffsetForMuzzleFlash);
|
||||||
foreach (ParticleEmitter emitter in particleEmitters)
|
foreach (ParticleEmitter emitter in particleEmitters)
|
||||||
{
|
{
|
||||||
emitter.Emit(1.0f, particlePos, hullGuess: null, angle: -rotation, particleRotation: rotation);
|
emitter.Emit(1.0f, particlePos, hullGuess: null, angle: -rotation, particleRotation: rotation);
|
||||||
@@ -215,12 +243,55 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float chargeRatio = currentChargeTime / MaxChargeTime;
|
||||||
|
currentBarrelSpin = (currentBarrelSpin + MaxCircle * chargeRatio * deltaTime * 3f) % MaxCircle;
|
||||||
|
|
||||||
|
switch (currentChargingState)
|
||||||
|
{
|
||||||
|
case ChargingState.WindingUp:
|
||||||
|
Vector2 particlePos = GetRelativeFiringPosition();
|
||||||
|
float sizeMultiplier = Math.Clamp(chargeRatio, 0.1f, 1f);
|
||||||
|
foreach (ParticleEmitter emitter in particleEmitterCharges)
|
||||||
|
{
|
||||||
|
// color is currently not connected to ammo type, should be updated when ammo is changed
|
||||||
|
emitter.Emit(deltaTime, particlePos, hullGuess: null, angle: -rotation, particleRotation: rotation, sizeMultiplier: sizeMultiplier, colorMultiplier: emitter.Prefab.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(1f, 2f, chargeRatio);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (chargeSoundChannel != null)
|
||||||
|
{
|
||||||
|
if (chargeSoundChannel.IsPlaying)
|
||||||
|
{
|
||||||
|
chargeSoundChannel.FadeOutAndDispose();
|
||||||
|
chargeSoundChannel.Looping = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chargeSoundChannel = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (moveSoundChannel != null && moveSoundChannel.IsPlaying)
|
if (moveSoundChannel != null && moveSoundChannel.IsPlaying)
|
||||||
{
|
{
|
||||||
moveSoundChannel.Gain = MathHelper.Clamp(Math.Abs(angularVelocity), 0.5f, 1.0f);
|
moveSoundChannel.Gain = MathHelper.Clamp(Math.Abs(angularVelocity), 0.5f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flashLowPower || flashNoAmmo)
|
if (flashLowPower || flashNoAmmo || flashLoaderBroken)
|
||||||
{
|
{
|
||||||
flashTimer += deltaTime;
|
flashTimer += deltaTime;
|
||||||
if (flashTimer >= flashLength)
|
if (flashTimer >= flashLength)
|
||||||
@@ -228,6 +299,7 @@ namespace Barotrauma.Items.Components
|
|||||||
flashTimer = 0;
|
flashTimer = 0;
|
||||||
flashLowPower = false;
|
flashLowPower = false;
|
||||||
flashNoAmmo = false;
|
flashNoAmmo = false;
|
||||||
|
flashLoaderBroken = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -289,6 +361,42 @@ namespace Barotrauma.Items.Components
|
|||||||
rotation + MathHelper.PiOver2, item.Scale,
|
rotation + MathHelper.PiOver2, item.Scale,
|
||||||
SpriteEffects.None, item.SpriteDepth + (barrelSprite.Depth - item.Sprite.Depth));
|
SpriteEffects.None, item.SpriteDepth + (barrelSprite.Depth - item.Sprite.Depth));
|
||||||
|
|
||||||
|
float chargeRatio = currentChargeTime / MaxChargeTime;
|
||||||
|
|
||||||
|
foreach (Tuple<Sprite, Vector2> chargeSprite in chargeSprites)
|
||||||
|
{
|
||||||
|
chargeSprite.Item1?.Draw(spriteBatch,
|
||||||
|
drawPos - MathUtils.RotatePoint(new Vector2(chargeSprite.Item2.X * chargeRatio, chargeSprite.Item2.Y * chargeRatio) * item.Scale, rotation + MathHelper.PiOver2),
|
||||||
|
item.SpriteColor,
|
||||||
|
rotation + MathHelper.PiOver2, item.Scale,
|
||||||
|
SpriteEffects.None, item.SpriteDepth + (chargeSprite.Item1.Depth - item.Sprite.Depth));
|
||||||
|
}
|
||||||
|
|
||||||
|
int spinningBarrelCount = spinningBarrelSprites.Count;
|
||||||
|
|
||||||
|
for (int i = 0; i < spinningBarrelCount; i++)
|
||||||
|
{
|
||||||
|
// this block is messy since I was debugging it with a bunch of values, should be cleaned up / optimized if prototype is accepted
|
||||||
|
Sprite spinningBarrel = spinningBarrelSprites[i];
|
||||||
|
float barrelCirclePosition = (MaxCircle * i / spinningBarrelCount + currentBarrelSpin) % MaxCircle;
|
||||||
|
|
||||||
|
float newDepth = spinningBarrel.Depth + (barrelCirclePosition > HalfCircle ? -0.001f : 0.001f);
|
||||||
|
|
||||||
|
float barrelColorPosition = (barrelCirclePosition + QuarterCircle) % MaxCircle;
|
||||||
|
float colorOffset = Math.Abs(barrelColorPosition - HalfCircle) / HalfCircle;
|
||||||
|
Color newColorModifier = Color.Lerp(Color.Black, Color.Gray, colorOffset);
|
||||||
|
|
||||||
|
float barrelHalfCirclePosition = Math.Abs(barrelCirclePosition - HalfCircle);
|
||||||
|
float barrelPositionModifier = MathUtils.SmoothStep(barrelHalfCirclePosition / HalfCircle);
|
||||||
|
float newPositionOffset = barrelPositionModifier * SpinningBarrelDistance;
|
||||||
|
|
||||||
|
spinningBarrel.Draw(spriteBatch,
|
||||||
|
drawPos - MathUtils.RotatePoint(new Vector2(newPositionOffset, 0f) * item.Scale, rotation + MathHelper.PiOver2),
|
||||||
|
Color.Lerp(item.SpriteColor, newColorModifier, 0.8f),
|
||||||
|
rotation + MathHelper.PiOver2, item.Scale,
|
||||||
|
SpriteEffects.None, newDepth);
|
||||||
|
}
|
||||||
|
|
||||||
if (!editing || GUI.DisableHUD || !item.IsSelected) { return; }
|
if (!editing || GUI.DisableHUD || !item.IsSelected) { return; }
|
||||||
|
|
||||||
const float widgetRadius = 60.0f;
|
const float widgetRadius = 60.0f;
|
||||||
@@ -552,14 +660,20 @@ namespace Barotrauma.Items.Components
|
|||||||
new VisualSlot(new Rectangle(invSlotPos + new Point((i % slotsPerRow) * (slotSize.X + spacing.X), (int)Math.Floor(i / (float)slotsPerRow) * (slotSize.Y + spacing.Y)), slotSize)),
|
new VisualSlot(new Rectangle(invSlotPos + new Point((i % slotsPerRow) * (slotSize.X + spacing.X), (int)Math.Floor(i / (float)slotsPerRow) * (slotSize.Y + spacing.Y)), slotSize)),
|
||||||
availableAmmo[i], -1, true);
|
availableAmmo[i], -1, true);
|
||||||
}
|
}
|
||||||
|
Rectangle rect = new Rectangle(invSlotPos.X, invSlotPos.Y, totalWidth, slotSize.Y);
|
||||||
|
float inflate = MathHelper.Lerp(3, 8, (float)Math.Abs(Math.Sin(flashTimer * 5)));
|
||||||
|
rect.Inflate(inflate, inflate);
|
||||||
|
Color color = GUI.Style.Red * Math.Max(0.5f, (float)Math.Sin(flashTimer * 12));
|
||||||
if (flashNoAmmo)
|
if (flashNoAmmo)
|
||||||
{
|
{
|
||||||
Rectangle rect = new Rectangle(invSlotPos.X, invSlotPos.Y, totalWidth, slotSize.Y);
|
|
||||||
float inflate = MathHelper.Lerp(3, 8, (float)Math.Abs(1 * Math.Sin(flashTimer * 5)));
|
|
||||||
rect.Inflate(inflate, inflate);
|
|
||||||
Color color = GUI.Style.Red * MathHelper.Max(0.5f, (float)Math.Sin(flashTimer * 12));
|
|
||||||
GUI.DrawRectangle(spriteBatch, rect, color, thickness: 3);
|
GUI.DrawRectangle(spriteBatch, rect, color, thickness: 3);
|
||||||
}
|
}
|
||||||
|
else if (flashLoaderBroken)
|
||||||
|
{
|
||||||
|
GUI.DrawRectangle(spriteBatch, rect, color, thickness: 3);
|
||||||
|
GUI.BrokenIcon.Draw(spriteBatch, rect.Center.ToVector2(), color, scale: rect.Height / GUI.BrokenIcon.size.Y);
|
||||||
|
GUIComponent.DrawToolTip(spriteBatch, TextManager.Get("turretloaderbroken"), new Rectangle(invSlotPos.X + totalWidth + GUI.IntScale(10), invSlotPos.Y + slotSize.Y / 2 - GUI.IntScale(9), 0, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float zoom = cam == null ? 1.0f : (float)Math.Sqrt(cam.Zoom);
|
float zoom = cam == null ? 1.0f : (float)Math.Sqrt(cam.Zoom);
|
||||||
|
|||||||
@@ -320,6 +320,11 @@ namespace Barotrauma
|
|||||||
toolTip += $"‖color:{conditionColorStr}‖ ({(int)item.ConditionPercentage} %)‖color:end‖";
|
toolTip += $"‖color:{conditionColorStr}‖ ({(int)item.ConditionPercentage} %)‖color:end‖";
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(description)) { toolTip += '\n' + description; }
|
if (!string.IsNullOrEmpty(description)) { toolTip += '\n' + description; }
|
||||||
|
if (item.prefab.ContentPackage != GameMain.VanillaContent && item.prefab.ContentPackage != null)
|
||||||
|
{
|
||||||
|
colorStr = XMLExtensions.ColorToString(Color.MediumPurple);
|
||||||
|
toolTip += $"\n‖color:{colorStr}‖{item.prefab.ContentPackage.Name}‖color:end‖";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (itemsInSlot.Count() > 1)
|
if (itemsInSlot.Count() > 1)
|
||||||
{
|
{
|
||||||
@@ -1575,7 +1580,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
sprite.Draw(spriteBatch, itemPos, spriteColor, rotation, scale);
|
sprite.Draw(spriteBatch, itemPos, spriteColor, rotation, scale);
|
||||||
|
|
||||||
if (!item.AllowStealing && CharacterInventory.LimbSlotIcons.ContainsKey(InvSlotType.LeftHand))
|
if ((!item.AllowStealing || (inventory != null && inventory.slots[slotIndex].Items.Any(it => !it.AllowStealing))) && CharacterInventory.LimbSlotIcons.ContainsKey(InvSlotType.LeftHand))
|
||||||
{
|
{
|
||||||
var stealIcon = CharacterInventory.LimbSlotIcons[InvSlotType.LeftHand];
|
var stealIcon = CharacterInventory.LimbSlotIcons[InvSlotType.LeftHand];
|
||||||
Vector2 iconSize = new Vector2(25 * GUI.Scale);
|
Vector2 iconSize = new Vector2(25 * GUI.Scale);
|
||||||
|
|||||||
@@ -22,6 +22,19 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private readonly List<ItemComponent> activeHUDs = new List<ItemComponent>();
|
private readonly List<ItemComponent> activeHUDs = new List<ItemComponent>();
|
||||||
|
|
||||||
|
public GUIComponentStyle IconStyle { get; private set; } = null;
|
||||||
|
partial void AssignCampaignInteractionTypeProjSpecific(CampaignMode.InteractionType interactionType)
|
||||||
|
{
|
||||||
|
if (interactionType == CampaignMode.InteractionType.None)
|
||||||
|
{
|
||||||
|
IconStyle = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IconStyle = GUI.Style.GetComponentStyle($"CampaignInteractionIcon.{interactionType}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<ItemComponent> ActiveHUDs => activeHUDs;
|
public IEnumerable<ItemComponent> ActiveHUDs => activeHUDs;
|
||||||
|
|
||||||
public float LastImpactSoundTime;
|
public float LastImpactSoundTime;
|
||||||
@@ -252,7 +265,8 @@ namespace Barotrauma
|
|||||||
else if (!ShowItems) { return; }
|
else if (!ShowItems) { return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
Color color = IsHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? GUI.Style.Orange : GetSpriteColor();
|
Color color = IsIncludedInSelection && editing ? GUI.Style.Blue : IsHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? GUI.Style.Orange * Math.Max(GetSpriteColor().A / (float) byte.MaxValue, 0.1f) : GetSpriteColor();
|
||||||
|
|
||||||
//if (IsSelected && editing) color = Color.Lerp(color, Color.Gold, 0.5f);
|
//if (IsSelected && editing) color = Color.Lerp(color, Color.Gold, 0.5f);
|
||||||
|
|
||||||
bool isWiringMode = editing && SubEditorScreen.TransparentWiringMode && SubEditorScreen.IsWiringMode() && !isWire && parentInventory == null;
|
bool isWiringMode = editing && SubEditorScreen.TransparentWiringMode && SubEditorScreen.IsWiringMode() && !isWire && parentInventory == null;
|
||||||
@@ -305,24 +319,27 @@ namespace Barotrauma
|
|||||||
if (prefab.ResizeHorizontal || prefab.ResizeVertical)
|
if (prefab.ResizeHorizontal || prefab.ResizeVertical)
|
||||||
{
|
{
|
||||||
Vector2 size = new Vector2(rect.Width, rect.Height);
|
Vector2 size = new Vector2(rect.Width, rect.Height);
|
||||||
activeSprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + drawOffset,
|
if (color.A > 0)
|
||||||
size, color: color,
|
|
||||||
textureScale: Vector2.One * Scale,
|
|
||||||
depth: depth);
|
|
||||||
fadeInBrokenSprite?.Sprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + fadeInBrokenSprite.Offset.ToVector2() * Scale, size, color: color * fadeInBrokenSpriteAlpha,
|
|
||||||
textureScale: Vector2.One * Scale,
|
|
||||||
depth: depth - 0.000001f);
|
|
||||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
|
||||||
{
|
{
|
||||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
activeSprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + drawOffset,
|
||||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
|
|
||||||
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
|
||||||
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
|
||||||
decorativeSprite.Sprite.DrawTiled(spriteBatch,
|
|
||||||
new Vector2(DrawPosition.X + offset.X - rect.Width / 2, -(DrawPosition.Y + offset.Y + rect.Height / 2)),
|
|
||||||
size, color: color,
|
size, color: color,
|
||||||
textureScale: Vector2.One * Scale,
|
textureScale: Vector2.One * Scale,
|
||||||
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth), 0.999f));
|
depth: depth);
|
||||||
|
fadeInBrokenSprite?.Sprite.DrawTiled(spriteBatch, new Vector2(DrawPosition.X - rect.Width / 2, -(DrawPosition.Y + rect.Height / 2)) + fadeInBrokenSprite.Offset.ToVector2() * Scale, size, color: color * fadeInBrokenSpriteAlpha,
|
||||||
|
textureScale: Vector2.One * Scale,
|
||||||
|
depth: depth - 0.000001f);
|
||||||
|
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||||
|
{
|
||||||
|
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||||
|
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier, -rotationRad) * Scale;
|
||||||
|
if (flippedX && Prefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
||||||
|
if (flippedY && Prefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
||||||
|
decorativeSprite.Sprite.DrawTiled(spriteBatch,
|
||||||
|
new Vector2(DrawPosition.X + offset.X - rect.Width / 2, -(DrawPosition.Y + offset.Y + rect.Height / 2)),
|
||||||
|
size, color: color,
|
||||||
|
textureScale: Vector2.One * Scale,
|
||||||
|
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth), 0.999f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -336,8 +353,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
origin.Y = activeSprite.SourceRect.Height - origin.Y;
|
origin.Y = activeSprite.SourceRect.Height - origin.Y;
|
||||||
}
|
}
|
||||||
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, rotationRad, Scale, activeSprite.effects, depth);
|
if (color.A > 0)
|
||||||
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, depth - 0.000001f);
|
{
|
||||||
|
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, rotationRad, Scale, activeSprite.effects, depth);
|
||||||
|
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, depth - 0.000001f);
|
||||||
|
}
|
||||||
if (Infector != null && (Infector.ParentBallastFlora.HasBrokenThrough || BallastFloraBehavior.AlwaysShowBallastFloraSprite))
|
if (Infector != null && (Infector.ParentBallastFlora.HasBrokenThrough || BallastFloraBehavior.AlwaysShowBallastFloraSprite))
|
||||||
{
|
{
|
||||||
Prefab.InfectedSprite?.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, Prefab.InfectedSprite.Origin, rotationRad, Scale, activeSprite.effects, depth - 0.001f);
|
Prefab.InfectedSprite?.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, Prefab.InfectedSprite.Origin, rotationRad, Scale, activeSprite.effects, depth - 0.001f);
|
||||||
@@ -365,7 +385,7 @@ namespace Barotrauma
|
|||||||
float depthStep = 0.000001f;
|
float depthStep = 0.000001f;
|
||||||
if (holdable.Picker.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand) == this)
|
if (holdable.Picker.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand) == this)
|
||||||
{
|
{
|
||||||
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.RightHand);
|
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.RightArm);
|
||||||
if (holdLimb?.ActiveSprite != null)
|
if (holdLimb?.ActiveSprite != null)
|
||||||
{
|
{
|
||||||
depth = holdLimb.ActiveSprite.Depth + holdable.Picker.AnimController.GetDepthOffset() + depthStep * 2;
|
depth = holdLimb.ActiveSprite.Depth + holdable.Picker.AnimController.GetDepthOffset() + depthStep * 2;
|
||||||
@@ -377,7 +397,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (holdable.Picker.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand) == this)
|
else if (holdable.Picker.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand) == this)
|
||||||
{
|
{
|
||||||
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.LeftHand);
|
Limb holdLimb = holdable.Picker.AnimController.GetLimb(LimbType.LeftArm);
|
||||||
if (holdLimb?.ActiveSprite != null)
|
if (holdLimb?.ActiveSprite != null)
|
||||||
{
|
{
|
||||||
depth = holdLimb.ActiveSprite.Depth + holdable.Picker.AnimController.GetDepthOffset() - depthStep * 2;
|
depth = holdLimb.ActiveSprite.Depth + holdable.Picker.AnimController.GetDepthOffset() - depthStep * 2;
|
||||||
@@ -675,7 +695,11 @@ namespace Barotrauma
|
|||||||
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
|
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
{
|
{
|
||||||
FlipX(relativeToSub: false);
|
foreach (MapEntity me in SelectedList)
|
||||||
|
{
|
||||||
|
me.FlipX(relativeToSub: false);
|
||||||
|
}
|
||||||
|
if (!SelectedList.Contains(this)) { FlipX(relativeToSub: false); }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -684,7 +708,11 @@ namespace Barotrauma
|
|||||||
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
|
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
{
|
{
|
||||||
FlipY(relativeToSub: false);
|
foreach (MapEntity me in SelectedList)
|
||||||
|
{
|
||||||
|
me.FlipY(relativeToSub: false);
|
||||||
|
}
|
||||||
|
if (!SelectedList.Contains(this)) { FlipY(relativeToSub: false); }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -702,7 +730,12 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
{
|
{
|
||||||
Reset();
|
foreach (MapEntity me in SelectedList)
|
||||||
|
{
|
||||||
|
(me as Item)?.Reset();
|
||||||
|
(me as Structure)?.Reset();
|
||||||
|
}
|
||||||
|
if (!SelectedList.Contains(this)) { Reset(); }
|
||||||
CreateEditingHUD();
|
CreateEditingHUD();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -734,7 +767,11 @@ namespace Barotrauma
|
|||||||
if (inGame)
|
if (inGame)
|
||||||
{
|
{
|
||||||
if (!ic.AllowInGameEditing) { continue; }
|
if (!ic.AllowInGameEditing) { continue; }
|
||||||
if (SerializableProperty.GetProperties<InGameEditable>(ic).Count == 0) { continue; }
|
if (SerializableProperty.GetProperties<InGameEditable>(ic).Count == 0 &&
|
||||||
|
!SerializableProperty.GetProperties<ConditionallyEditable>(ic).Any(p => p.GetAttribute<ConditionallyEditable>().IsEditable()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1093,8 +1130,9 @@ namespace Barotrauma
|
|||||||
nameText += $" ({idName})";
|
nameText += $" ({idName})";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
texts.Add(new ColoredText(nameText, GUI.Style.TextColor, false, false));
|
texts.Add(new ColoredText(nameText, GUI.Style.TextColor, false, false));
|
||||||
|
|
||||||
|
bool noComponentText = true;
|
||||||
foreach (ItemComponent ic in components)
|
foreach (ItemComponent ic in components)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(ic.DisplayMsg)) { continue; }
|
if (string.IsNullOrEmpty(ic.DisplayMsg)) { continue; }
|
||||||
@@ -1114,8 +1152,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
texts.Add(new ColoredText(ic.DisplayMsg, color, false, false));
|
texts.Add(new ColoredText(ic.DisplayMsg, color, false, false));
|
||||||
|
noComponentText = false;
|
||||||
}
|
}
|
||||||
if ((PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift)) && CrewManager.DoesItemHaveContextualOrders(this))
|
if (noComponentText && CampaignInteractionType != CampaignMode.InteractionType.None)
|
||||||
|
{
|
||||||
|
texts.Add(new ColoredText(TextManager.GetWithVariable($"CampaignInteraction.{CampaignInteractionType}", "[key]", GameMain.Config.KeyBindText(InputType.Use)), Color.Cyan, false, false));
|
||||||
|
}
|
||||||
|
if (PlayerInput.IsShiftDown() && CrewManager.DoesItemHaveContextualOrders(this))
|
||||||
{
|
{
|
||||||
texts.Add(new ColoredText(TextManager.ParseInputTypes(TextManager.Get("itemmsgcontextualorders")), Color.Cyan, false, false));
|
texts.Add(new ColoredText(TextManager.ParseInputTypes(TextManager.Get("itemmsgcontextualorders")), Color.Cyan, false, false));
|
||||||
}
|
}
|
||||||
@@ -1213,6 +1256,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
SetActiveSprite();
|
SetActiveSprite();
|
||||||
break;
|
break;
|
||||||
|
case NetEntityEvent.Type.AssignCampaignInteraction:
|
||||||
|
CampaignInteractionType = (CampaignMode.InteractionType)msg.ReadByte();
|
||||||
|
break;
|
||||||
case NetEntityEvent.Type.ApplyStatusEffect:
|
case NetEntityEvent.Type.ApplyStatusEffect:
|
||||||
{
|
{
|
||||||
ActionType actionType = (ActionType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ActionType)).Length - 1);
|
ActionType actionType = (ActionType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ActionType)).Length - 1);
|
||||||
@@ -1327,6 +1373,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
isActive = true;
|
isActive = true;
|
||||||
|
|
||||||
|
if (positionBuffer.Count > 0)
|
||||||
|
{
|
||||||
|
transformDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
body.CorrectPosition(positionBuffer, out Vector2 newPosition, out Vector2 newVelocity, out float newRotation, out float newAngularVelocity);
|
body.CorrectPosition(positionBuffer, out Vector2 newPosition, out Vector2 newVelocity, out float newRotation, out float newAngularVelocity);
|
||||||
body.LinearVelocity = newVelocity;
|
body.LinearVelocity = newVelocity;
|
||||||
body.AngularVelocity = newAngularVelocity;
|
body.AngularVelocity = newAngularVelocity;
|
||||||
|
|||||||
@@ -63,9 +63,12 @@ namespace Barotrauma
|
|||||||
public Dictionary<int, List<DecorativeSprite>> DecorativeSpriteGroups = new Dictionary<int, List<DecorativeSprite>>();
|
public Dictionary<int, List<DecorativeSprite>> DecorativeSpriteGroups = new Dictionary<int, List<DecorativeSprite>>();
|
||||||
public Sprite InventoryIcon;
|
public Sprite InventoryIcon;
|
||||||
public Sprite MinimapIcon;
|
public Sprite MinimapIcon;
|
||||||
|
public Sprite UpgradePreviewSprite;
|
||||||
public Sprite InfectedSprite;
|
public Sprite InfectedSprite;
|
||||||
public Sprite DamagedInfectedSprite;
|
public Sprite DamagedInfectedSprite;
|
||||||
|
|
||||||
|
public float UpgradePreviewScale = 1.0f;
|
||||||
|
|
||||||
//only used to display correct color in the sub editor, item instances have their own property that can be edited on a per-item basis
|
//only used to display correct color in the sub editor, item instances have their own property that can be edited on a per-item basis
|
||||||
[Serialize("1.0,1.0,1.0,1.0", false)]
|
[Serialize("1.0,1.0,1.0,1.0", false)]
|
||||||
public Color InventoryIconColor
|
public Color InventoryIconColor
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
get { return selectedList.Contains(this); }
|
get { return selectedList.Contains(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsIncludedInSelection { get; set; }
|
||||||
|
|
||||||
public virtual bool IsVisible(Rectangle worldView)
|
public virtual bool IsVisible(Rectangle worldView)
|
||||||
{
|
{
|
||||||
@@ -360,6 +362,11 @@ namespace Barotrauma
|
|||||||
selectionSize.X = position.X - selectionPos.X;
|
selectionSize.X = position.X - selectionPos.X;
|
||||||
selectionSize.Y = selectionPos.Y - position.Y;
|
selectionSize.Y = selectionPos.Y - position.Y;
|
||||||
|
|
||||||
|
foreach (MapEntity entity in mapEntityList)
|
||||||
|
{
|
||||||
|
entity.IsIncludedInSelection = false;
|
||||||
|
}
|
||||||
|
|
||||||
List<MapEntity> newSelection = new List<MapEntity>();// FindSelectedEntities(selectionPos, selectionSize);
|
List<MapEntity> newSelection = new List<MapEntity>();// FindSelectedEntities(selectionPos, selectionSize);
|
||||||
if (Math.Abs(selectionSize.X) > Submarine.GridSize.X || Math.Abs(selectionSize.Y) > Submarine.GridSize.Y)
|
if (Math.Abs(selectionSize.X) > Submarine.GridSize.X || Math.Abs(selectionSize.Y) > Submarine.GridSize.Y)
|
||||||
{
|
{
|
||||||
@@ -372,10 +379,15 @@ namespace Barotrauma
|
|||||||
if (SelectionGroups.TryGetValue(highLightedEntity, out List<MapEntity> group))
|
if (SelectionGroups.TryGetValue(highLightedEntity, out List<MapEntity> group))
|
||||||
{
|
{
|
||||||
newSelection.AddRange(group);
|
newSelection.AddRange(group);
|
||||||
|
foreach (MapEntity entity in group)
|
||||||
|
{
|
||||||
|
entity.IsIncludedInSelection = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newSelection.Add(highLightedEntity);
|
newSelection.Add(highLightedEntity);
|
||||||
|
highLightedEntity.IsIncludedInSelection = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -443,6 +455,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
selectionPos = Vector2.Zero;
|
selectionPos = Vector2.Zero;
|
||||||
selectionSize = Vector2.Zero;
|
selectionSize = Vector2.Zero;
|
||||||
|
foreach (MapEntity entity in mapEntityList)
|
||||||
|
{
|
||||||
|
entity.IsIncludedInSelection = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//default, not doing anything specific yet
|
//default, not doing anything specific yet
|
||||||
@@ -800,7 +816,32 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (selectionPos != null && selectionPos != Vector2.Zero)
|
if (selectionPos != null && selectionPos != Vector2.Zero)
|
||||||
{
|
{
|
||||||
GUI.DrawRectangle(spriteBatch, new Vector2(selectionPos.X, -selectionPos.Y), selectionSize, Color.DarkRed, false, 0, 2f / GameScreen.Selected.Cam.Zoom);
|
var (sizeX, sizeY) = selectionSize;
|
||||||
|
var (posX, posY) = selectionPos;
|
||||||
|
|
||||||
|
posY = -posY;
|
||||||
|
|
||||||
|
Vector2[] corners =
|
||||||
|
{
|
||||||
|
new Vector2(posX, posY),
|
||||||
|
new Vector2(posX + sizeX, posY),
|
||||||
|
new Vector2(posX + sizeX, posY + sizeY),
|
||||||
|
new Vector2(posX, posY + sizeY)
|
||||||
|
};
|
||||||
|
|
||||||
|
Color selectionColor = GUI.Style.Blue;
|
||||||
|
float thickness = Math.Max(2f, 2f / Screen.Selected.Cam.Zoom);
|
||||||
|
|
||||||
|
GUI.DrawFilledRectangle(spriteBatch, corners[0], selectionSize, selectionColor * 0.1f);
|
||||||
|
|
||||||
|
Vector2 offset = new Vector2(0f, thickness / 2f);
|
||||||
|
|
||||||
|
if (sizeY < 0) { offset.Y = -offset.Y; }
|
||||||
|
|
||||||
|
spriteBatch.DrawLine(corners[0], corners[1], selectionColor, thickness);
|
||||||
|
spriteBatch.DrawLine(corners[1] - offset, corners[2] + offset, selectionColor, thickness);
|
||||||
|
spriteBatch.DrawLine(corners[2], corners[3], selectionColor, thickness);
|
||||||
|
spriteBatch.DrawLine(corners[3] + offset, corners[0] - offset, selectionColor, thickness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1141,7 +1182,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (!e.SelectableInEditor) continue;
|
if (!e.SelectableInEditor) continue;
|
||||||
|
|
||||||
if (Submarine.RectsOverlap(selectionRect, e.rect)) foundEntities.Add(e);
|
if (Submarine.RectsOverlap(selectionRect, e.rect))
|
||||||
|
{
|
||||||
|
foundEntities.Add(e);
|
||||||
|
e.IsIncludedInSelection = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return foundEntities;
|
return foundEntities;
|
||||||
|
|||||||
@@ -127,7 +127,11 @@ namespace Barotrauma
|
|||||||
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
|
ToolTip = TextManager.Get("MirrorEntityXToolTip"),
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
{
|
{
|
||||||
FlipX(relativeToSub: false);
|
foreach (MapEntity me in SelectedList)
|
||||||
|
{
|
||||||
|
me.FlipX(relativeToSub: false);
|
||||||
|
}
|
||||||
|
if (!SelectedList.Contains(this)) { FlipX(relativeToSub: false); }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -136,7 +140,11 @@ namespace Barotrauma
|
|||||||
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
|
ToolTip = TextManager.Get("MirrorEntityYToolTip"),
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
{
|
{
|
||||||
FlipY(relativeToSub: false);
|
foreach (MapEntity me in SelectedList)
|
||||||
|
{
|
||||||
|
me.FlipY(relativeToSub: false);
|
||||||
|
}
|
||||||
|
if (!SelectedList.Contains(this)) { FlipY(relativeToSub: false); }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -153,7 +161,12 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
OnClicked = (button, data) =>
|
OnClicked = (button, data) =>
|
||||||
{
|
{
|
||||||
Reset();
|
foreach (MapEntity me in SelectedList)
|
||||||
|
{
|
||||||
|
(me as Item)?.Reset();
|
||||||
|
(me as Structure)?.Reset();
|
||||||
|
}
|
||||||
|
if (!SelectedList.Contains(this)) { Reset(); }
|
||||||
CreateEditingHUD();
|
CreateEditingHUD();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -247,7 +260,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (HiddenInGame) { return; }
|
else if (HiddenInGame) { return; }
|
||||||
|
|
||||||
Color color = IsHighlighted ? GUI.Style.Orange : spriteColor;
|
Color color = IsIncludedInSelection && editing ? GUI.Style.Blue : IsHighlighted ? GUI.Style.Orange * Math.Max(spriteColor.A / (float) byte.MaxValue, 0.1f) : spriteColor;
|
||||||
|
|
||||||
if (IsSelected && editing)
|
if (IsSelected && editing)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -114,7 +114,6 @@ namespace Barotrauma
|
|||||||
if (realWorldDimensions != Vector2.Zero)
|
if (realWorldDimensions != Vector2.Zero)
|
||||||
{
|
{
|
||||||
string dimensionsStr = TextManager.GetWithVariables("DimensionsFormat", new string[2] { "[width]", "[height]" }, new string[2] { ((int)realWorldDimensions.X).ToString(), ((int)realWorldDimensions.Y).ToString() });
|
string dimensionsStr = TextManager.GetWithVariables("DimensionsFormat", new string[2] { "[width]", "[height]" }, new string[2] { ((int)realWorldDimensions.X).ToString(), ((int)realWorldDimensions.Y).ToString() });
|
||||||
|
|
||||||
var dimensionsText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
var dimensionsText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||||
TextManager.Get("Dimensions"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
TextManager.Get("Dimensions"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||||
{ CanBeFocused = false };
|
{ CanBeFocused = false };
|
||||||
@@ -124,6 +123,15 @@ namespace Barotrauma
|
|||||||
dimensionsText.RectTransform.MinSize = new Point(0, dimensionsText.Children.First().Rect.Height);
|
dimensionsText.RectTransform.MinSize = new Point(0, dimensionsText.Children.First().Rect.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string cargoCapacityStr = CargoCapacity < 0 ? TextManager.Get("unknown") : TextManager.GetWithVariables("cargocapacityformat", new string[1] { "[cratecount]" }, new string[1] {CargoCapacity.ToString() });
|
||||||
|
var cargoCapacityText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||||
|
TextManager.Get("cargocapacity"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||||
|
{ CanBeFocused = false };
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), cargoCapacityText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||||
|
cargoCapacityStr, textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||||
|
{ CanBeFocused = false };
|
||||||
|
cargoCapacityText.RectTransform.MinSize = new Point(0, cargoCapacityText.Children.First().Rect.Height);
|
||||||
|
|
||||||
if (RecommendedCrewSizeMax > 0)
|
if (RecommendedCrewSizeMax > 0)
|
||||||
{
|
{
|
||||||
var crewSizeText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
var crewSizeText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ namespace Barotrauma
|
|||||||
if (IsHighlighted || IsHighlighted) { clr = Color.Lerp(clr, Color.White, 0.8f); }
|
if (IsHighlighted || IsHighlighted) { clr = Color.Lerp(clr, Color.White, 0.8f); }
|
||||||
|
|
||||||
int iconSize = spawnType == SpawnType.Path ? WaypointSize : SpawnPointSize;
|
int iconSize = spawnType == SpawnType.Path ? WaypointSize : SpawnPointSize;
|
||||||
if (ConnectedDoor != null || Ladders != null || Stairs != null || SpawnType != SpawnType.Path) { iconSize = (int)(iconSize * 1.5f); }
|
if (ConnectedDoor != null || Ladders != null || Stairs != null || SpawnType != SpawnType.Path)
|
||||||
|
{
|
||||||
|
iconSize = (int)(iconSize * 1.5f);
|
||||||
|
}
|
||||||
|
|
||||||
if (IsSelected || IsHighlighted)
|
if (IsSelected || IsHighlighted)
|
||||||
{
|
{
|
||||||
@@ -98,10 +101,32 @@ namespace Barotrauma
|
|||||||
GUI.Style.Green * 0.5f, width: 1);
|
GUI.Style.Green * 0.5f, width: 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var color = Color.WhiteSmoke;
|
||||||
|
if (spawnType == SpawnType.Path)
|
||||||
|
{
|
||||||
|
if (linkedTo.Count < 2)
|
||||||
|
{
|
||||||
|
if (linkedTo.Count == 0)
|
||||||
|
{
|
||||||
|
color = Color.Red;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CurrentHull == null)
|
||||||
|
{
|
||||||
|
color = Ladders == null ? Color.Red : Color.Yellow;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
color = Color.Yellow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
GUI.SmallFont.DrawString(spriteBatch,
|
GUI.SmallFont.DrawString(spriteBatch,
|
||||||
ID.ToString(),
|
ID.ToString(),
|
||||||
new Vector2(DrawPosition.X - 10, -DrawPosition.Y - 30),
|
new Vector2(DrawPosition.X - 10, -DrawPosition.Y - 30),
|
||||||
Color.WhiteSmoke);
|
color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsMouseOn(Vector2 position)
|
public override bool IsMouseOn(Vector2 position)
|
||||||
|
|||||||
@@ -53,100 +53,32 @@ namespace Barotrauma.Networking
|
|||||||
case ChatMessageType.Default:
|
case ChatMessageType.Default:
|
||||||
break;
|
break;
|
||||||
case ChatMessageType.Order:
|
case ChatMessageType.Order:
|
||||||
int orderIndex = msg.ReadByte();
|
var orderMessageInfo = OrderChatMessage.ReadOrder(msg);
|
||||||
UInt16 targetCharacterID = msg.ReadUInt16();
|
if (orderMessageInfo.OrderIndex < 0 || orderMessageInfo.OrderIndex >= Order.PrefabList.Count)
|
||||||
Character targetCharacter = Entity.FindEntityByID(targetCharacterID) as Character;
|
|
||||||
Entity targetEntity = Entity.FindEntityByID(msg.ReadUInt16());
|
|
||||||
|
|
||||||
Order orderPrefab = null;
|
|
||||||
int? optionIndex = null;
|
|
||||||
string orderOption = null;
|
|
||||||
|
|
||||||
// The option of a Dismiss order is written differently so we know what order we target
|
|
||||||
// now that the game supports multiple current orders simultaneously
|
|
||||||
if (orderIndex >= 0 && orderIndex < Order.PrefabList.Count)
|
|
||||||
{
|
|
||||||
orderPrefab = Order.PrefabList[orderIndex];
|
|
||||||
if (orderPrefab.Identifier != "dismissed")
|
|
||||||
{
|
|
||||||
optionIndex = msg.ReadByte();
|
|
||||||
}
|
|
||||||
// Does the dismiss order have a specified target?
|
|
||||||
else if (msg.ReadBoolean())
|
|
||||||
{
|
|
||||||
int identifierCount = msg.ReadByte();
|
|
||||||
if (identifierCount > 0)
|
|
||||||
{
|
|
||||||
int dismissedOrderIndex = msg.ReadByte();
|
|
||||||
Order dismissedOrderPrefab = null;
|
|
||||||
if (dismissedOrderIndex >= 0 && dismissedOrderIndex < Order.PrefabList.Count)
|
|
||||||
{
|
|
||||||
dismissedOrderPrefab = Order.PrefabList[dismissedOrderIndex];
|
|
||||||
orderOption = dismissedOrderPrefab.Identifier;
|
|
||||||
}
|
|
||||||
if (identifierCount > 1)
|
|
||||||
{
|
|
||||||
int dismissedOrderOptionIndex = msg.ReadByte();
|
|
||||||
if (dismissedOrderPrefab != null)
|
|
||||||
{
|
|
||||||
var options = dismissedOrderPrefab.Options;
|
|
||||||
if (options != null && dismissedOrderOptionIndex >= 0 && dismissedOrderOptionIndex < options.Length)
|
|
||||||
{
|
|
||||||
orderOption += $".{options[dismissedOrderOptionIndex]}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
optionIndex = msg.ReadByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
int orderPriority = msg.ReadByte();
|
|
||||||
OrderTarget orderTargetPosition = null;
|
|
||||||
Order.OrderTargetType orderTargetType = (Order.OrderTargetType)msg.ReadByte();
|
|
||||||
int wallSectionIndex = 0;
|
|
||||||
if (msg.ReadBoolean())
|
|
||||||
{
|
|
||||||
var x = msg.ReadSingle();
|
|
||||||
var y = msg.ReadSingle();
|
|
||||||
var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull;
|
|
||||||
orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, creatingFromExistingData: true);
|
|
||||||
}
|
|
||||||
else if(orderTargetType == Order.OrderTargetType.WallSection)
|
|
||||||
{
|
|
||||||
wallSectionIndex = msg.ReadByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
|
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Invalid order message - order index out of bounds.");
|
DebugConsole.ThrowError("Invalid order message - order index out of bounds.");
|
||||||
if (NetIdUtils.IdMoreRecent(id, LastID)) { LastID = id; }
|
if (NetIdUtils.IdMoreRecent(id, LastID)) { LastID = id; }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
var orderPrefab = orderMessageInfo.OrderPrefab ?? Order.PrefabList[orderMessageInfo.OrderIndex];
|
||||||
{
|
string orderOption = orderMessageInfo.OrderOption;
|
||||||
orderPrefab ??= Order.PrefabList[orderIndex];
|
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);
|
||||||
orderOption ??= optionIndex.HasValue && optionIndex >= 0 && optionIndex < orderPrefab.Options.Length ? orderPrefab.Options[optionIndex.Value] : "";
|
|
||||||
txt = orderPrefab.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption);
|
|
||||||
|
|
||||||
if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
|
if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
|
||||||
{
|
{
|
||||||
Order order = null;
|
Order order = null;
|
||||||
switch (orderTargetType)
|
switch (orderMessageInfo.TargetType)
|
||||||
{
|
{
|
||||||
case Order.OrderTargetType.Entity:
|
case Order.OrderTargetType.Entity:
|
||||||
order = new Order(orderPrefab, targetEntity, orderPrefab.GetTargetItemComponent(targetEntity as Item), orderGiver: senderCharacter);
|
order = new Order(orderPrefab, orderMessageInfo.TargetEntity, orderPrefab.GetTargetItemComponent(orderMessageInfo.TargetEntity as Item), orderGiver: senderCharacter);
|
||||||
break;
|
break;
|
||||||
case Order.OrderTargetType.Position:
|
case Order.OrderTargetType.Position:
|
||||||
order = new Order(orderPrefab, orderTargetPosition, orderGiver: senderCharacter);
|
order = new Order(orderPrefab, orderMessageInfo.TargetPosition, orderGiver: senderCharacter);
|
||||||
break;
|
break;
|
||||||
case Order.OrderTargetType.WallSection:
|
case Order.OrderTargetType.WallSection:
|
||||||
order = new Order(orderPrefab, targetEntity as Structure, wallSectionIndex, orderGiver: senderCharacter);
|
order = new Order(orderPrefab, orderMessageInfo.TargetEntity as Structure, orderMessageInfo.WallSectionIndex, orderGiver: senderCharacter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,9 +89,9 @@ namespace Barotrauma.Networking
|
|||||||
var fadeOutTime = !orderPrefab.IsIgnoreOrder ? (float?)orderPrefab.FadeOutTime : null;
|
var fadeOutTime = !orderPrefab.IsIgnoreOrder ? (float?)orderPrefab.FadeOutTime : null;
|
||||||
GameMain.GameSession?.CrewManager?.AddOrder(order, fadeOutTime);
|
GameMain.GameSession?.CrewManager?.AddOrder(order, fadeOutTime);
|
||||||
}
|
}
|
||||||
else if (targetCharacter != null)
|
else if (orderMessageInfo.TargetCharacter != null)
|
||||||
{
|
{
|
||||||
targetCharacter.SetOrder(order, orderOption, orderPriority, senderCharacter);
|
orderMessageInfo.TargetCharacter.SetOrder(order, orderOption, orderMessageInfo.Priority, senderCharacter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,7 +99,7 @@ namespace Barotrauma.Networking
|
|||||||
if (NetIdUtils.IdMoreRecent(id, LastID))
|
if (NetIdUtils.IdMoreRecent(id, LastID))
|
||||||
{
|
{
|
||||||
GameMain.Client.AddChatMessage(
|
GameMain.Client.AddChatMessage(
|
||||||
new OrderChatMessage(orderPrefab, orderOption, orderPriority, txt, orderTargetPosition ?? targetEntity as ISpatialEntity, targetCharacter, senderCharacter));
|
new OrderChatMessage(orderPrefab, orderOption, orderMessageInfo.Priority, txt, orderMessageInfo.TargetPosition ?? orderMessageInfo.TargetEntity as ISpatialEntity, orderMessageInfo.TargetCharacter, senderCharacter));
|
||||||
LastID = id;
|
LastID = id;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1046,6 +1046,11 @@ namespace Barotrauma.Networking
|
|||||||
mission.ClientReadInitial(inc);
|
mission.ClientReadInitial(inc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inc.ReadBoolean())
|
||||||
|
{
|
||||||
|
CrewManager.ClientReadActiveOrders(inc);
|
||||||
|
}
|
||||||
|
|
||||||
roundInitStatus = RoundInitStatus.Started;
|
roundInitStatus = RoundInitStatus.Started;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1609,6 +1614,9 @@ namespace Barotrauma.Networking
|
|||||||
DateTime? timeOut = null;
|
DateTime? timeOut = null;
|
||||||
DateTime requestFinalizeTime = DateTime.Now;
|
DateTime requestFinalizeTime = DateTime.Now;
|
||||||
TimeSpan requestFinalizeInterval = new TimeSpan(0, 0, 2);
|
TimeSpan requestFinalizeInterval = new TimeSpan(0, 0, 2);
|
||||||
|
IWriteMessage msg = new WriteOnlyMessage();
|
||||||
|
msg.Write((byte)ClientPacketHeader.REQUEST_STARTGAMEFINALIZE);
|
||||||
|
clientPeer.Send(msg, DeliveryMethod.Unreliable);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -1618,7 +1626,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
if (DateTime.Now > requestFinalizeTime)
|
if (DateTime.Now > requestFinalizeTime)
|
||||||
{
|
{
|
||||||
IWriteMessage msg = new WriteOnlyMessage();
|
msg = new WriteOnlyMessage();
|
||||||
msg.Write((byte)ClientPacketHeader.REQUEST_STARTGAMEFINALIZE);
|
msg.Write((byte)ClientPacketHeader.REQUEST_STARTGAMEFINALIZE);
|
||||||
clientPeer.Send(msg, DeliveryMethod.Unreliable);
|
clientPeer.Send(msg, DeliveryMethod.Unreliable);
|
||||||
requestFinalizeTime = DateTime.Now + requestFinalizeInterval;
|
requestFinalizeTime = DateTime.Now + requestFinalizeInterval;
|
||||||
@@ -1648,12 +1656,11 @@ namespace Barotrauma.Networking
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize)
|
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize) { break; }
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
clientPeer.Update((float)Timing.Step);
|
clientPeer.Update((float)Timing.Step);
|
||||||
|
|
||||||
|
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize) { break; }
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -3289,16 +3296,24 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
string respawnText = string.Empty;
|
string respawnText = string.Empty;
|
||||||
Color textColor = Color.White;
|
Color textColor = Color.White;
|
||||||
bool canChooseRespawn =
|
bool canChooseRespawn =
|
||||||
GameMain.GameSession.GameMode is CampaignMode &&
|
GameMain.GameSession.GameMode is CampaignMode &&
|
||||||
Character.Controlled == null &&
|
Character.Controlled == null &&
|
||||||
Level.Loaded?.Type != LevelData.LevelType.Outpost &&
|
Level.Loaded?.Type != LevelData.LevelType.Outpost &&
|
||||||
(characterInfo == null || HasSpawned);
|
(characterInfo == null || HasSpawned);
|
||||||
if (respawnManager.CurrentState == RespawnManager.State.Waiting &&
|
if (respawnManager.CurrentState == RespawnManager.State.Waiting)
|
||||||
respawnManager.RespawnCountdownStarted)
|
|
||||||
{
|
{
|
||||||
float timeLeft = (float)(respawnManager.RespawnTime - DateTime.Now).TotalSeconds;
|
if (respawnManager.RespawnCountdownStarted)
|
||||||
respawnText = TextManager.GetWithVariable(respawnManager.UsingShuttle ? "RespawnShuttleDispatching" : "RespawningIn", "[time]", ToolBox.SecondsToReadableTime(timeLeft));
|
{
|
||||||
|
float timeLeft = (float)(respawnManager.RespawnTime - DateTime.Now).TotalSeconds;
|
||||||
|
respawnText = TextManager.GetWithVariable(respawnManager.UsingShuttle ? "RespawnShuttleDispatching" : "RespawningIn", "[time]", ToolBox.SecondsToReadableTime(timeLeft));
|
||||||
|
}
|
||||||
|
else if (respawnManager.PendingRespawnCount > 0)
|
||||||
|
{
|
||||||
|
respawnText = TextManager.GetWithVariables("RespawnWaitingForMoreDeadPlayers",
|
||||||
|
new string[] { "[deadplayers]", "[requireddeadplayers]" },
|
||||||
|
new string[] { respawnManager.PendingRespawnCount.ToString(), respawnManager.RequiredRespawnCount.ToString() });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (respawnManager.CurrentState == RespawnManager.State.Transporting &&
|
else if (respawnManager.CurrentState == RespawnManager.State.Transporting &&
|
||||||
respawnManager.ReturnCountdownStarted)
|
respawnManager.ReturnCountdownStarted)
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using Lidgren.Network;
|
using System;
|
||||||
using Microsoft.Xna.Framework;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Barotrauma.Networking
|
namespace Barotrauma.Networking
|
||||||
{
|
{
|
||||||
@@ -8,6 +6,17 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
private DateTime lastShuttleLeavingWarningTime;
|
private DateTime lastShuttleLeavingWarningTime;
|
||||||
|
|
||||||
|
public int PendingRespawnCount
|
||||||
|
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int RequiredRespawnCount
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
partial void UpdateTransportingProjSpecific(float deltaTime)
|
partial void UpdateTransportingProjSpecific(float deltaTime)
|
||||||
{
|
{
|
||||||
if (GameMain.Client?.Character == null || GameMain.Client.Character.Submarine != RespawnShuttle) { return; }
|
if (GameMain.Client?.Character == null || GameMain.Client.Character.Submarine != RespawnShuttle) { return; }
|
||||||
@@ -41,6 +50,8 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case State.Waiting:
|
case State.Waiting:
|
||||||
|
PendingRespawnCount = msg.ReadUInt16();
|
||||||
|
RequiredRespawnCount = msg.ReadUInt16();
|
||||||
RespawnCountdownStarted = msg.ReadBoolean();
|
RespawnCountdownStarted = msg.ReadBoolean();
|
||||||
ResetShuttle();
|
ResetShuttle();
|
||||||
float newRespawnTime = msg.ReadSingle();
|
float newRespawnTime = msg.ReadSingle();
|
||||||
|
|||||||
@@ -745,6 +745,10 @@ namespace Barotrauma.Networking
|
|||||||
TextManager.Get("ServerSettingsAllowRewiring"));
|
TextManager.Get("ServerSettingsAllowRewiring"));
|
||||||
GetPropertyData("AllowRewiring").AssignGUIComponent(allowRewiring);
|
GetPropertyData("AllowRewiring").AssignGUIComponent(allowRewiring);
|
||||||
|
|
||||||
|
var allowWifiChatter = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
|
||||||
|
TextManager.Get("ServerSettingsAllowWifiChat"));
|
||||||
|
GetPropertyData("AllowLinkingWifiToChat").AssignGUIComponent(allowWifiChatter);
|
||||||
|
|
||||||
var allowDisguises = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
|
var allowDisguises = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
|
||||||
TextManager.Get("ServerSettingsAllowDisguises"));
|
TextManager.Get("ServerSettingsAllowDisguises"));
|
||||||
GetPropertyData("AllowDisguises").AssignGUIComponent(allowDisguises);
|
GetPropertyData("AllowDisguises").AssignGUIComponent(allowDisguises);
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace Barotrauma.Particles
|
|||||||
public Vector4 ColorMultiplier;
|
public Vector4 ColorMultiplier;
|
||||||
|
|
||||||
public bool DrawOnTop { get; private set; }
|
public bool DrawOnTop { get; private set; }
|
||||||
|
|
||||||
public ParticlePrefab.DrawTargetType DrawTarget
|
public ParticlePrefab.DrawTargetType DrawTarget
|
||||||
{
|
{
|
||||||
get { return prefab.DrawTarget; }
|
get { return prefab.DrawTarget; }
|
||||||
@@ -103,8 +103,7 @@ namespace Barotrauma.Particles
|
|||||||
{
|
{
|
||||||
return debugName;
|
return debugName;
|
||||||
}
|
}
|
||||||
|
public void Init(ParticlePrefab prefab, Vector2 position, Vector2 speed, float rotation, Hull hullGuess = null, bool drawOnTop = false, float collisionIgnoreTimer = 0f, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||||
public void Init(ParticlePrefab prefab, Vector2 position, Vector2 speed, float rotation, Hull hullGuess = null, bool drawOnTop = false, float collisionIgnoreTimer = 0f)
|
|
||||||
{
|
{
|
||||||
this.prefab = prefab;
|
this.prefab = prefab;
|
||||||
debugName = $"Particle ({prefab.Name})";
|
debugName = $"Particle ({prefab.Name})";
|
||||||
@@ -118,6 +117,16 @@ namespace Barotrauma.Particles
|
|||||||
|
|
||||||
currentHull = Hull.FindHull(position, hullGuess);
|
currentHull = Hull.FindHull(position, hullGuess);
|
||||||
|
|
||||||
|
size = prefab.StartSizeMin + (prefab.StartSizeMax - prefab.StartSizeMin) * Rand.Range(0.0f, 1.0f);
|
||||||
|
|
||||||
|
if (tracerPoints != null)
|
||||||
|
{
|
||||||
|
size = new Vector2(Vector2.Distance(tracerPoints.Item1, tracerPoints.Item2), size.Y);
|
||||||
|
position = (tracerPoints.Item1 + tracerPoints.Item2) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
sizeChange = prefab.SizeChangeMin + (prefab.SizeChangeMax - prefab.SizeChangeMin) * Rand.Range(0.0f, 1.0f);
|
||||||
|
|
||||||
this.position = position;
|
this.position = position;
|
||||||
prevPosition = position;
|
prevPosition = position;
|
||||||
|
|
||||||
@@ -138,10 +147,6 @@ namespace Barotrauma.Particles
|
|||||||
totalLifeTime = prefab.LifeTime;
|
totalLifeTime = prefab.LifeTime;
|
||||||
lifeTime = prefab.LifeTime;
|
lifeTime = prefab.LifeTime;
|
||||||
startDelay = Rand.Range(prefab.StartDelayMin, prefab.StartDelayMax);
|
startDelay = Rand.Range(prefab.StartDelayMin, prefab.StartDelayMax);
|
||||||
|
|
||||||
size = prefab.StartSizeMin + (prefab.StartSizeMax - prefab.StartSizeMin) * Rand.Range(0.0f, 1.0f);
|
|
||||||
|
|
||||||
sizeChange = prefab.SizeChangeMin + (prefab.SizeChangeMax - prefab.SizeChangeMin) * Rand.Range(0.0f, 1.0f);
|
|
||||||
|
|
||||||
color = prefab.StartColor;
|
color = prefab.StartColor;
|
||||||
changeColor = prefab.StartColor != prefab.EndColor;
|
changeColor = prefab.StartColor != prefab.EndColor;
|
||||||
|
|||||||
@@ -1,10 +1,21 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Particles
|
namespace Barotrauma.Particles
|
||||||
{
|
{
|
||||||
|
class ParticleEmitterProperties : ISerializableEntity
|
||||||
|
{
|
||||||
|
public string Name => nameof(ParticleEmitterProperties);
|
||||||
|
public Dictionary<string, SerializableProperty> SerializableProperties { get; }
|
||||||
|
|
||||||
|
public ParticleEmitterProperties(XElement element)
|
||||||
|
{
|
||||||
|
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ParticleEmitter
|
class ParticleEmitter
|
||||||
{
|
{
|
||||||
private float emitTimer;
|
private float emitTimer;
|
||||||
@@ -23,7 +34,7 @@ namespace Barotrauma.Particles
|
|||||||
Prefab = prefab;
|
Prefab = prefab;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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)
|
||||||
{
|
{
|
||||||
emitTimer += deltaTime * amountMultiplier;
|
emitTimer += deltaTime * amountMultiplier;
|
||||||
burstEmitTimer -= deltaTime;
|
burstEmitTimer -= deltaTime;
|
||||||
@@ -33,7 +44,7 @@ namespace Barotrauma.Particles
|
|||||||
float emitInterval = 1.0f / Prefab.ParticlesPerSecond;
|
float emitInterval = 1.0f / Prefab.ParticlesPerSecond;
|
||||||
while (emitTimer > emitInterval)
|
while (emitTimer > emitInterval)
|
||||||
{
|
{
|
||||||
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle);
|
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, tracerPoints: tracerPoints);
|
||||||
emitTimer -= emitInterval;
|
emitTimer -= emitInterval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,11 +54,11 @@ namespace Barotrauma.Particles
|
|||||||
burstEmitTimer = Prefab.EmitInterval;
|
burstEmitTimer = Prefab.EmitInterval;
|
||||||
for (int i = 0; i < Prefab.ParticleAmount * amountMultiplier; i++)
|
for (int i = 0; i < Prefab.ParticleAmount * amountMultiplier; i++)
|
||||||
{
|
{
|
||||||
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle);
|
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, tracerPoints: tracerPoints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null)
|
private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||||
{
|
{
|
||||||
angle += Rand.Range(Prefab.AngleMin, Prefab.AngleMax);
|
angle += Rand.Range(Prefab.AngleMin, Prefab.AngleMax);
|
||||||
|
|
||||||
@@ -55,11 +66,12 @@ namespace Barotrauma.Particles
|
|||||||
Vector2 velocity = dir * Rand.Range(Prefab.VelocityMin, Prefab.VelocityMax) * velocityMultiplier;
|
Vector2 velocity = dir * Rand.Range(Prefab.VelocityMin, Prefab.VelocityMax) * velocityMultiplier;
|
||||||
position += dir * Rand.Range(Prefab.DistanceMin, Prefab.DistanceMax);
|
position += dir * Rand.Range(Prefab.DistanceMin, Prefab.DistanceMax);
|
||||||
|
|
||||||
var particle = GameMain.ParticleManager.CreateParticle(overrideParticle ?? Prefab.ParticlePrefab, position, velocity, particleRotation, hullGuess, Prefab.DrawOnTop);
|
var particle = GameMain.ParticleManager.CreateParticle(overrideParticle ?? Prefab.ParticlePrefab, position, velocity, particleRotation, hullGuess, Prefab.DrawOnTop, tracerPoints: tracerPoints);
|
||||||
|
|
||||||
if (particle != null)
|
if (particle != null)
|
||||||
{
|
{
|
||||||
particle.Size *= Rand.Range(Prefab.ScaleMin, Prefab.ScaleMax) * sizeMultiplier;
|
particle.Size *= Rand.Range(Prefab.ScaleMin, Prefab.ScaleMax) * sizeMultiplier;
|
||||||
|
particle.Size *= Prefab.ScaleMultiplier;
|
||||||
particle.HighQualityCollisionDetection = Prefab.HighQualityCollisionDetection;
|
particle.HighQualityCollisionDetection = Prefab.HighQualityCollisionDetection;
|
||||||
if (colorMultiplier.HasValue)
|
if (colorMultiplier.HasValue)
|
||||||
{
|
{
|
||||||
@@ -135,6 +147,7 @@ namespace Barotrauma.Particles
|
|||||||
public readonly float VelocityMin, VelocityMax;
|
public readonly float VelocityMin, VelocityMax;
|
||||||
|
|
||||||
public readonly float ScaleMin, ScaleMax;
|
public readonly float ScaleMin, ScaleMax;
|
||||||
|
public readonly Vector2 ScaleMultiplier;
|
||||||
|
|
||||||
public readonly float EmitInterval;
|
public readonly float EmitInterval;
|
||||||
public readonly int ParticleAmount;
|
public readonly int ParticleAmount;
|
||||||
@@ -179,6 +192,7 @@ namespace Barotrauma.Particles
|
|||||||
ScaleMin = element.GetAttributeFloat("scalemin", 1.0f);
|
ScaleMin = element.GetAttributeFloat("scalemin", 1.0f);
|
||||||
ScaleMax = Math.Max(ScaleMin, element.GetAttributeFloat("scalemax", 1.0f));
|
ScaleMax = Math.Max(ScaleMin, element.GetAttributeFloat("scalemax", 1.0f));
|
||||||
}
|
}
|
||||||
|
ScaleMultiplier = element.GetAttributeVector2("scalemultiplier", Vector2.One);
|
||||||
|
|
||||||
if (element.Attribute("distance") == null)
|
if (element.Attribute("distance") == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -114,13 +114,12 @@ namespace Barotrauma.Particles
|
|||||||
{
|
{
|
||||||
Prefabs.RemoveByFile(configFile);
|
Prefabs.RemoveByFile(configFile);
|
||||||
}
|
}
|
||||||
|
public Particle CreateParticle(string prefabName, Vector2 position, float angle, float speed, Hull hullGuess = null, float collisionIgnoreTimer = 0f, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||||
public Particle CreateParticle(string prefabName, Vector2 position, float angle, float speed, Hull hullGuess = null, float collisionIgnoreTimer = 0f)
|
|
||||||
{
|
{
|
||||||
return CreateParticle(prefabName, position, new Vector2((float)Math.Cos(angle), (float)-Math.Sin(angle)) * speed, angle, hullGuess, collisionIgnoreTimer);
|
return CreateParticle(prefabName, position, new Vector2((float)Math.Cos(angle), (float)-Math.Sin(angle)) * speed, angle, hullGuess, collisionIgnoreTimer, tracerPoints: tracerPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Particle CreateParticle(string prefabName, Vector2 position, Vector2 velocity, float rotation = 0.0f, Hull hullGuess = null, float collisionIgnoreTimer = 0f)
|
public Particle CreateParticle(string prefabName, Vector2 position, Vector2 velocity, float rotation = 0.0f, Hull hullGuess = null, float collisionIgnoreTimer = 0f, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||||
{
|
{
|
||||||
ParticlePrefab prefab = FindPrefab(prefabName);
|
ParticlePrefab prefab = FindPrefab(prefabName);
|
||||||
|
|
||||||
@@ -129,27 +128,30 @@ namespace Barotrauma.Particles
|
|||||||
DebugConsole.ThrowError("Particle prefab \"" + prefabName + "\" not found!");
|
DebugConsole.ThrowError("Particle prefab \"" + prefabName + "\" not found!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return CreateParticle(prefab, position, velocity, rotation, hullGuess, collisionIgnoreTimer: collisionIgnoreTimer, tracerPoints:tracerPoints);
|
||||||
return CreateParticle(prefab, position, velocity, rotation, hullGuess, collisionIgnoreTimer: collisionIgnoreTimer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Particle CreateParticle(ParticlePrefab prefab, Vector2 position, Vector2 velocity, float rotation = 0.0f, Hull hullGuess = null, bool drawOnTop = false, float collisionIgnoreTimer = 0f)
|
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; }
|
if (particleCount >= MaxParticles || prefab == null || prefab.Sprites.Count == 0) { return null; }
|
||||||
|
|
||||||
|
// this should be optimized for tracers after prototyping
|
||||||
|
if (tracerPoints == null)
|
||||||
|
{
|
||||||
|
Vector2 particleEndPos = prefab.CalculateEndPosition(position, velocity);
|
||||||
|
|
||||||
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));
|
||||||
|
|
||||||
Vector2 minPos = new Vector2(Math.Min(position.X, particleEndPos.X), Math.Min(position.Y, particleEndPos.Y));
|
Rectangle expandedViewRect = MathUtils.ExpandRect(cam.WorldView, MaxOutOfViewDist);
|
||||||
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; }
|
||||||
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();
|
if (particles[particleCount] == null) particles[particleCount] = new Particle();
|
||||||
|
|
||||||
particles[particleCount].Init(prefab, position, velocity, rotation, hullGuess, drawOnTop, collisionIgnoreTimer);
|
particles[particleCount].Init(prefab, position, velocity, rotation, hullGuess, drawOnTop, collisionIgnoreTimer, tracerPoints: tracerPoints);
|
||||||
|
|
||||||
particleCount++;
|
particleCount++;
|
||||||
|
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static bool KeyHit(Keys button)
|
public static bool KeyHit(Keys button)
|
||||||
{
|
{
|
||||||
return (AllowInput && oldKeyboardState.IsKeyDown(button) && keyboardState.IsKeyUp(button));
|
return AllowInput && oldKeyboardState.IsKeyUp(button) && keyboardState.IsKeyDown(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool InventoryKeyHit(int index)
|
public static bool InventoryKeyHit(int index)
|
||||||
@@ -454,7 +454,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static bool KeyDown(Keys button)
|
public static bool KeyDown(Keys button)
|
||||||
{
|
{
|
||||||
return (AllowInput && keyboardState.IsKeyDown(button));
|
return AllowInput && keyboardState.IsKeyDown(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool KeyUp(Keys button)
|
public static bool KeyUp(Keys button)
|
||||||
|
|||||||
@@ -505,7 +505,7 @@ namespace Barotrauma
|
|||||||
missionName.CalculateHeightFromText();
|
missionName.CalculateHeightFromText();
|
||||||
}
|
}
|
||||||
|
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission.GetMissionRewardText(), wrap: true, parseRichText: true);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission.GetMissionRewardText(Submarine.MainSub), wrap: true, parseRichText: true);
|
||||||
|
|
||||||
string reputationText = mission.GetReputationRewardText(mission.Locations[0]);
|
string reputationText = mission.GetReputationRewardText(mission.Locations[0]);
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), reputationText, wrap: true, parseRichText: true);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), reputationText, wrap: true, parseRichText: true);
|
||||||
@@ -517,8 +517,9 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
var textBlock = child as GUITextBlock;
|
var textBlock = child as GUITextBlock;
|
||||||
textBlock.Color = textBlock.SelectedColor = textBlock.HoverColor = Color.Transparent;
|
textBlock.Color = textBlock.SelectedColor = textBlock.HoverColor = Color.Transparent;
|
||||||
textBlock.HoverTextColor = textBlock.TextColor;
|
textBlock.SelectedTextColor = textBlock.TextColor;
|
||||||
textBlock.TextColor *= 0.5f;
|
textBlock.TextColor *= 0.5f;
|
||||||
|
textBlock.HoverTextColor = textBlock.TextColor;
|
||||||
}
|
}
|
||||||
missionPanel.OnAddedToGUIUpdateList = (c) =>
|
missionPanel.OnAddedToGUIUpdateList = (c) =>
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -4731,7 +4731,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
rotation: 0,
|
rotation: 0,
|
||||||
origin: orig,
|
origin: orig,
|
||||||
sourceRectangle: wearable.InheritSourceRect ? limb.ActiveSprite.SourceRect : wearable.Sprite.SourceRect,
|
sourceRectangle: wearable.InheritSourceRect ? limb.ActiveSprite.SourceRect : wearable.Sprite.SourceRect,
|
||||||
scale: (wearable.InheritTextureScale ? 1 : 1 / RagdollParams.TextureScale) * spriteSheetZoom,
|
scale: (wearable.InheritTextureScale ? 1 : wearable.Scale / RagdollParams.TextureScale) * spriteSheetZoom,
|
||||||
effects: SpriteEffects.None,
|
effects: SpriteEffects.None,
|
||||||
color: Color.White,
|
color: Color.White,
|
||||||
layerDepth: 0);
|
layerDepth: 0);
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), mainElement.RectTransform, Anchor.CenterLeft), TextManager.Get("ContentPackage"));
|
new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), mainElement.RectTransform, Anchor.CenterLeft), TextManager.Get("ContentPackage"));
|
||||||
var rightContainer = new GUIFrame(new RectTransform(new Vector2(0.7f, 1), mainElement.RectTransform, Anchor.CenterRight), style: null);
|
var rightContainer = new GUIFrame(new RectTransform(new Vector2(0.7f, 1), mainElement.RectTransform, Anchor.CenterRight), style: null);
|
||||||
contentPackageDropDown = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.5f), rightContainer.RectTransform, Anchor.TopRight));
|
contentPackageDropDown = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.5f), rightContainer.RectTransform, Anchor.TopRight));
|
||||||
foreach (ContentPackage cp in ContentPackage.AllPackages)
|
foreach (ContentPackage cp in GameMain.Config.AllEnabledPackages)
|
||||||
{
|
{
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
if (cp == GameMain.VanillaContent) { continue; }
|
if (cp == GameMain.VanillaContent) { continue; }
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
class EditorScreen : Screen
|
||||||
|
{
|
||||||
|
public static Color BackgroundColor = GameSettings.SubEditorBackgroundColor;
|
||||||
|
|
||||||
|
public void CreateBackgroundColorPicker()
|
||||||
|
{
|
||||||
|
var msgBox = new GUIMessageBox(TextManager.Get("CharacterEditor.EditBackgroundColor"), "", new[] { TextManager.Get("Reset"), TextManager.Get("OK")}, new Vector2(0.2f, 0.175f), minSize: new Point(300, 175));
|
||||||
|
|
||||||
|
var rgbLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.25f), msgBox.Content.RectTransform), isHorizontal: true);
|
||||||
|
|
||||||
|
// Generate R,G,B labels and parent elements
|
||||||
|
var layoutParents = new GUILayoutGroup[3];
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
var colorContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.33f, 1), rgbLayout.RectTransform), isHorizontal: true) { Stretch = true };
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1), colorContainer.RectTransform, Anchor.CenterLeft) { MinSize = new Point(15, 0) }, GUI.colorComponentLabels[i], font: GUI.SmallFont, textAlignment: Alignment.Center);
|
||||||
|
layoutParents[i] = colorContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach number inputs to our generated parent elements
|
||||||
|
var rInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1f), layoutParents[0].RectTransform), GUINumberInput.NumberType.Int) { IntValue = BackgroundColor.R };
|
||||||
|
var gInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1f), layoutParents[1].RectTransform), GUINumberInput.NumberType.Int) { IntValue = BackgroundColor.G };
|
||||||
|
var bInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1f), layoutParents[2].RectTransform), GUINumberInput.NumberType.Int) { IntValue = BackgroundColor.B };
|
||||||
|
|
||||||
|
rInput.MinValueInt = gInput.MinValueInt = bInput.MinValueInt = 0;
|
||||||
|
rInput.MaxValueInt = gInput.MaxValueInt = bInput.MaxValueInt = 255;
|
||||||
|
|
||||||
|
rInput.OnValueChanged = gInput.OnValueChanged = bInput.OnValueChanged = delegate
|
||||||
|
{
|
||||||
|
var color = new Color(rInput.IntValue, gInput.IntValue, bInput.IntValue);
|
||||||
|
BackgroundColor = color;
|
||||||
|
GameSettings.SubEditorBackgroundColor = color;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reset button
|
||||||
|
msgBox.Buttons[0].OnClicked = (button, o) =>
|
||||||
|
{
|
||||||
|
rInput.IntValue = 13;
|
||||||
|
gInput.IntValue = 37;
|
||||||
|
bInput.IntValue = 69;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ok button
|
||||||
|
msgBox.Buttons[1].OnClicked = (button, o) =>
|
||||||
|
{
|
||||||
|
msgBox.Close();
|
||||||
|
GameMain.Config.SaveNewPlayerConfig();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -227,7 +227,7 @@ namespace Barotrauma
|
|||||||
public static GUIMessageBox AskForConfirmation(string header, string body, Func<bool> onConfirm)
|
public static GUIMessageBox AskForConfirmation(string header, string body, Func<bool> onConfirm)
|
||||||
{
|
{
|
||||||
string[] buttons = { TextManager.Get("Ok"), TextManager.Get("Cancel") };
|
string[] buttons = { TextManager.Get("Ok"), TextManager.Get("Cancel") };
|
||||||
GUIMessageBox msgBox = new GUIMessageBox(header, body, buttons, new Vector2(0.2f, 0.175f), minSize: new Point(300, 175));
|
GUIMessageBox msgBox = new GUIMessageBox(header, body, buttons);
|
||||||
|
|
||||||
// Cancel button
|
// Cancel button
|
||||||
msgBox.Buttons[1].OnClicked = delegate
|
msgBox.Buttons[1].OnClicked = delegate
|
||||||
|
|||||||
@@ -364,13 +364,15 @@ namespace Barotrauma
|
|||||||
Quad.Render();
|
Quad.Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
float grainStrength = Character.Controlled?.GrainStrength ?? 0;
|
if (Character.Controlled is { } character)
|
||||||
if (grainStrength > 0)
|
|
||||||
{
|
{
|
||||||
|
float grainStrength = character.GrainStrength;
|
||||||
Rectangle screenRect = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
Rectangle screenRect = new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: GrainEffect);
|
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: GrainEffect);
|
||||||
GUI.DrawRectangle(spriteBatch, screenRect, Color.White * grainStrength, isFilled: true);
|
GUI.DrawRectangle(spriteBatch, screenRect, Color.White, isFilled: true);
|
||||||
GrainEffect.Parameters["seed"].SetValue(Rand.Range(0f, 1f, Rand.RandSync.Unsynced));
|
GrainEffect.Parameters["seed"].SetValue(Rand.Range(0f, 1f, Rand.RandSync.Unsynced));
|
||||||
|
GrainEffect.Parameters["intensity"].SetValue(grainStrength);
|
||||||
|
GrainEffect.Parameters["grainColor"].SetValue(character.GrainColor.ToVector4());
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -929,7 +929,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
QuitCampaignButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.3f), campaignContent.RectTransform),
|
QuitCampaignButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.3f), campaignContent.RectTransform),
|
||||||
TextManager.Get("pausemenusavequit"), textAlignment: Alignment.Center)
|
TextManager.Get("quitbutton"), textAlignment: Alignment.Center)
|
||||||
{
|
{
|
||||||
OnClicked = (_, __) =>
|
OnClicked = (_, __) =>
|
||||||
{
|
{
|
||||||
@@ -1322,7 +1322,7 @@ namespace Barotrauma
|
|||||||
roundControlsHolder.Children.ForEach(c => c.IgnoreLayoutGroups = !c.Visible);
|
roundControlsHolder.Children.ForEach(c => c.IgnoreLayoutGroups = !c.Visible);
|
||||||
roundControlsHolder.Recalculate();
|
roundControlsHolder.Recalculate();
|
||||||
|
|
||||||
ReadyToStartBox.Parent.Visible = !GameMain.Client.GameStarted && SelectedMode != GameModePreset.MultiPlayerCampaign;
|
ReadyToStartBox.Parent.Visible = !GameMain.Client.GameStarted;
|
||||||
|
|
||||||
RefreshGameModeContent();
|
RefreshGameModeContent();
|
||||||
}
|
}
|
||||||
@@ -3269,7 +3269,7 @@ namespace Barotrauma
|
|||||||
CampaignFrame.Visible = CampaignSetupFrame.Visible = false;
|
CampaignFrame.Visible = CampaignSetupFrame.Visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadyToStartBox.Parent.Visible = !GameMain.Client.GameStarted && SelectedMode != GameModePreset.MultiPlayerCampaign;
|
ReadyToStartBox.Parent.Visible = !GameMain.Client.GameStarted;
|
||||||
|
|
||||||
StartButton.Visible =
|
StartButton.Visible =
|
||||||
GameMain.Client.HasPermission(ClientPermissions.ManageRound) &&
|
GameMain.Client.HasPermission(ClientPermissions.ManageRound) &&
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Barotrauma.Extensions;
|
using Barotrauma.Extensions;
|
||||||
|
using FarseerPhysics;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
@@ -15,7 +16,7 @@ using Barotrauma.IO;
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class ParticleEditorScreen : Screen
|
class ParticleEditorScreen : EditorScreen
|
||||||
{
|
{
|
||||||
class Emitter : ISerializableEntity
|
class Emitter : ISerializableEntity
|
||||||
{
|
{
|
||||||
@@ -23,22 +24,22 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public float BurstTimer;
|
public float BurstTimer;
|
||||||
|
|
||||||
[Editable(), Serialize("0.0,360.0", false)]
|
[Editable, Serialize("0.0,360.0", false)]
|
||||||
public Vector2 AngleRange { get; private set; }
|
public Vector2 AngleRange { get; private set; }
|
||||||
|
|
||||||
[Editable(), Serialize("0.0,0.0", false)]
|
[Editable, Serialize("0.0,0.0", false)]
|
||||||
public Vector2 VelocityRange { get; private set; }
|
public Vector2 VelocityRange { get; private set; }
|
||||||
|
|
||||||
[Editable(), Serialize("1.0,1.0", false)]
|
[Editable, Serialize("1.0,1.0", false)]
|
||||||
public Vector2 ScaleRange { get; private set; }
|
public Vector2 ScaleRange { get; private set; }
|
||||||
|
|
||||||
[Editable(), Serialize(0, false)]
|
[Editable, Serialize(0, false)]
|
||||||
public int ParticleBurstAmount { get; private set; }
|
public int ParticleBurstAmount { get; private set; }
|
||||||
|
|
||||||
[Editable(), Serialize(1.0f, false)]
|
[Editable, Serialize(1.0f, false)]
|
||||||
public float ParticleBurstInterval { get; private set; }
|
public float ParticleBurstInterval { get; private set; }
|
||||||
|
|
||||||
[Editable(), Serialize(1.0f, false)]
|
[Editable, Serialize(1.0f, false)]
|
||||||
public float ParticlesPerSecond { get; private set; }
|
public float ParticlesPerSecond { get; private set; }
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
@@ -77,19 +78,24 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private readonly Camera cam;
|
private readonly Camera cam;
|
||||||
|
|
||||||
public override Camera Cam
|
public override Camera Cam => cam;
|
||||||
{
|
|
||||||
get
|
private const string sizeRefFilePath = "Content/size_reference.png";
|
||||||
{
|
private readonly Texture2D sizeReference;
|
||||||
return cam;
|
private Vector2 sizeRefPosition = Vector2.Zero;
|
||||||
}
|
private readonly Vector2 sizeRefOrigin;
|
||||||
}
|
private bool sizeRefEnabled;
|
||||||
|
|
||||||
public ParticleEditorScreen()
|
public ParticleEditorScreen()
|
||||||
{
|
{
|
||||||
cam = new Camera();
|
cam = new Camera();
|
||||||
GameMain.Instance.ResolutionChanged += CreateUI;
|
GameMain.Instance.ResolutionChanged += CreateUI;
|
||||||
CreateUI();
|
CreateUI();
|
||||||
|
if (File.Exists(sizeRefFilePath))
|
||||||
|
{
|
||||||
|
sizeReference = TextureLoader.FromFile(sizeRefFilePath, compress: false);
|
||||||
|
sizeRefOrigin = new Vector2(sizeReference.Width / 2f, sizeReference.Height / 2f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateUI()
|
private void CreateUI()
|
||||||
@@ -314,7 +320,17 @@ namespace Barotrauma
|
|||||||
public override void Update(double deltaTime)
|
public override void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
cam.MoveCamera((float)deltaTime, allowMove: true, allowZoom: GUI.MouseOn == null);
|
cam.MoveCamera((float)deltaTime, allowMove: true, allowZoom: GUI.MouseOn == null);
|
||||||
|
|
||||||
|
if (GUI.MouseOn is null && PlayerInput.PrimaryMouseButtonHeld())
|
||||||
|
{
|
||||||
|
sizeRefPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PlayerInput.SecondaryMouseButtonClicked())
|
||||||
|
{
|
||||||
|
CreateContextMenu();
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedPrefab != null)
|
if (selectedPrefab != null)
|
||||||
{
|
{
|
||||||
emitter.EmitTimer += (float)deltaTime;
|
emitter.EmitTimer += (float)deltaTime;
|
||||||
@@ -345,6 +361,15 @@ namespace Barotrauma
|
|||||||
GameMain.ParticleManager.Update((float)deltaTime);
|
GameMain.ParticleManager.Update((float)deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateContextMenu()
|
||||||
|
{
|
||||||
|
GUIContextMenu.CreateContextMenu
|
||||||
|
(
|
||||||
|
new ContextMenuOption("subeditor.editbackgroundcolor", true, CreateBackgroundColorPicker),
|
||||||
|
new ContextMenuOption("editor.togglereferencecharacter", true, delegate { sizeRefEnabled = !sizeRefEnabled; })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
cam.UpdateTransform();
|
cam.UpdateTransform();
|
||||||
@@ -357,7 +382,7 @@ namespace Barotrauma
|
|||||||
null, null, null, null,
|
null, null, null, null,
|
||||||
cam.Transform);
|
cam.Transform);
|
||||||
|
|
||||||
graphics.Clear(new Color(0.051f, 0.149f, 0.271f, 1.0f));
|
graphics.Clear(BackgroundColor);
|
||||||
|
|
||||||
GameMain.ParticleManager.Draw(spriteBatch, false, false, ParticleBlendState.AlphaBlend);
|
GameMain.ParticleManager.Draw(spriteBatch, false, false, ParticleBlendState.AlphaBlend);
|
||||||
GameMain.ParticleManager.Draw(spriteBatch, true, false, ParticleBlendState.AlphaBlend);
|
GameMain.ParticleManager.Draw(spriteBatch, true, false, ParticleBlendState.AlphaBlend);
|
||||||
@@ -374,6 +399,20 @@ namespace Barotrauma
|
|||||||
|
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
|
|
||||||
|
if (sizeRefEnabled && !(sizeReference is null))
|
||||||
|
{
|
||||||
|
spriteBatch.Begin(SpriteSortMode.Deferred,
|
||||||
|
BlendState.NonPremultiplied,
|
||||||
|
null, null, null, null,
|
||||||
|
cam.Transform);
|
||||||
|
|
||||||
|
Vector2 pos = sizeRefPosition;
|
||||||
|
pos.Y = -pos.Y;
|
||||||
|
spriteBatch.Draw(sizeReference, pos, null, Color.White, 0f, sizeRefOrigin, new Vector2(0.4f), SpriteEffects.None, 0f);
|
||||||
|
|
||||||
|
spriteBatch.End();
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
|
|
||||||
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
|
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ namespace Barotrauma
|
|||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void OnFileDropped(string filePath, string extension) { }
|
||||||
|
|
||||||
public virtual void Release()
|
public virtual void Release()
|
||||||
{
|
{
|
||||||
frame.RectTransform.Parent = null;
|
frame.RectTransform.Parent = null;
|
||||||
|
|||||||
@@ -363,7 +363,9 @@ namespace Barotrauma
|
|||||||
"VineSprite",
|
"VineSprite",
|
||||||
"LeafSprite",
|
"LeafSprite",
|
||||||
"FlowerSprite",
|
"FlowerSprite",
|
||||||
"DecorativeSprite"
|
"DecorativeSprite",
|
||||||
|
"BarrelSprite",
|
||||||
|
"RailSprite"
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (string spriteElementName in spriteElementNames)
|
foreach (string spriteElementName in spriteElementNames)
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ namespace Barotrauma
|
|||||||
//listbox that shows the files included in the item being created
|
//listbox that shows the files included in the item being created
|
||||||
private GUIListBox createItemFileList;
|
private GUIListBox createItemFileList;
|
||||||
|
|
||||||
|
private GUIImage previewIcon;
|
||||||
|
|
||||||
private System.IO.FileSystemWatcher createItemWatcher;
|
private System.IO.FileSystemWatcher createItemWatcher;
|
||||||
|
|
||||||
private readonly List<GUIButton> tabButtons = new List<GUIButton>();
|
private readonly List<GUIButton> tabButtons = new List<GUIButton>();
|
||||||
@@ -277,6 +279,24 @@ namespace Barotrauma
|
|||||||
SelectTab(Tab.Mods);
|
SelectTab(Tab.Mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnFileDropped(string filePath, string extension)
|
||||||
|
{
|
||||||
|
switch (extension)
|
||||||
|
{
|
||||||
|
case ".png": // workshop preview
|
||||||
|
case ".jpg":
|
||||||
|
case ".jpeg":
|
||||||
|
if (previewIcon == null || itemContentPackage == null) { break; }
|
||||||
|
|
||||||
|
OnPreviewImageSelected(previewIcon, filePath);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DebugConsole.ThrowError($"Could not drag and drop the file. \"{extension}\" is not a valid file extension! (expected .png, .jpg or .jpeg)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnItemInstalled(ulong itemId)
|
private void OnItemInstalled(ulong itemId)
|
||||||
{
|
{
|
||||||
RefreshSubscribedItems();
|
RefreshSubscribedItems();
|
||||||
@@ -1263,7 +1283,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), topLeftColumn.RectTransform), TextManager.Get("WorkshopItemPreviewImage"), font: GUI.SubHeadingFont);
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), topLeftColumn.RectTransform), TextManager.Get("WorkshopItemPreviewImage"), font: GUI.SubHeadingFont);
|
||||||
|
|
||||||
var previewIcon = new GUIImage(new RectTransform(new Vector2(1.0f, 0.7f), topLeftColumn.RectTransform), SteamManager.DefaultPreviewImage, scaleToFit: true);
|
previewIcon = new GUIImage(new RectTransform(new Vector2(1.0f, 0.7f), topLeftColumn.RectTransform), SteamManager.DefaultPreviewImage, scaleToFit: true);
|
||||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.2f), topLeftColumn.RectTransform), TextManager.Get("WorkshopItemBrowse"), style: "GUIButtonSmall")
|
new GUIButton(new RectTransform(new Vector2(1.0f, 0.2f), topLeftColumn.RectTransform), TextManager.Get("WorkshopItemBrowse"), style: "GUIButtonSmall")
|
||||||
{
|
{
|
||||||
OnClicked = (btn, userdata) =>
|
OnClicked = (btn, userdata) =>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ using Barotrauma.IO;
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class SubEditorScreen : Screen
|
class SubEditorScreen : EditorScreen
|
||||||
{
|
{
|
||||||
private static readonly string[] crewExperienceLevels =
|
private static readonly string[] crewExperienceLevels =
|
||||||
{
|
{
|
||||||
@@ -177,8 +177,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private Mode mode;
|
private Mode mode;
|
||||||
|
|
||||||
private Color backgroundColor = GameSettings.SubEditorBackgroundColor;
|
|
||||||
|
|
||||||
private Vector2 MeasurePositionStart = Vector2.Zero;
|
private Vector2 MeasurePositionStart = Vector2.Zero;
|
||||||
|
|
||||||
// Prevent the mode from changing
|
// Prevent the mode from changing
|
||||||
@@ -1007,6 +1005,12 @@ namespace Barotrauma
|
|||||||
string name = legacy ? TextManager.GetWithVariable("legacyitemformat", "[name]", ep.Name) : ep.Name;
|
string name = legacy ? TextManager.GetWithVariable("legacyitemformat", "[name]", ep.Name) : ep.Name;
|
||||||
frame.ToolTip = string.IsNullOrEmpty(ep.Description) ? name : name + '\n' + ep.Description;
|
frame.ToolTip = string.IsNullOrEmpty(ep.Description) ? name : name + '\n' + ep.Description;
|
||||||
|
|
||||||
|
if (ep.ContentPackage != GameMain.VanillaContent && ep.ContentPackage != null)
|
||||||
|
{
|
||||||
|
frame.Color = Color.Magenta;
|
||||||
|
string colorStr = XMLExtensions.ColorToString(Color.MediumPurple);
|
||||||
|
frame.ToolTip += $"\n‖color:{colorStr}‖{ep.ContentPackage?.Name}‖color:end‖";
|
||||||
|
}
|
||||||
if (ep.HideInMenus)
|
if (ep.HideInMenus)
|
||||||
{
|
{
|
||||||
frame.Color = Color.Red;
|
frame.Color = Color.Red;
|
||||||
@@ -1225,6 +1229,50 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnFileDropped(string filePath, string extension)
|
||||||
|
{
|
||||||
|
switch (extension)
|
||||||
|
{
|
||||||
|
case ".sub": // Submarine
|
||||||
|
SubmarineInfo info = new SubmarineInfo(filePath);
|
||||||
|
if (info.IsFileCorrupted)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"Could not drag and drop the file. File \"{filePath}\" is corrupted!");
|
||||||
|
info.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string body = TextManager.GetWithVariable("SubEditor.LoadConfirmBody", "[submarine]", info.Name);
|
||||||
|
GUI.AskForConfirmation(TextManager.Get("Load"), body, onConfirm: () => LoadSub(info), onDeny: () => info.Dispose());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ".xml": // Item Assembly
|
||||||
|
string text = File.ReadAllText(filePath);
|
||||||
|
// PlayerInput.MousePosition doesn't update while the window is not active so we need to use this method
|
||||||
|
Vector2 mousePos = Mouse.GetState().Position.ToVector2();
|
||||||
|
PasteAssembly(text, cam.ScreenToWorld(mousePos));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ".png": // submarine preview
|
||||||
|
case ".jpg":
|
||||||
|
case ".jpeg":
|
||||||
|
if (saveFrame == null) { break; }
|
||||||
|
|
||||||
|
Texture2D texture = Sprite.LoadTexture(filePath);
|
||||||
|
previewImage.Sprite = new Sprite(texture, null, null);
|
||||||
|
if (Submarine.MainSub != null)
|
||||||
|
{
|
||||||
|
Submarine.MainSub.Info.PreviewImage = previewImage.Sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DebugConsole.ThrowError($"Could not drag and drop the file. \"{extension}\" is not a valid file extension! (expected .xml, .sub, .png or .jpg)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Coroutine that waits 5 minutes and then runs itself recursively again to save the submarine into a temporary file
|
/// Coroutine that waits 5 minutes and then runs itself recursively again to save the submarine into a temporary file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2020,30 +2068,27 @@ namespace Barotrauma
|
|||||||
Submarine.MainSub.Info.Price = Math.Max(Submarine.MainSub.Info.Price, basePrice);
|
Submarine.MainSub.Info.Price = Math.Max(Submarine.MainSub.Info.Price, basePrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Submarine.MainSub.Info.HasTag(SubmarineTag.Shuttle))
|
var classGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), subSettingsContainer.RectTransform), isHorizontal: true)
|
||||||
{
|
{
|
||||||
var classGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), subSettingsContainer.RectTransform), isHorizontal: true)
|
Stretch = true
|
||||||
{
|
};
|
||||||
Stretch = true
|
var classText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), classGroup.RectTransform),
|
||||||
};
|
TextManager.Get("submarineclass"), textAlignment: Alignment.CenterLeft, wrap: true);
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), classGroup.RectTransform),
|
GUIDropDown classDropDown = new GUIDropDown(new RectTransform(new Vector2(0.4f, 1.0f), classGroup.RectTransform));
|
||||||
TextManager.Get("submarineclass"), textAlignment: Alignment.CenterLeft, wrap: true);
|
classDropDown.RectTransform.MinSize = new Point(0, subTypeContainer.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||||
GUIDropDown classDropDown = new GUIDropDown(new RectTransform(new Vector2(0.4f, 1.0f), classGroup.RectTransform));
|
classDropDown.AddItem(TextManager.Get("submarineclass.undefined"), SubmarineClass.Undefined);
|
||||||
classDropDown.RectTransform.MinSize = new Point(0, subTypeContainer.RectTransform.Children.Max(c => c.MinSize.Y));
|
classDropDown.AddItem(TextManager.Get("submarineclass.scout"), SubmarineClass.Scout);
|
||||||
classDropDown.AddItem(TextManager.Get("submarineclass.undefined"), SubmarineClass.Undefined);
|
classDropDown.AddItem(TextManager.Get("submarineclass.attack"), SubmarineClass.Attack);
|
||||||
classDropDown.AddItem(TextManager.Get("submarineclass.scout"), SubmarineClass.Scout);
|
classDropDown.AddItem(TextManager.Get("submarineclass.transport"), SubmarineClass.Transport);
|
||||||
classDropDown.AddItem(TextManager.Get("submarineclass.attack"), SubmarineClass.Attack);
|
classDropDown.AddItem(TextManager.Get("submarineclass.deepdiver"), SubmarineClass.DeepDiver);
|
||||||
classDropDown.AddItem(TextManager.Get("submarineclass.transport"), SubmarineClass.Transport);
|
classDropDown.OnSelected += (selected, userdata) =>
|
||||||
classDropDown.AddItem(TextManager.Get("submarineclass.deepdiver"), SubmarineClass.DeepDiver);
|
{
|
||||||
classDropDown.OnSelected += (selected, userdata) =>
|
SubmarineClass submarineClass = (SubmarineClass)userdata;
|
||||||
{
|
Submarine.MainSub.Info.SubmarineClass = submarineClass;
|
||||||
SubmarineClass submarineClass = (SubmarineClass)userdata;
|
return true;
|
||||||
Submarine.MainSub.Info.SubmarineClass = submarineClass;
|
};
|
||||||
return true;
|
classDropDown.SelectItem(Submarine.MainSub.Info.SubmarineClass);
|
||||||
};
|
classText.Enabled = classDropDown.ButtonEnabled = !Submarine.MainSub.Info.HasTag(SubmarineTag.Shuttle);
|
||||||
|
|
||||||
classDropDown.SelectItem(Submarine.MainSub.Info.SubmarineClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
var crewSizeArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), subSettingsContainer.RectTransform), isHorizontal: true)
|
var crewSizeArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), subSettingsContainer.RectTransform), isHorizontal: true)
|
||||||
{
|
{
|
||||||
@@ -2216,17 +2261,29 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Selected = Submarine.MainSub != null && Submarine.MainSub.Info.HasTag(tag),
|
Selected = Submarine.MainSub != null && Submarine.MainSub.Info.HasTag(tag),
|
||||||
UserData = tag,
|
UserData = tag,
|
||||||
|
|
||||||
OnSelected = (GUITickBox tickBox) =>
|
OnSelected = (GUITickBox tickBox) =>
|
||||||
{
|
{
|
||||||
if (Submarine.MainSub == null) return false;
|
if (Submarine.MainSub == null) return false;
|
||||||
|
SubmarineTag tag = (SubmarineTag)tickBox.UserData;
|
||||||
|
if (tag == SubmarineTag.Shuttle)
|
||||||
|
{
|
||||||
|
if (tickBox.Selected)
|
||||||
|
{
|
||||||
|
classDropDown.SelectItem(SubmarineClass.Undefined);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
classDropDown.SelectItem(Submarine.MainSub.Info.SubmarineClass);
|
||||||
|
}
|
||||||
|
classText.Enabled = classDropDown.ButtonEnabled = !tickBox.Selected;
|
||||||
|
}
|
||||||
if (tickBox.Selected)
|
if (tickBox.Selected)
|
||||||
{
|
{
|
||||||
Submarine.MainSub.Info.AddTag((SubmarineTag)tickBox.UserData);
|
Submarine.MainSub.Info.AddTag(tag);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Submarine.MainSub.Info.RemoveTag((SubmarineTag)tickBox.UserData);
|
Submarine.MainSub.Info.RemoveTag(tag);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2305,7 +2362,6 @@ namespace Barotrauma
|
|||||||
if (quickSave) { SaveSub(saveButton, saveButton.UserData); }
|
if (quickSave) { SaveSub(saveButton, saveButton.UserData); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void CreateSaveAssemblyScreen()
|
private void CreateSaveAssemblyScreen()
|
||||||
{
|
{
|
||||||
SetMode(Mode.Default);
|
SetMode(Mode.Default);
|
||||||
@@ -2712,8 +2768,15 @@ namespace Barotrauma
|
|||||||
if (subList.SelectedComponent == null) { return false; }
|
if (subList.SelectedComponent == null) { return false; }
|
||||||
if (!(subList.SelectedComponent.UserData is SubmarineInfo selectedSubInfo)) { return false; }
|
if (!(subList.SelectedComponent.UserData is SubmarineInfo selectedSubInfo)) { return false; }
|
||||||
|
|
||||||
|
LoadSub(selectedSubInfo);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadSub(SubmarineInfo info)
|
||||||
|
{
|
||||||
Submarine.Unload();
|
Submarine.Unload();
|
||||||
var selectedSub = new Submarine(selectedSubInfo);
|
var selectedSub = new Submarine(info);
|
||||||
Submarine.MainSub = selectedSub;
|
Submarine.MainSub = selectedSub;
|
||||||
Submarine.MainSub.UpdateTransform(interpolate: false);
|
Submarine.MainSub.UpdateTransform(interpolate: false);
|
||||||
ClearUndoBuffer();
|
ClearUndoBuffer();
|
||||||
@@ -2744,8 +2807,6 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
adjustLightsPrompt.Buttons[1].OnClicked += adjustLightsPrompt.Close;
|
adjustLightsPrompt.Buttons[1].OnClicked += adjustLightsPrompt.Close;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TryDeleteSub(SubmarineInfo sub)
|
private void TryDeleteSub(SubmarineInfo sub)
|
||||||
@@ -2822,7 +2883,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(entityFilterBox.Text) || dummyCharacter?.SelectedConstruction?.OwnInventory != null)
|
if (!string.IsNullOrEmpty(entityFilterBox.Text))
|
||||||
{
|
{
|
||||||
FilterEntities(entityFilterBox.Text);
|
FilterEntities(entityFilterBox.Text);
|
||||||
}
|
}
|
||||||
@@ -2835,7 +2896,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void FilterEntities(string filter)
|
private void FilterEntities(string filter)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(filter) && dummyCharacter?.SelectedConstruction?.OwnInventory == null)
|
if (string.IsNullOrWhiteSpace(filter))
|
||||||
{
|
{
|
||||||
allEntityList.Visible = false;
|
allEntityList.Visible = false;
|
||||||
categorizedEntityList.Visible = true;
|
categorizedEntityList.Visible = true;
|
||||||
@@ -2862,11 +2923,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
child.Visible =
|
child.Visible =
|
||||||
(!selectedCategory.HasValue || ((MapEntityPrefab)child.UserData).Category.HasFlag(selectedCategory)) &&
|
(!selectedCategory.HasValue || ((MapEntityPrefab)child.UserData).Category.HasFlag(selectedCategory)) &&
|
||||||
((MapEntityPrefab)child.UserData).Name.ToLower().Contains(filter); ;
|
((MapEntityPrefab)child.UserData).Name.ToLower().Contains(filter);
|
||||||
if (child.Visible && dummyCharacter?.SelectedConstruction?.OwnInventory != null)
|
|
||||||
{
|
|
||||||
child.Visible = child.UserData is MapEntityPrefab item && IsItemPrefab(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
allEntityList.UpdateScrollBarSize();
|
allEntityList.UpdateScrollBarSize();
|
||||||
allEntityList.BarScroll = 0.0f;
|
allEntityList.BarScroll = 0.0f;
|
||||||
@@ -2942,7 +2999,7 @@ namespace Barotrauma
|
|||||||
new ContextMenuOption("SubEditor.EditBackgroundColor", isEnabled: true, onSelected: CreateBackgroundColorPicker),
|
new ContextMenuOption("SubEditor.EditBackgroundColor", isEnabled: true, onSelected: CreateBackgroundColorPicker),
|
||||||
new ContextMenuOption("SubEditor.ToggleTransparency", isEnabled: true, onSelected: () => TransparentWiringMode = !TransparentWiringMode),
|
new ContextMenuOption("SubEditor.ToggleTransparency", isEnabled: true, onSelected: () => TransparentWiringMode = !TransparentWiringMode),
|
||||||
new ContextMenuOption("SubEditor.ToggleGrid", isEnabled: true, onSelected: () => ShouldDrawGrid = !ShouldDrawGrid),
|
new ContextMenuOption("SubEditor.ToggleGrid", isEnabled: true, onSelected: () => ShouldDrawGrid = !ShouldDrawGrid),
|
||||||
new ContextMenuOption("SubEditor.PasteAssembly", isEnabled: true, PasteAssembly),
|
new ContextMenuOption("SubEditor.PasteAssembly", isEnabled: true, () => PasteAssembly()),
|
||||||
new ContextMenuOption("Editor.SelectSame", isEnabled: targets.Count > 0, onSelected: delegate
|
new ContextMenuOption("Editor.SelectSame", isEnabled: targets.Count > 0, onSelected: delegate
|
||||||
{
|
{
|
||||||
IEnumerable<MapEntity> matching = MapEntity.mapEntityList.Where(e => e.prefab != null && targets.Any(t => t.prefab?.Identifier == e.prefab.Identifier) && !MapEntity.SelectedList.Contains(e));
|
IEnumerable<MapEntity> matching = MapEntity.mapEntityList.Where(e => e.prefab != null && targets.Any(t => t.prefab?.Identifier == e.prefab.Identifier) && !MapEntity.SelectedList.Contains(e));
|
||||||
@@ -2973,10 +3030,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PasteAssembly()
|
private void PasteAssembly(string text = null, Vector2? pos = null)
|
||||||
{
|
{
|
||||||
string clipboard = Clipboard.GetText();
|
pos ??= cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||||
if (string.IsNullOrWhiteSpace(clipboard))
|
text ??= Clipboard.GetText();
|
||||||
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Unable to paste assembly: Clipboard content is empty.");
|
DebugConsole.ThrowError("Unable to paste assembly: Clipboard content is empty.");
|
||||||
return;
|
return;
|
||||||
@@ -2986,7 +3044,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
element = XDocument.Parse(clipboard).Root;
|
element = XDocument.Parse(text).Root;
|
||||||
}
|
}
|
||||||
catch (Exception) { /* ignored */ }
|
catch (Exception) { /* ignored */ }
|
||||||
|
|
||||||
@@ -2996,12 +3054,11 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 pos = cam.ScreenToWorld(PlayerInput.MousePosition);
|
|
||||||
Submarine sub = Submarine.MainSub;
|
Submarine sub = Submarine.MainSub;
|
||||||
List<MapEntity> entities;
|
List<MapEntity> entities;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
entities = ItemAssemblyPrefab.PasteEntities(pos, sub, element, selectInstance: true);
|
entities = ItemAssemblyPrefab.PasteEntities(pos.Value, sub, element, selectInstance: true);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -3274,57 +3331,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
static string ColorToHex(Color color) => $"#{(color.R << 16 | color.G << 8 | color.B):X6}";
|
static string ColorToHex(Color color) => $"#{(color.R << 16 | color.G << 8 | color.B):X6}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a color picker that can be used to change the submarine editor's background color
|
|
||||||
/// </summary>
|
|
||||||
private void CreateBackgroundColorPicker()
|
|
||||||
{
|
|
||||||
var msgBox = new GUIMessageBox(TextManager.Get("CharacterEditor.EditBackgroundColor"), "", new[] { TextManager.Get("Reset"), TextManager.Get("OK")}, new Vector2(0.2f, 0.175f), minSize: new Point(300, 175));
|
|
||||||
|
|
||||||
var rgbLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.25f), msgBox.Content.RectTransform), isHorizontal: true);
|
|
||||||
|
|
||||||
// Generate R,G,B labels and parent elements
|
|
||||||
var layoutParents = new GUILayoutGroup[3];
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
var colorContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.33f, 1), rgbLayout.RectTransform), isHorizontal: true) { Stretch = true };
|
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1), colorContainer.RectTransform, Anchor.CenterLeft) { MinSize = new Point(15, 0) }, GUI.colorComponentLabels[i], font: GUI.SmallFont, textAlignment: Alignment.Center);
|
|
||||||
layoutParents[i] = colorContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// attach number inputs to our generated parent elements
|
|
||||||
var rInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1f), layoutParents[0].RectTransform), GUINumberInput.NumberType.Int) { IntValue = backgroundColor.R };
|
|
||||||
var gInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1f), layoutParents[1].RectTransform), GUINumberInput.NumberType.Int) { IntValue = backgroundColor.G };
|
|
||||||
var bInput = new GUINumberInput(new RectTransform(new Vector2(0.7f, 1f), layoutParents[2].RectTransform), GUINumberInput.NumberType.Int) { IntValue = backgroundColor.B };
|
|
||||||
|
|
||||||
rInput.MinValueInt = gInput.MinValueInt = bInput.MinValueInt = 0;
|
|
||||||
rInput.MaxValueInt = gInput.MaxValueInt = bInput.MaxValueInt = 255;
|
|
||||||
|
|
||||||
rInput.OnValueChanged = gInput.OnValueChanged = bInput.OnValueChanged = delegate
|
|
||||||
{
|
|
||||||
var color = new Color(rInput.IntValue, gInput.IntValue, bInput.IntValue);
|
|
||||||
backgroundColor = color;
|
|
||||||
GameSettings.SubEditorBackgroundColor = color;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Reset button
|
|
||||||
msgBox.Buttons[0].OnClicked = (button, o) =>
|
|
||||||
{
|
|
||||||
rInput.IntValue = 13;
|
|
||||||
gInput.IntValue = 37;
|
|
||||||
bInput.IntValue = 69;
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ok button
|
|
||||||
msgBox.Buttons[1].OnClicked = (button, o) =>
|
|
||||||
{
|
|
||||||
msgBox.Close();
|
|
||||||
GameMain.Config.SaveNewPlayerConfig();
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private GUIFrame CreateWiringPanel()
|
private GUIFrame CreateWiringPanel()
|
||||||
{
|
{
|
||||||
@@ -3495,27 +3501,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
submarineDescriptionCharacterCount.Text = text.Length + " / " + submarineDescriptionLimit;
|
submarineDescriptionCharacterCount.Text = text.Length + " / " + submarineDescriptionLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the prefab is an item or if it only consists of items
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mapPrefab">The prefab to check</param>
|
|
||||||
/// <returns>True if the the prefab is an item or it contains only items</returns>
|
|
||||||
private bool IsItemPrefab(MapEntityPrefab mapPrefab)
|
|
||||||
{
|
|
||||||
if (dummyCharacter?.SelectedConstruction == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapPrefab switch
|
|
||||||
{
|
|
||||||
ItemPrefab iPrefab => true,
|
|
||||||
ItemAssemblyPrefab aPrefab => aPrefab.DisplayEntities.All(pair => pair.First is ItemPrefab),
|
|
||||||
_ => false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool SelectPrefab(GUIComponent component, object obj)
|
private bool SelectPrefab(GUIComponent component, object obj)
|
||||||
{
|
{
|
||||||
allEntityList.Deselect();
|
allEntityList.Deselect();
|
||||||
@@ -4753,7 +4739,7 @@ namespace Barotrauma
|
|||||||
sub.UpdateTransform();
|
sub.UpdateTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
graphics.Clear(backgroundColor);
|
graphics.Clear(BackgroundColor);
|
||||||
|
|
||||||
ImageManager.Draw(spriteBatch, cam);
|
ImageManager.Draw(spriteBatch, cam);
|
||||||
|
|
||||||
|
|||||||
@@ -272,7 +272,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SerializableEntityEditor(RectTransform parent, ISerializableEntity entity, bool inGame, bool showName, string style = "", int elementHeight = 24, ScalableFont titleFont = null)
|
public SerializableEntityEditor(RectTransform parent, ISerializableEntity entity, bool inGame, bool showName, string style = "", int elementHeight = 24, ScalableFont titleFont = null)
|
||||||
: this(parent, entity, inGame ? SerializableProperty.GetProperties<InGameEditable>(entity) : SerializableProperty.GetProperties<Editable>(entity), showName, style, elementHeight, titleFont)
|
: this(parent, entity, inGame ?
|
||||||
|
SerializableProperty.GetProperties<InGameEditable>(entity).Union(SerializableProperty.GetProperties<ConditionallyEditable>(entity).Where(p => p.GetAttribute<ConditionallyEditable>()?.IsEditable() ?? false))
|
||||||
|
: SerializableProperty.GetProperties<Editable>(entity), showName, style, elementHeight, titleFont)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,6 +449,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
TrySendNetworkUpdate(entity, property);
|
TrySendNetworkUpdate(entity, property);
|
||||||
}
|
}
|
||||||
|
// Ensure that the values stay in sync (could be that we force the value in the property accessor).
|
||||||
|
bool propertyValue = (bool)property.GetValue(entity);
|
||||||
|
if (tickBox.Selected != propertyValue)
|
||||||
|
{
|
||||||
|
tickBox.Selected = propertyValue;
|
||||||
|
tickBox.Flash(Color.Red);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ namespace Barotrauma
|
|||||||
private readonly static BackgroundMusic[] targetMusic = new BackgroundMusic[MaxMusicChannels];
|
private readonly static BackgroundMusic[] targetMusic = new BackgroundMusic[MaxMusicChannels];
|
||||||
private static List<BackgroundMusic> musicClips;
|
private static List<BackgroundMusic> musicClips;
|
||||||
|
|
||||||
|
private static BackgroundMusic previousDefaultMusic;
|
||||||
|
|
||||||
private static float updateMusicTimer;
|
private static float updateMusicTimer;
|
||||||
|
|
||||||
//ambience
|
//ambience
|
||||||
@@ -829,9 +831,23 @@ namespace Barotrauma
|
|||||||
targetMusic[0] = null;
|
targetMusic[0] = null;
|
||||||
}
|
}
|
||||||
//switch the music if nothing playing atm or the currently playing clip is not suitable anymore
|
//switch the music if nothing playing atm or the currently playing clip is not suitable anymore
|
||||||
else if (targetMusic[0] == null || currentMusic[0] == null || !suitableMusic.Any(m => m.File == currentMusic[0].Filename))
|
else if (targetMusic[0] == null || currentMusic[0] == null || !currentMusic[0].IsPlaying() || !suitableMusic.Any(m => m.File == currentMusic[0].Filename))
|
||||||
{
|
{
|
||||||
targetMusic[0] = suitableMusic.GetRandom();
|
if (currentMusicType == "default")
|
||||||
|
{
|
||||||
|
if (previousDefaultMusic == null)
|
||||||
|
{
|
||||||
|
targetMusic[0] = previousDefaultMusic = suitableMusic.GetRandom();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetMusic[0] = previousDefaultMusic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetMusic[0] = suitableMusic.GetRandom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the appropriate intensity layers for current situation
|
//get the appropriate intensity layers for current situation
|
||||||
@@ -851,7 +867,7 @@ namespace Barotrauma
|
|||||||
foreach (BackgroundMusic intensityMusic in suitableIntensityMusic)
|
foreach (BackgroundMusic intensityMusic in suitableIntensityMusic)
|
||||||
{
|
{
|
||||||
//already playing, do nothing
|
//already playing, do nothing
|
||||||
if (targetMusic.Any(m => m != null && m.File == intensityMusic.File)) continue;
|
if (targetMusic.Any(m => m != null && m.File == intensityMusic.File)) { continue; }
|
||||||
|
|
||||||
for (int i = 1; i < MaxMusicChannels; i++)
|
for (int i = 1; i < MaxMusicChannels; i++)
|
||||||
{
|
{
|
||||||
@@ -973,7 +989,11 @@ namespace Barotrauma
|
|||||||
return "editor";
|
return "editor";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Screen.Selected != GameMain.GameScreen) { return firstTimeInMainMenu ? "menu" : "default"; }
|
if (Screen.Selected != GameMain.GameScreen)
|
||||||
|
{
|
||||||
|
previousDefaultMusic = null;
|
||||||
|
return firstTimeInMainMenu ? "menu" : "default";
|
||||||
|
}
|
||||||
|
|
||||||
firstTimeInMainMenu = false;
|
firstTimeInMainMenu = false;
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ namespace Barotrauma
|
|||||||
GameMain.Instance.GraphicsDevice.Viewport = prevViewport;
|
GameMain.Instance.GraphicsDevice.Viewport = prevViewport;
|
||||||
using (FileStream fs = File.Open("wikiimage.png", System.IO.FileMode.Create))
|
using (FileStream fs = File.Open("wikiimage.png", System.IO.FileMode.Create))
|
||||||
{
|
{
|
||||||
rt.SaveAsPng(fs, boundingBox.Width, boundingBox.Height);
|
rt.SaveAsPng(fs, texWidth, texHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.13.3.11</Version>
|
<Version>0.1400.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.13.3.11</Version>
|
<Version>0.1400.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// vim:ft=hlsl
|
// vim:ft=hlsl
|
||||||
//float4 baseColor;
|
|
||||||
float seed;
|
float seed;
|
||||||
|
float intensity;
|
||||||
|
float4 grainColor;
|
||||||
|
|
||||||
float nrand(float2 uv)
|
float nrand(float2 uv)
|
||||||
{
|
{
|
||||||
@@ -9,16 +10,15 @@ float nrand(float2 uv)
|
|||||||
|
|
||||||
float4 grain(float4 position : SV_POSITION, float4 clr : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
|
float4 grain(float4 position : SV_POSITION, float4 clr : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
|
||||||
{
|
{
|
||||||
float4 baseColor = { 1, 1, 1, 0.25 };
|
float4 baseColor = grainColor;
|
||||||
float4 color = baseColor * nrand(texCoord);
|
float4 color = baseColor * nrand(texCoord);
|
||||||
float2 center = { 0.5, 0.5 };
|
float2 center = { 0.5, 0.5 };
|
||||||
float2 diff = texCoord - center;
|
float2 diff = texCoord - center;
|
||||||
float alpha = diff.x * diff.x + diff.y * diff.y;
|
float alpha = diff.x * diff.x + diff.y * diff.y;
|
||||||
color.a = alpha;
|
color.a = alpha * intensity;
|
||||||
return clr * color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
technique Grain
|
technique Grain
|
||||||
{
|
{
|
||||||
pass Pass1
|
pass Pass1
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// vim:ft=hlsl
|
// vim:ft=hlsl
|
||||||
//float4 baseColor;
|
|
||||||
float seed;
|
float seed;
|
||||||
|
float intensity;
|
||||||
|
float4 grainColor;
|
||||||
|
|
||||||
float nrand(float2 uv)
|
float nrand(float2 uv)
|
||||||
{
|
{
|
||||||
@@ -9,16 +10,15 @@ float nrand(float2 uv)
|
|||||||
|
|
||||||
float4 grain(float4 position : SV_POSITION, float4 clr : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
|
float4 grain(float4 position : SV_POSITION, float4 clr : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
|
||||||
{
|
{
|
||||||
float4 baseColor = { 1, 1, 1, 0.25 };
|
float4 baseColor = grainColor;
|
||||||
float4 color = baseColor * nrand(texCoord);
|
float4 color = baseColor * nrand(texCoord);
|
||||||
float2 center = { 0.5, 0.5 };
|
float2 center = { 0.5, 0.5 };
|
||||||
float2 diff = texCoord - center;
|
float2 diff = texCoord - center;
|
||||||
float alpha = diff.x * diff.x + diff.y * diff.y;
|
float alpha = diff.x * diff.x + diff.y * diff.y;
|
||||||
color.a = alpha;
|
color.a = alpha * intensity;
|
||||||
return clr * color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
technique Grain
|
technique Grain
|
||||||
{
|
{
|
||||||
pass Pass1
|
pass Pass1
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.13.3.11</Version>
|
<Version>0.1400.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.13.3.11</Version>
|
<Version>0.1400.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.13.3.11</Version>
|
<Version>0.1400.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -283,24 +283,25 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (extraData != null)
|
if (extraData != null)
|
||||||
{
|
{
|
||||||
|
int min = 0, max = 9;
|
||||||
switch ((NetEntityEvent.Type)extraData[0])
|
switch ((NetEntityEvent.Type)extraData[0])
|
||||||
{
|
{
|
||||||
case NetEntityEvent.Type.InventoryState:
|
case NetEntityEvent.Type.InventoryState:
|
||||||
msg.WriteRangedInteger(0, 0, 6);
|
msg.WriteRangedInteger(0, min, max);
|
||||||
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
|
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
|
||||||
Inventory.ServerWrite(msg, c);
|
Inventory.ServerWrite(msg, c);
|
||||||
break;
|
break;
|
||||||
case NetEntityEvent.Type.Control:
|
case NetEntityEvent.Type.Control:
|
||||||
msg.WriteRangedInteger(1, 0, 6);
|
msg.WriteRangedInteger(1, min, max);
|
||||||
Client owner = (Client)extraData[1];
|
Client owner = (Client)extraData[1];
|
||||||
msg.Write(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.ID : (byte)0);
|
msg.Write(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.ID : (byte)0);
|
||||||
break;
|
break;
|
||||||
case NetEntityEvent.Type.Status:
|
case NetEntityEvent.Type.Status:
|
||||||
msg.WriteRangedInteger(2, 0, 6);
|
msg.WriteRangedInteger(2, min, max);
|
||||||
WriteStatus(msg);
|
WriteStatus(msg);
|
||||||
break;
|
break;
|
||||||
case NetEntityEvent.Type.UpdateSkills:
|
case NetEntityEvent.Type.UpdateSkills:
|
||||||
msg.WriteRangedInteger(3, 0, 6);
|
msg.WriteRangedInteger(3, min, max);
|
||||||
if (Info?.Job == null)
|
if (Info?.Job == null)
|
||||||
{
|
{
|
||||||
msg.Write((byte)0);
|
msg.Write((byte)0);
|
||||||
@@ -315,39 +316,71 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NetEntityEvent.Type.SetAttackTarget:
|
||||||
case NetEntityEvent.Type.ExecuteAttack:
|
case NetEntityEvent.Type.ExecuteAttack:
|
||||||
Limb attackLimb = extraData[1] as Limb;
|
Limb attackLimb = extraData[1] as Limb;
|
||||||
UInt16 targetEntityID = (UInt16)extraData[2];
|
UInt16 targetEntityID = (UInt16)extraData[2];
|
||||||
int targetLimbIndex = extraData.Length > 3 ? (int)extraData[3] : 0;
|
int targetLimbIndex = extraData.Length > 3 ? (int)extraData[3] : 0;
|
||||||
msg.WriteRangedInteger(4, 0, 6);
|
msg.WriteRangedInteger(extraData[0] is NetEntityEvent.Type.SetAttackTarget ? 4 : 5, min, max);
|
||||||
msg.Write((byte)(Removed ? 255 : Array.IndexOf(AnimController.Limbs, attackLimb)));
|
msg.Write((byte)(Removed ? 255 : Array.IndexOf(AnimController.Limbs, attackLimb)));
|
||||||
msg.Write(targetEntityID);
|
msg.Write(targetEntityID);
|
||||||
msg.Write((byte)targetLimbIndex);
|
msg.Write((byte)targetLimbIndex);
|
||||||
|
msg.Write(extraData.Length > 4 ? (float)extraData[4] : 0);
|
||||||
|
msg.Write(extraData.Length > 5 ? (float)extraData[5] : 0);
|
||||||
break;
|
break;
|
||||||
case NetEntityEvent.Type.AssignCampaignInteraction:
|
case NetEntityEvent.Type.AssignCampaignInteraction:
|
||||||
msg.WriteRangedInteger(5, 0, 6);
|
msg.WriteRangedInteger(6, min, max);
|
||||||
msg.Write((byte)CampaignInteractionType);
|
msg.Write((byte)CampaignInteractionType);
|
||||||
break;
|
break;
|
||||||
case NetEntityEvent.Type.ObjectiveManagerOrderState:
|
case NetEntityEvent.Type.ObjectiveManagerState:
|
||||||
msg.WriteRangedInteger(6, 0, 6);
|
msg.WriteRangedInteger(7, min, max);
|
||||||
|
int type = (extraData[1] as string) switch
|
||||||
|
{
|
||||||
|
"order" => 1,
|
||||||
|
"objective" => 2,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
msg.WriteRangedInteger(type, 0, 2);
|
||||||
if (!(AIController is HumanAIController controller))
|
if (!(AIController is HumanAIController controller))
|
||||||
{
|
{
|
||||||
msg.Write(false);
|
msg.Write(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var currentOrderInfo = controller.ObjectiveManager.GetCurrentOrderInfo();
|
if (type == 1)
|
||||||
if (!currentOrderInfo.HasValue)
|
|
||||||
{
|
{
|
||||||
msg.Write(false);
|
var currentOrderInfo = controller.ObjectiveManager.GetCurrentOrderInfo();
|
||||||
break;
|
bool validOrder = currentOrderInfo.HasValue;
|
||||||
|
msg.Write(validOrder);
|
||||||
|
if (!validOrder) { break; }
|
||||||
|
var orderPrefab = currentOrderInfo.Value.Order.Prefab;
|
||||||
|
int orderIndex = Order.PrefabList.IndexOf(orderPrefab);
|
||||||
|
msg.WriteRangedInteger(orderIndex, 0, Order.PrefabList.Count);
|
||||||
|
if (!orderPrefab.HasOptions) { break; }
|
||||||
|
int optionIndex = orderPrefab.Options.IndexOf(currentOrderInfo.Value.OrderOption);
|
||||||
|
msg.WriteRangedInteger(optionIndex, 0, orderPrefab.Options.Length);
|
||||||
}
|
}
|
||||||
msg.Write(true);
|
else if (type == 2)
|
||||||
var orderPrefab = currentOrderInfo.Value.Order.Prefab;
|
{
|
||||||
int orderIndex = Order.PrefabList.IndexOf(orderPrefab);
|
var objective = controller.ObjectiveManager.CurrentObjective;
|
||||||
msg.WriteRangedInteger(orderIndex, 0, Order.PrefabList.Count);
|
bool validObjective = !string.IsNullOrEmpty(objective?.Identifier);
|
||||||
if (!orderPrefab.HasOptions) { break; }
|
msg.Write(validObjective);
|
||||||
int optionIndex = orderPrefab.Options.IndexOf(currentOrderInfo.Value.OrderOption);
|
if (!validObjective) { break; }
|
||||||
msg.WriteRangedInteger(optionIndex, 0, orderPrefab.Options.Length);
|
msg.Write(objective.Identifier);
|
||||||
|
msg.Write(objective.Option ?? "");
|
||||||
|
UInt16 targetEntityId = 0;
|
||||||
|
if (objective is AIObjectiveOperateItem operateObjective && operateObjective.OperateTarget != null)
|
||||||
|
{
|
||||||
|
targetEntityId = operateObjective.OperateTarget.ID;
|
||||||
|
}
|
||||||
|
msg.Write(targetEntityId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NetEntityEvent.Type.TeamChange:
|
||||||
|
msg.WriteRangedInteger(8, min, max);
|
||||||
|
msg.Write((byte)TeamID);
|
||||||
|
break;
|
||||||
|
case NetEntityEvent.Type.AddToCrew:
|
||||||
|
msg.WriteRangedInteger(9, min, max);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DebugConsole.ThrowError("Invalid NetworkEvent type for entity " + ToString() + " (" + (NetEntityEvent.Type)extraData[0] + ")");
|
DebugConsole.ThrowError("Invalid NetworkEvent type for entity " + ToString() + " (" + (NetEntityEvent.Type)extraData[0] + ")");
|
||||||
|
|||||||
@@ -1688,13 +1688,18 @@ namespace Barotrauma
|
|||||||
"heal",
|
"heal",
|
||||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||||
{
|
{
|
||||||
Character healedCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args);
|
bool healAll = args.Length > 1 && args[1].Equals("all", StringComparison.OrdinalIgnoreCase);
|
||||||
|
Character healedCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(healAll ? args.Take(args.Length - 1).ToArray() : args);
|
||||||
if (healedCharacter != null)
|
if (healedCharacter != null)
|
||||||
{
|
{
|
||||||
healedCharacter.SetAllDamage(0.0f, 0.0f, 0.0f);
|
healedCharacter.SetAllDamage(0.0f, 0.0f, 0.0f);
|
||||||
healedCharacter.Oxygen = 100.0f;
|
healedCharacter.Oxygen = 100.0f;
|
||||||
healedCharacter.Bloodloss = 0.0f;
|
healedCharacter.Bloodloss = 0.0f;
|
||||||
healedCharacter.SetStun(0.0f, true);
|
healedCharacter.SetStun(0.0f, true);
|
||||||
|
if (healAll)
|
||||||
|
{
|
||||||
|
healedCharacter.CharacterHealth.RemoveAllAfflictions();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace Barotrauma
|
|||||||
msg.Write((ushort)characterItems[character].Count());
|
msg.Write((ushort)characterItems[character].Count());
|
||||||
foreach (Item item in characterItems[character])
|
foreach (Item item in characterItems[character])
|
||||||
{
|
{
|
||||||
item.WriteSpawnData(msg, item.ID, item.ParentInventory.Owner?.ID ?? Entity.NullEntityID, 0);
|
item.WriteSpawnData(msg, item.ID, item.ParentInventory?.Owner?.ID ?? Entity.NullEntityID, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Barotrauma.Networking;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
partial class EscortMission : Mission
|
||||||
|
{
|
||||||
|
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||||
|
{
|
||||||
|
if (characters.Count == 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Server attempted to write escort mission data when no characters had been spawned.");
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Write((byte)characters.Count);
|
||||||
|
foreach (Character character in characters)
|
||||||
|
{
|
||||||
|
character.WriteSpawnData(msg, character.ID, restrictMessageSize: false);
|
||||||
|
List<Item> characterItems = characterDictionary[character];
|
||||||
|
// items must be written in a specific sequence so that child items aren't written before their parents
|
||||||
|
msg.Write((ushort)characterItems.Count());
|
||||||
|
foreach (Item item in characterItems)
|
||||||
|
{
|
||||||
|
item.WriteSpawnData(msg, item.ID, item.ParentInventory.Owner?.ID ?? Entity.NullEntityID, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using Barotrauma.Networking;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
partial class PirateMission : Mission
|
||||||
|
{
|
||||||
|
public override void ServerWriteInitial(IWriteMessage msg, Client c)
|
||||||
|
{
|
||||||
|
// duplicate code from escortmission, should possibly be combined, though additional loot items might be added so maybe not
|
||||||
|
if (characters.Count == 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Server attempted to write escort mission data when no characters had been spawned.");
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Write((byte)characters.Count);
|
||||||
|
foreach (Character character in characters)
|
||||||
|
{
|
||||||
|
character.WriteSpawnData(msg, character.ID, restrictMessageSize: false);
|
||||||
|
List<Item> characterItems = characterDictionary[character];
|
||||||
|
// items must be written in a specific sequence so that child items aren't written before their parents
|
||||||
|
msg.Write((ushort)characterItems.Count());
|
||||||
|
foreach (Item item in characterItems)
|
||||||
|
{
|
||||||
|
item.WriteSpawnData(msg, item.ID, item.ParentInventory.Owner?.ID ?? Entity.NullEntityID, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
using System;
|
using Barotrauma.Networking;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Barotrauma.Networking;
|
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -26,7 +25,6 @@ namespace Barotrauma
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves bots in multiplayer
|
/// Saves bots in multiplayer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="root"></param>
|
|
||||||
public void SaveMultiplayer(XElement root)
|
public void SaveMultiplayer(XElement root)
|
||||||
{
|
{
|
||||||
XElement saveElement = new XElement("bots", new XAttribute("hasbots", HasBots));
|
XElement saveElement = new XElement("bots", new XAttribute("hasbots", HasBots));
|
||||||
@@ -40,8 +38,30 @@ namespace Barotrauma
|
|||||||
XElement characterElement = info.Save(saveElement);
|
XElement characterElement = info.Save(saveElement);
|
||||||
if (info.InventoryData != null) { characterElement.Add(info.InventoryData); }
|
if (info.InventoryData != null) { characterElement.Add(info.InventoryData); }
|
||||||
if (info.HealthData != null) { characterElement.Add(info.HealthData); }
|
if (info.HealthData != null) { characterElement.Add(info.HealthData); }
|
||||||
|
if (info.OrderData != null) { characterElement.Add(info.OrderData); }
|
||||||
}
|
}
|
||||||
|
SaveActiveOrders(saveElement);
|
||||||
root.Add(saveElement);
|
root.Add(saveElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ServerWriteActiveOrders(IWriteMessage msg)
|
||||||
|
{
|
||||||
|
ushort count = (ushort)ActiveOrders.Count(o => o.First != null && !o.Second.HasValue);
|
||||||
|
msg.Write(count);
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
foreach (var activeOrder in ActiveOrders)
|
||||||
|
{
|
||||||
|
if (!(activeOrder?.First is Order order) || activeOrder.Second.HasValue) { continue; }
|
||||||
|
OrderChatMessage.WriteOrder(msg, order, null, order.TargetSpatialEntity, null, 0, order.WallSectionIndex);
|
||||||
|
bool hasOrderGiver = order.OrderGiver != null;
|
||||||
|
msg.Write(hasOrderGiver);
|
||||||
|
if (hasOrderGiver)
|
||||||
|
{
|
||||||
|
msg.Write(order.OrderGiver.ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-2
@@ -35,9 +35,14 @@ namespace Barotrauma
|
|||||||
character.SpawnInventoryItems(inventory, itemData);
|
character.SpawnInventoryItems(inventory, itemData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyHealthData(CharacterInfo characterInfo, Character character)
|
public void ApplyHealthData(Character character)
|
||||||
{
|
{
|
||||||
characterInfo.ApplyHealthData(character, healthData);
|
CharacterInfo.ApplyHealthData(character, healthData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ApplyOrderData(Character character)
|
||||||
|
{
|
||||||
|
CharacterInfo.ApplyOrderData(character, OrderData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+112
-55
@@ -49,7 +49,15 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
|
||||||
SaveUtil.LoadGame(selectedSave);
|
SaveUtil.LoadGame(selectedSave);
|
||||||
((MultiPlayerCampaign)GameMain.GameSession.GameMode).LastSaveID++;
|
if (GameMain.GameSession.GameMode is MultiPlayerCampaign mpCampaign)
|
||||||
|
{
|
||||||
|
mpCampaign.LastSaveID++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Unexpected game mode: " + GameMain.GameSession.GameMode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
DebugConsole.NewMessage("Campaign loaded!", Color.Cyan);
|
DebugConsole.NewMessage("Campaign loaded!", Color.Cyan);
|
||||||
DebugConsole.NewMessage(
|
DebugConsole.NewMessage(
|
||||||
GameMain.GameSession.Map.SelectedLocation == null ?
|
GameMain.GameSession.Map.SelectedLocation == null ?
|
||||||
@@ -155,6 +163,63 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SaveInventories()
|
||||||
|
{
|
||||||
|
List<CharacterCampaignData> prevCharacterData = new List<CharacterCampaignData>(characterData);
|
||||||
|
//client character has spawned this round -> remove old data (and replace with an up-to-date one if the client still has a character)
|
||||||
|
characterData.RemoveAll(cd => cd.HasSpawned);
|
||||||
|
|
||||||
|
//refresh the character data of clients who are still in the server
|
||||||
|
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||||
|
{
|
||||||
|
if (c.Character?.Info == null) { continue; }
|
||||||
|
if (c.Character.IsDead && c.Character.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) { continue; }
|
||||||
|
c.CharacterInfo = c.Character.Info;
|
||||||
|
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
||||||
|
characterData.Add(new CharacterCampaignData(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
//refresh the character data of clients who aren't in the server anymore
|
||||||
|
foreach (CharacterCampaignData data in prevCharacterData)
|
||||||
|
{
|
||||||
|
if (data.HasSpawned && !characterData.Any(cd => cd.IsDuplicate(data)))
|
||||||
|
{
|
||||||
|
var character = Character.CharacterList.Find(c => c.Info == data.CharacterInfo && !c.IsHusk);
|
||||||
|
if (character != null && (!character.IsDead || character.CauseOfDeath?.Type == CauseOfDeathType.Disconnected))
|
||||||
|
{
|
||||||
|
data.Refresh(character);
|
||||||
|
characterData.Add(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
characterData.ForEach(cd => cd.HasSpawned = false);
|
||||||
|
|
||||||
|
petsElement = new XElement("pets");
|
||||||
|
PetBehavior.SavePets(petsElement);
|
||||||
|
|
||||||
|
//remove all items that are in someone's inventory
|
||||||
|
foreach (Character c in Character.CharacterList)
|
||||||
|
{
|
||||||
|
if (c.Inventory == null) { continue; }
|
||||||
|
if (Level.Loaded.Type == LevelData.LevelType.Outpost && c.Submarine != Level.Loaded.StartOutpost)
|
||||||
|
{
|
||||||
|
Map.CurrentLocation.RegisterTakenItems(c.Inventory.AllItems.Where(it => it.SpawnedInOutpost && it.OriginalModuleIndex > 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.Info != null && c.IsBot)
|
||||||
|
{
|
||||||
|
if (c.IsDead && c.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) { CrewManager.RemoveCharacterInfo(c.Info); }
|
||||||
|
c.Info.HealthData = new XElement("health");
|
||||||
|
c.CharacterHealth.Save(c.Info.HealthData);
|
||||||
|
c.Info.InventoryData = new XElement("inventory");
|
||||||
|
c.SaveInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Inventory.DeleteAllItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override IEnumerable<object> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults)
|
protected override IEnumerable<object> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults)
|
||||||
{
|
{
|
||||||
lastUpdateID++;
|
lastUpdateID++;
|
||||||
@@ -186,59 +251,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
List<CharacterCampaignData> prevCharacterData = new List<CharacterCampaignData>(characterData);
|
SaveInventories();
|
||||||
//client character has spawned this round -> remove old data (and replace with an up-to-date one if the client still has a character)
|
|
||||||
characterData.RemoveAll(cd => cd.HasSpawned);
|
|
||||||
|
|
||||||
//refresh the character data of clients who are still in the server
|
|
||||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
|
||||||
{
|
|
||||||
if (c.Character?.Info == null) { continue; }
|
|
||||||
if (c.Character.IsDead && c.Character.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) { continue; }
|
|
||||||
c.CharacterInfo = c.Character.Info;
|
|
||||||
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
|
||||||
characterData.Add(new CharacterCampaignData(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
//refresh the character data of clients who aren't in the server anymore
|
|
||||||
foreach (CharacterCampaignData data in prevCharacterData)
|
|
||||||
{
|
|
||||||
if (data.HasSpawned && !characterData.Any(cd => cd.IsDuplicate(data)))
|
|
||||||
{
|
|
||||||
var character = Character.CharacterList.Find(c => c.Info == data.CharacterInfo && !c.IsHusk);
|
|
||||||
if (character != null && (!character.IsDead || character.CauseOfDeath?.Type == CauseOfDeathType.Disconnected))
|
|
||||||
{
|
|
||||||
data.Refresh(character);
|
|
||||||
characterData.Add(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
characterData.ForEach(cd => cd.HasSpawned = false);
|
|
||||||
|
|
||||||
petsElement = new XElement("pets");
|
|
||||||
PetBehavior.SavePets(petsElement);
|
|
||||||
|
|
||||||
//remove all items that are in someone's inventory
|
|
||||||
foreach (Character c in Character.CharacterList)
|
|
||||||
{
|
|
||||||
if (c.Inventory == null) { continue; }
|
|
||||||
if (Level.Loaded.Type == LevelData.LevelType.Outpost && c.Submarine != Level.Loaded.StartOutpost)
|
|
||||||
{
|
|
||||||
Map.CurrentLocation.RegisterTakenItems(c.Inventory.AllItems.Where(it => it.SpawnedInOutpost && it.OriginalModuleIndex > 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c.Info != null && c.IsBot)
|
|
||||||
{
|
|
||||||
if (c.IsDead && c.CauseOfDeath?.Type != CauseOfDeathType.Disconnected) { CrewManager.RemoveCharacterInfo(c.Info); }
|
|
||||||
c.Info.HealthData = new XElement("health");
|
|
||||||
c.CharacterHealth.Save(c.Info.HealthData);
|
|
||||||
c.Info.InventoryData = new XElement("inventory");
|
|
||||||
c.SaveInventory(c.Inventory, c.Info.InventoryData);
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Inventory.DeleteAllItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
@@ -284,6 +297,8 @@ namespace Barotrauma
|
|||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CrewManager?.ClearCurrentOrders();
|
||||||
|
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
|
|
||||||
GameMain.Server.EndGame(transitionType);
|
GameMain.Server.EndGame(transitionType);
|
||||||
@@ -497,6 +512,13 @@ namespace Barotrauma
|
|||||||
msg.Write((byte)level);
|
msg.Write((byte)level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msg.Write((ushort)UpgradeManager.PurchasedItemSwaps.Count);
|
||||||
|
foreach (var itemSwap in UpgradeManager.PurchasedItemSwaps)
|
||||||
|
{
|
||||||
|
msg.Write(itemSwap.ItemToRemove.ID);
|
||||||
|
msg.Write(itemSwap.ItemToInstall?.Identifier ?? string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
var characterData = GetClientCharacterData(c);
|
var characterData = GetClientCharacterData(c);
|
||||||
if (characterData?.CharacterInfo == null)
|
if (characterData?.CharacterInfo == null)
|
||||||
{
|
{
|
||||||
@@ -563,6 +585,21 @@ namespace Barotrauma
|
|||||||
purchasedUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
|
purchasedUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ushort purchasedItemSwapCount = msg.ReadUInt16();
|
||||||
|
List<PurchasedItemSwap> purchasedItemSwaps = new List<PurchasedItemSwap>();
|
||||||
|
for (int i = 0; i < purchasedItemSwapCount; i++)
|
||||||
|
{
|
||||||
|
UInt16 itemToRemoveID = msg.ReadUInt16();
|
||||||
|
Item itemToRemove = Entity.FindEntityByID(itemToRemoveID) as Item;
|
||||||
|
|
||||||
|
string itemToInstallIdentifier = msg.ReadString();
|
||||||
|
ItemPrefab itemToInstall = string.IsNullOrEmpty(itemToInstallIdentifier) ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier);
|
||||||
|
|
||||||
|
if (itemToRemove == null) { continue; }
|
||||||
|
|
||||||
|
purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall));
|
||||||
|
}
|
||||||
|
|
||||||
if (!AllowedToManageCampaign(sender))
|
if (!AllowedToManageCampaign(sender))
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
|
DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
|
||||||
@@ -649,6 +686,26 @@ namespace Barotrauma
|
|||||||
int level = UpgradeManager.GetUpgradeLevel(prefab, category);
|
int level = UpgradeManager.GetUpgradeLevel(prefab, category);
|
||||||
GameServer.Log($"SERVER: Purchased level {level} {category.Identifier}.{prefab.Identifier} for {price}", ServerLog.MessageType.ServerMessage);
|
GameServer.Log($"SERVER: Purchased level {level} {category.Identifier}.{prefab.Identifier} for {price}", ServerLog.MessageType.ServerMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var purchasedItemSwap in purchasedItemSwaps)
|
||||||
|
{
|
||||||
|
if (purchasedItemSwap.ItemToInstall == null)
|
||||||
|
{
|
||||||
|
UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (Item item in Item.ItemList)
|
||||||
|
{
|
||||||
|
if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item))
|
||||||
|
{
|
||||||
|
UpgradeManager.CancelItemSwap(item);
|
||||||
|
item.PendingItemSwap = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ServerReadCrew(IReadMessage msg, Client sender)
|
public void ServerReadCrew(IReadMessage msg, Client sender)
|
||||||
@@ -863,7 +920,7 @@ namespace Barotrauma
|
|||||||
CampaignMetadata?.Save(modeElement);
|
CampaignMetadata?.Save(modeElement);
|
||||||
Map.Save(modeElement);
|
Map.Save(modeElement);
|
||||||
CargoManager?.SavePurchasedItems(modeElement);
|
CargoManager?.SavePurchasedItems(modeElement);
|
||||||
UpgradeManager?.SavePendingUpgrades(modeElement, UpgradeManager?.PendingUpgrades);
|
UpgradeManager?.Save(modeElement);
|
||||||
|
|
||||||
if (petsElement != null)
|
if (petsElement != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,11 +8,18 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial class Item : MapEntity, IDamageable, ISerializableEntity, IServerSerializable, IClientSerializable
|
partial class Item : MapEntity, IDamageable, ISerializableEntity, IServerSerializable, IClientSerializable
|
||||||
{
|
{
|
||||||
|
private CoroutineHandle logPropertyChangeCoroutine;
|
||||||
|
|
||||||
public override Sprite Sprite
|
public override Sprite Sprite
|
||||||
{
|
{
|
||||||
get { return prefab?.sprite; }
|
get { return prefab?.sprite; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void AssignCampaignInteractionTypeProjSpecific(CampaignMode.InteractionType interactionType)
|
||||||
|
{
|
||||||
|
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.AssignCampaignInteraction });
|
||||||
|
}
|
||||||
|
|
||||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||||
{
|
{
|
||||||
string errorMsg = "";
|
string errorMsg = "";
|
||||||
@@ -86,6 +93,9 @@ namespace Barotrauma
|
|||||||
case NetEntityEvent.Type.Status:
|
case NetEntityEvent.Type.Status:
|
||||||
msg.Write(condition);
|
msg.Write(condition);
|
||||||
break;
|
break;
|
||||||
|
case NetEntityEvent.Type.AssignCampaignInteraction:
|
||||||
|
msg.Write((byte)CampaignInteractionType);
|
||||||
|
break;
|
||||||
case NetEntityEvent.Type.Treatment:
|
case NetEntityEvent.Type.Treatment:
|
||||||
{
|
{
|
||||||
ItemComponent targetComponent = (ItemComponent)extraData[1];
|
ItemComponent targetComponent = (ItemComponent)extraData[1];
|
||||||
|
|||||||
@@ -22,80 +22,23 @@ namespace Barotrauma.Networking
|
|||||||
int? wallSectionIndex = null;
|
int? wallSectionIndex = null;
|
||||||
if (type == ChatMessageType.Order)
|
if (type == ChatMessageType.Order)
|
||||||
{
|
{
|
||||||
int orderIndex = msg.ReadByte();
|
var orderMessageInfo = OrderChatMessage.ReadOrder(msg);
|
||||||
orderTargetCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character;
|
if (orderMessageInfo.OrderIndex < 0 || orderMessageInfo.OrderIndex >= Order.PrefabList.Count)
|
||||||
orderTargetEntity = Entity.FindEntityByID(msg.ReadUInt16()) as Entity;
|
|
||||||
|
|
||||||
Order orderPrefab = null;
|
|
||||||
int? orderOptionIndex = null;
|
|
||||||
string orderOption = null;
|
|
||||||
|
|
||||||
// The option of a Dismiss order is written differently so we know what order we target
|
|
||||||
// now that the game supports multiple current orders simultaneously
|
|
||||||
if (orderIndex >= 0 && orderIndex < Order.PrefabList.Count)
|
|
||||||
{
|
{
|
||||||
orderPrefab = Order.PrefabList[orderIndex];
|
DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderMessageInfo.OrderIndex}).");
|
||||||
if (orderPrefab.Identifier != "dismissed")
|
|
||||||
{
|
|
||||||
orderOptionIndex = msg.ReadByte();
|
|
||||||
}
|
|
||||||
// Does the dismiss order have a specified target?
|
|
||||||
else if(msg.ReadBoolean())
|
|
||||||
{
|
|
||||||
int identifierCount = msg.ReadByte();
|
|
||||||
if (identifierCount > 0)
|
|
||||||
{
|
|
||||||
int dismissedOrderIndex = msg.ReadByte();
|
|
||||||
Order dismissedOrderPrefab = null;
|
|
||||||
if (dismissedOrderIndex >= 0 && dismissedOrderIndex < Order.PrefabList.Count)
|
|
||||||
{
|
|
||||||
dismissedOrderPrefab = Order.PrefabList[dismissedOrderIndex];
|
|
||||||
orderOption = dismissedOrderPrefab.Identifier;
|
|
||||||
}
|
|
||||||
if (identifierCount > 1)
|
|
||||||
{
|
|
||||||
int dismissedOrderOptionIndex = msg.ReadByte();
|
|
||||||
if (dismissedOrderPrefab != null)
|
|
||||||
{
|
|
||||||
var options = dismissedOrderPrefab.Options;
|
|
||||||
if (options != null && dismissedOrderOptionIndex >= 0 && dismissedOrderOptionIndex < options.Length)
|
|
||||||
{
|
|
||||||
orderOption += $".{options[dismissedOrderOptionIndex]}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
orderOptionIndex = msg.ReadByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
int orderPriority = msg.ReadByte();
|
|
||||||
orderTargetType = (Order.OrderTargetType)msg.ReadByte();
|
|
||||||
if (msg.ReadBoolean())
|
|
||||||
{
|
|
||||||
var x = msg.ReadSingle();
|
|
||||||
var y = msg.ReadSingle();
|
|
||||||
var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull;
|
|
||||||
orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, true);
|
|
||||||
}
|
|
||||||
else if (orderTargetType == Order.OrderTargetType.WallSection)
|
|
||||||
{
|
|
||||||
wallSectionIndex = msg.ReadByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderIndex}).");
|
|
||||||
if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { c.LastSentChatMsgID = ID; }
|
if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { c.LastSentChatMsgID = ID; }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
orderTargetCharacter = orderMessageInfo.TargetCharacter;
|
||||||
orderPrefab ??= Order.PrefabList[orderIndex];
|
orderTargetEntity = orderMessageInfo.TargetEntity;
|
||||||
orderOption ??= orderOptionIndex == null || orderOptionIndex < 0 || orderOptionIndex >= orderPrefab.Options.Length ? "" : orderPrefab.Options[orderOptionIndex.Value];
|
orderTargetPosition = orderMessageInfo.TargetPosition;
|
||||||
orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderPriority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character)
|
orderTargetType = orderMessageInfo.TargetType;
|
||||||
|
wallSectionIndex = orderMessageInfo.WallSectionIndex;
|
||||||
|
var orderPrefab = orderMessageInfo.OrderPrefab ?? Order.PrefabList[orderMessageInfo.OrderIndex];
|
||||||
|
string orderOption = orderMessageInfo.OrderOption ??
|
||||||
|
(orderMessageInfo.OrderOptionIndex == null || orderMessageInfo.OrderOptionIndex < 0 || orderMessageInfo.OrderOptionIndex >= orderPrefab.Options.Length ?
|
||||||
|
"" : orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value]);
|
||||||
|
orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderMessageInfo.Priority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character)
|
||||||
{
|
{
|
||||||
WallSectionIndex = wallSectionIndex
|
WallSectionIndex = wallSectionIndex
|
||||||
};
|
};
|
||||||
@@ -176,46 +119,49 @@ namespace Barotrauma.Networking
|
|||||||
if (type == ChatMessageType.Order)
|
if (type == ChatMessageType.Order)
|
||||||
{
|
{
|
||||||
if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead) { return; }
|
if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead) { return; }
|
||||||
Order order = null;
|
|
||||||
if (orderMsg.Order.IsReport)
|
if (orderMsg.Order.IsReport)
|
||||||
{
|
{
|
||||||
HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order);
|
HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order);
|
||||||
}
|
}
|
||||||
else if (orderTargetCharacter != null && !orderMsg.Order.TargetAllCharacters)
|
Order order = orderTargetType switch
|
||||||
{
|
{
|
||||||
switch (orderTargetType)
|
Order.OrderTargetType.Entity =>
|
||||||
|
new Order(orderMsg.Order, orderTargetEntity, orderMsg.Order?.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: orderMsg.Sender),
|
||||||
|
Order.OrderTargetType.Position =>
|
||||||
|
new Order(orderMsg.Order, orderTargetPosition, orderGiver: orderMsg.Sender),
|
||||||
|
Order.OrderTargetType.WallSection when orderTargetEntity is Structure s && wallSectionIndex.HasValue =>
|
||||||
|
new Order(orderMsg.Order, s, wallSectionIndex, orderGiver: orderMsg.Sender),
|
||||||
|
_ => throw new NotImplementedException()
|
||||||
|
};
|
||||||
|
if (order != null)
|
||||||
|
{
|
||||||
|
if (order.TargetAllCharacters)
|
||||||
{
|
{
|
||||||
case Order.OrderTargetType.Entity:
|
if (order.IsIgnoreOrder)
|
||||||
order = new Order(orderMsg.Order.Prefab, orderTargetEntity, orderMsg.Order.Prefab?.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: orderMsg.Sender);
|
{
|
||||||
break;
|
switch (orderTargetType)
|
||||||
case Order.OrderTargetType.Position:
|
{
|
||||||
order = new Order(orderMsg.Order.Prefab, orderTargetPosition, orderGiver: orderMsg.Sender);
|
case Order.OrderTargetType.Entity:
|
||||||
break;
|
if (!(orderTargetEntity is IIgnorable ignorableEntity)) { break; }
|
||||||
|
ignorableEntity.OrderedToBeIgnored = order.Identifier == "ignorethis";
|
||||||
|
break;
|
||||||
|
case Order.OrderTargetType.Position:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
case Order.OrderTargetType.WallSection:
|
||||||
|
if (!wallSectionIndex.HasValue) { break; }
|
||||||
|
if (!(orderTargetEntity is Structure s)) { break; }
|
||||||
|
if (!(s.GetSection(wallSectionIndex.Value) is IIgnorable ignorableWall)) { break; }
|
||||||
|
ignorableWall.OrderedToBeIgnored = order.Identifier == "ignorethis";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GameMain.GameSession?.CrewManager?.AddOrder(order, order.IsIgnoreOrder ? (float?)null : order.FadeOutTime);
|
||||||
}
|
}
|
||||||
if (order != null)
|
else if (orderTargetCharacter != null)
|
||||||
{
|
{
|
||||||
orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.OrderPriority, orderMsg.Sender);
|
orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.OrderPriority, orderMsg.Sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (orderMsg.Order.IsIgnoreOrder)
|
|
||||||
{
|
|
||||||
switch (orderTargetType)
|
|
||||||
{
|
|
||||||
case Order.OrderTargetType.Entity:
|
|
||||||
if (orderTargetEntity is IIgnorable ignorableEntity)
|
|
||||||
{
|
|
||||||
ignorableEntity.OrderedToBeIgnored = orderMsg.Order.Identifier == "ignorethis";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Order.OrderTargetType.WallSection:
|
|
||||||
if (!wallSectionIndex.HasValue) { break; }
|
|
||||||
if (orderTargetEntity is Structure s && s.GetSection(wallSectionIndex.Value) is IIgnorable ignorableWall)
|
|
||||||
{
|
|
||||||
ignorableWall.OrderedToBeIgnored = orderMsg.Order.Identifier == "ignorethis";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GameMain.Server.SendOrderChatMessage(orderMsg);
|
GameMain.Server.SendOrderChatMessage(orderMsg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -537,7 +537,8 @@ namespace Barotrauma.Networking
|
|||||||
initiatedStartGame = false;
|
initiatedStartGame = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Screen.Selected == GameMain.NetLobbyScreen && !gameStarted && !initiatedStartGame)
|
else if (Screen.Selected == GameMain.NetLobbyScreen && !gameStarted && !initiatedStartGame &&
|
||||||
|
(GameMain.NetLobbyScreen.SelectedMode != GameModePreset.MultiPlayerCampaign || GameMain.GameSession?.GameMode is MultiPlayerCampaign))
|
||||||
{
|
{
|
||||||
if (serverSettings.AutoRestart)
|
if (serverSettings.AutoRestart)
|
||||||
{
|
{
|
||||||
@@ -1207,6 +1208,7 @@ namespace Barotrauma.Networking
|
|||||||
mpCampaign.ServerReadCrew(inc, sender);
|
mpCampaign.ServerReadCrew(inc, sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadReadyToSpawnMessage(IReadMessage inc, Client sender)
|
private void ReadReadyToSpawnMessage(IReadMessage inc, Client sender)
|
||||||
{
|
{
|
||||||
sender.SpectateOnly = inc.ReadBoolean() && (serverSettings.AllowSpectating || sender.Connection == OwnerConnection);
|
sender.SpectateOnly = inc.ReadBoolean() && (serverSettings.AllowSpectating || sender.Connection == OwnerConnection);
|
||||||
@@ -1315,6 +1317,12 @@ namespace Barotrauma.Networking
|
|||||||
if (gameStarted)
|
if (gameStarted)
|
||||||
{
|
{
|
||||||
Log("Client \"" + GameServer.ClientLogName(sender) + "\" ended the round.", ServerLog.MessageType.ServerMessage);
|
Log("Client \"" + GameServer.ClientLogName(sender) + "\" ended the round.", ServerLog.MessageType.ServerMessage);
|
||||||
|
if (mpCampaign != null && Level.IsLoadedOutpost)
|
||||||
|
{
|
||||||
|
mpCampaign.SaveInventories();
|
||||||
|
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
||||||
|
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||||
|
}
|
||||||
EndGame();
|
EndGame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1492,7 +1500,6 @@ namespace Barotrauma.Networking
|
|||||||
inc.ReadPadBits();
|
inc.ReadPadBits();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ClientWrite(Client c)
|
private void ClientWrite(Client c)
|
||||||
{
|
{
|
||||||
if (gameStarted && c.InGame)
|
if (gameStarted && c.InGame)
|
||||||
@@ -2251,10 +2258,6 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
client.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, client.Name);
|
client.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, client.Name);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
client.CharacterInfo.ClearCurrentOrders();
|
|
||||||
}
|
|
||||||
characterInfos.Add(client.CharacterInfo);
|
characterInfos.Add(client.CharacterInfo);
|
||||||
if (client.CharacterInfo.Job == null || client.CharacterInfo.Job.Prefab != client.AssignedJob.First)
|
if (client.CharacterInfo.Job == null || client.CharacterInfo.Job.Prefab != client.AssignedJob.First)
|
||||||
{
|
{
|
||||||
@@ -2340,7 +2343,8 @@ namespace Barotrauma.Networking
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
characterData.SpawnInventoryItems(spawnedCharacter, spawnedCharacter.Inventory);
|
characterData.SpawnInventoryItems(spawnedCharacter, spawnedCharacter.Inventory);
|
||||||
characterData.ApplyHealthData(spawnedCharacter.Info, spawnedCharacter);
|
characterData.ApplyHealthData(spawnedCharacter);
|
||||||
|
characterData.ApplyOrderData(spawnedCharacter);
|
||||||
spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]);
|
spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]);
|
||||||
characterData.HasSpawned = true;
|
characterData.HasSpawned = true;
|
||||||
}
|
}
|
||||||
@@ -2362,7 +2366,7 @@ namespace Barotrauma.Networking
|
|||||||
if (hadBots)
|
if (hadBots)
|
||||||
{
|
{
|
||||||
//loaded existing bots -> init them
|
//loaded existing bots -> init them
|
||||||
crewManager?.InitRound();
|
crewManager.InitRound();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2372,6 +2376,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
|
|
||||||
campaign?.LoadPets();
|
campaign?.LoadPets();
|
||||||
|
crewManager?.LoadActiveOrders();
|
||||||
|
|
||||||
foreach (Submarine sub in Submarine.MainSubs)
|
foreach (Submarine sub in Submarine.MainSubs)
|
||||||
{
|
{
|
||||||
@@ -2516,6 +2521,8 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
mission.ServerWriteInitial(msg, client);
|
mission.ServerWriteInitial(msg, client);
|
||||||
}
|
}
|
||||||
|
msg.Write(GameMain.GameSession.CrewManager != null);
|
||||||
|
GameMain.GameSession.CrewManager?.ServerWriteActiveOrders(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EndGame(CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
|
public void EndGame(CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
|
||||||
@@ -3314,7 +3321,6 @@ namespace Barotrauma.Networking
|
|||||||
serverSettings.SaveClientPermissions();
|
serverSettings.SaveClientPermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private IEnumerable<object> SendClientPermissionsAfterClientListSynced(Client recipient, Client client)
|
private IEnumerable<object> SendClientPermissionsAfterClientListSynced(Client recipient, Client client)
|
||||||
{
|
{
|
||||||
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
|
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
|
||||||
@@ -3331,7 +3337,6 @@ namespace Barotrauma.Networking
|
|||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void SendClientPermissions(Client recipient, Client client)
|
private void SendClientPermissions(Client recipient, Client client)
|
||||||
{
|
{
|
||||||
if (recipient?.Connection == null) { return; }
|
if (recipient?.Connection == null) { return; }
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
private DateTime despawnTime;
|
private DateTime despawnTime;
|
||||||
|
|
||||||
|
private float shuttleEmptyTimer;
|
||||||
|
|
||||||
|
private int pendingRespawnCount, requiredRespawnCount;
|
||||||
|
private int prevPendingRespawnCount, prevRequiredRespawnCount;
|
||||||
|
|
||||||
private IEnumerable<Client> GetClientsToRespawn()
|
private IEnumerable<Client> GetClientsToRespawn()
|
||||||
{
|
{
|
||||||
MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign;
|
MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign;
|
||||||
@@ -95,10 +100,19 @@ namespace Barotrauma.Networking
|
|||||||
RespawnShuttle.Velocity = Vector2.Zero;
|
RespawnShuttle.Velocity = Vector2.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
int clientsToRespawn = GetClientsToRespawn().Count();
|
pendingRespawnCount = GetClientsToRespawn().Count();
|
||||||
|
requiredRespawnCount = (int)Math.Max((float)GameMain.Server.ConnectedClients.Count * GameMain.Server.ServerSettings.MinRespawnRatio, 1.0f);
|
||||||
|
if (pendingRespawnCount != prevPendingRespawnCount ||
|
||||||
|
requiredRespawnCount != prevRequiredRespawnCount)
|
||||||
|
{
|
||||||
|
prevPendingRespawnCount = pendingRespawnCount;
|
||||||
|
prevRequiredRespawnCount = requiredRespawnCount;
|
||||||
|
GameMain.Server.CreateEntityEvent(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (RespawnCountdownStarted)
|
if (RespawnCountdownStarted)
|
||||||
{
|
{
|
||||||
if (clientsToRespawn == 0)
|
if (pendingRespawnCount == 0)
|
||||||
{
|
{
|
||||||
RespawnCountdownStarted = false;
|
RespawnCountdownStarted = false;
|
||||||
GameMain.Server.CreateEntityEvent(this);
|
GameMain.Server.CreateEntityEvent(this);
|
||||||
@@ -106,7 +120,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool shouldStartCountdown = ShouldStartRespawnCountdown(clientsToRespawn);
|
bool shouldStartCountdown = ShouldStartRespawnCountdown(pendingRespawnCount);
|
||||||
if (shouldStartCountdown)
|
if (shouldStartCountdown)
|
||||||
{
|
{
|
||||||
RespawnCountdownStarted = true;
|
RespawnCountdownStarted = true;
|
||||||
@@ -167,8 +181,14 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void UpdateReturningProjSpecific()
|
partial void UpdateReturningProjSpecific(float deltaTime)
|
||||||
{
|
{
|
||||||
|
//speed up despawning if there's no-one inside the shuttle
|
||||||
|
if (despawnTime > DateTime.Now + new TimeSpan(0, 0, seconds: 30) && CheckShuttleEmpty(deltaTime))
|
||||||
|
{
|
||||||
|
despawnTime = DateTime.Now + new TimeSpan(0, 0, seconds: 30);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (Door door in shuttleDoors)
|
foreach (Door door in shuttleDoors)
|
||||||
{
|
{
|
||||||
if (door.IsOpen) door.TrySetState(false, false, true);
|
if (door.IsOpen) door.TrySetState(false, false, true);
|
||||||
@@ -214,7 +234,7 @@ namespace Barotrauma.Networking
|
|||||||
if (!ReturnCountdownStarted)
|
if (!ReturnCountdownStarted)
|
||||||
{
|
{
|
||||||
//if there are no living chracters inside, transporting can be stopped immediately
|
//if there are no living chracters inside, transporting can be stopped immediately
|
||||||
if (!Character.CharacterList.Any(c => c.Submarine == RespawnShuttle && !c.IsDead))
|
if (CheckShuttleEmpty(deltaTime))
|
||||||
{
|
{
|
||||||
ReturnTime = DateTime.Now;
|
ReturnTime = DateTime.Now;
|
||||||
ReturnCountdownStarted = true;
|
ReturnCountdownStarted = true;
|
||||||
@@ -232,6 +252,10 @@ namespace Barotrauma.Networking
|
|||||||
GameMain.Server.CreateEntityEvent(this);
|
GameMain.Server.CreateEntityEvent(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (CheckShuttleEmpty(deltaTime))
|
||||||
|
{
|
||||||
|
ReturnTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
if (DateTime.Now > ReturnTime)
|
if (DateTime.Now > ReturnTime)
|
||||||
{
|
{
|
||||||
@@ -245,6 +269,19 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CheckShuttleEmpty(float deltaTime)
|
||||||
|
{
|
||||||
|
if (!Character.CharacterList.Any(c => c.Submarine == RespawnShuttle && !c.IsDead))
|
||||||
|
{
|
||||||
|
shuttleEmptyTimer += deltaTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shuttleEmptyTimer = 0.0f;
|
||||||
|
}
|
||||||
|
return shuttleEmptyTimer > 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
partial void RespawnCharactersProjSpecific(Vector2? shuttlePos)
|
partial void RespawnCharactersProjSpecific(Vector2? shuttlePos)
|
||||||
{
|
{
|
||||||
var respawnSub = RespawnShuttle ?? Submarine.MainSub;
|
var respawnSub = RespawnShuttle ?? Submarine.MainSub;
|
||||||
@@ -394,7 +431,7 @@ namespace Barotrauma.Networking
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
characterData.SpawnInventoryItems(character, character.Inventory);
|
characterData.SpawnInventoryItems(character, character.Inventory);
|
||||||
characterData.ApplyHealthData(character.Info, character);
|
characterData.ApplyHealthData(character);
|
||||||
character.GiveIdCardTags(mainSubSpawnPoints[i]);
|
character.GiveIdCardTags(mainSubSpawnPoints[i]);
|
||||||
characterData.HasSpawned = true;
|
characterData.HasSpawned = true;
|
||||||
}
|
}
|
||||||
@@ -427,6 +464,8 @@ namespace Barotrauma.Networking
|
|||||||
msg.Write((float)(ReturnTime - DateTime.Now).TotalSeconds);
|
msg.Write((float)(ReturnTime - DateTime.Now).TotalSeconds);
|
||||||
break;
|
break;
|
||||||
case State.Waiting:
|
case State.Waiting:
|
||||||
|
msg.Write((ushort)pendingRespawnCount);
|
||||||
|
msg.Write((ushort)requiredRespawnCount);
|
||||||
msg.Write(RespawnCountdownStarted);
|
msg.Write(RespawnCountdownStarted);
|
||||||
msg.Write((float)(RespawnTime - DateTime.Now).TotalSeconds);
|
msg.Write((float)(RespawnTime - DateTime.Now).TotalSeconds);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ namespace Barotrauma
|
|||||||
targetItems.Add(item);
|
targetItems.Add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//only target items in the main sub if there are any
|
||||||
|
if (targetItems.Count > 1 && targetItems.Any(it => it.Submarine == Submarine.MainSub))
|
||||||
|
{
|
||||||
|
targetItems.RemoveAll(it => it.Submarine != Submarine.MainSub);
|
||||||
|
}
|
||||||
if (targetItems.Count > 0)
|
if (targetItems.Count > 0)
|
||||||
{
|
{
|
||||||
var textId = targetItems[0].Prefab.GetItemNameTextId();
|
var textId = targetItems[0].Prefab.GetItemNameTextId();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.13.3.11</Version>
|
<Version>0.1400.0.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -38,10 +38,13 @@
|
|||||||
<Item file="Content/Items/Reactor/reactor.xml" />
|
<Item file="Content/Items/Reactor/reactor.xml" />
|
||||||
<Item file="Content/Items/Tools/tools.xml" />
|
<Item file="Content/Items/Tools/tools.xml" />
|
||||||
<Item file="Content/Items/Weapons/coilgun.xml" />
|
<Item file="Content/Items/Weapons/coilgun.xml" />
|
||||||
|
<Item file="Content/Items/Weapons/chaingun.xml" />
|
||||||
<Item file="Content/Items/Weapons/depthcharge.xml" />
|
<Item file="Content/Items/Weapons/depthcharge.xml" />
|
||||||
<Item file="Content/Items/Weapons/dischargecoil.xml" />
|
<Item file="Content/Items/Weapons/dischargecoil.xml" />
|
||||||
<Item file="Content/Items/Weapons/explosives.xml" />
|
<Item file="Content/Items/Weapons/explosives.xml" />
|
||||||
|
<Item file="Content/Items/Weapons/pulselaser.xml" />
|
||||||
<Item file="Content/Items/Weapons/railgun.xml" />
|
<Item file="Content/Items/Weapons/railgun.xml" />
|
||||||
|
<Item file="Content/Items/Weapons/turrethardpoint.xml" />
|
||||||
<Item file="Content/Items/Weapons/weapons.xml" />
|
<Item file="Content/Items/Weapons/weapons.xml" />
|
||||||
<Item file="Content/Items/Legacy/legacycommand.xml" />
|
<Item file="Content/Items/Legacy/legacycommand.xml" />
|
||||||
<Item file="Content/Items/Legacy/legacycontainers.xml" />
|
<Item file="Content/Items/Legacy/legacycontainers.xml" />
|
||||||
@@ -59,6 +62,7 @@
|
|||||||
<Item file="Content/Items/Gardening/growableplants.xml" />
|
<Item file="Content/Items/Gardening/growableplants.xml" />
|
||||||
<Item file="Content/Items/Gardening/gardeningtools.xml" />
|
<Item file="Content/Items/Gardening/gardeningtools.xml" />
|
||||||
<Item file="Content/Items/Gardening/plantproducts.xml" />
|
<Item file="Content/Items/Gardening/plantproducts.xml" />
|
||||||
|
<Item file="Content/Map/Pirates/PirateItems.xml" />
|
||||||
<Character file="Content/Characters/Balloon/Balloon.xml" />
|
<Character file="Content/Characters/Balloon/Balloon.xml" />
|
||||||
<Character file="Content/Characters/Carrier/Carrier.xml" />
|
<Character file="Content/Characters/Carrier/Carrier.xml" />
|
||||||
<Character file="Content/Characters/Charybdis/Charybdis.xml" />
|
<Character file="Content/Characters/Charybdis/Charybdis.xml" />
|
||||||
@@ -144,6 +148,7 @@
|
|||||||
<Afflictions file="Content/Afflictions.xml" />
|
<Afflictions file="Content/Afflictions.xml" />
|
||||||
<Structure file="Content/Map/StructurePrefabs.xml" />
|
<Structure file="Content/Map/StructurePrefabs.xml" />
|
||||||
<Structure file="Content/Map/Outposts/OutpostStructurePrefabs.xml" />
|
<Structure file="Content/Map/Outposts/OutpostStructurePrefabs.xml" />
|
||||||
|
<Structure file="Content/Map/Pirates/PirateAssets.xml" />
|
||||||
<Item file="Content/Map/Outposts/OutpostItems.xml" />
|
<Item file="Content/Map/Outposts/OutpostItems.xml" />
|
||||||
<Structure file="Content/Items/Shipwrecks/StructurePrefabsWrecked.xml" />
|
<Structure file="Content/Items/Shipwrecks/StructurePrefabsWrecked.xml" />
|
||||||
<Structure file="Content/Map/Thalamus/thalamusstructures.xml" />
|
<Structure file="Content/Map/Thalamus/thalamusstructures.xml" />
|
||||||
@@ -252,4 +257,5 @@
|
|||||||
<OutpostModule file="Content/Map/Outposts/MineModule_04.sub" />
|
<OutpostModule file="Content/Map/Outposts/MineModule_04.sub" />
|
||||||
<OutpostModule file="Content/Map/Outposts/HallModuleHorizontal_Abandoned.sub" />
|
<OutpostModule file="Content/Map/Outposts/HallModuleHorizontal_Abandoned.sub" />
|
||||||
<OutpostModule file="Content/Map/Outposts/HallModuleVertical_Abandoned.sub" />
|
<OutpostModule file="Content/Map/Outposts/HallModuleVertical_Abandoned.sub" />
|
||||||
|
<EnemySubmarine file="Content/Map/EnemySubmarines/HumpbackPirate.sub"/>
|
||||||
</contentpackage>
|
</contentpackage>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
public class CachedDistance
|
||||||
|
{
|
||||||
|
public readonly Vector2 StartWorldPos;
|
||||||
|
public readonly Vector2 EndWorldPos;
|
||||||
|
public readonly float Distance;
|
||||||
|
public double RecalculationTime;
|
||||||
|
|
||||||
|
public CachedDistance(Vector2 startWorldPos, Vector2 endWorldPos, float dist, double recalculationTime)
|
||||||
|
{
|
||||||
|
StartWorldPos = startWorldPos;
|
||||||
|
EndWorldPos = endWorldPos;
|
||||||
|
Distance = dist;
|
||||||
|
RecalculationTime = recalculationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldUpdateDistance(Vector2 currentStartWorldPos, Vector2 currentEndWorldPos, float minDistanceToUpdate = 500.0f)
|
||||||
|
{
|
||||||
|
if (Timing.TotalTime < RecalculationTime) { return false; }
|
||||||
|
float minDistSquared = minDistanceToUpdate * minDistanceToUpdate;
|
||||||
|
return Vector2.DistanceSquared(StartWorldPos, currentStartWorldPos) > minDistSquared ||
|
||||||
|
Vector2.DistanceSquared(EndWorldPos, currentEndWorldPos) > minDistSquared;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -73,6 +73,8 @@ namespace Barotrauma
|
|||||||
get { return true; }
|
get { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool IsMentallyUnstable => false;
|
||||||
|
|
||||||
private IEnumerable<Hull> visibleHulls;
|
private IEnumerable<Hull> visibleHulls;
|
||||||
private float hullVisibilityTimer;
|
private float hullVisibilityTimer;
|
||||||
const float hullVisibilityInterval = 0.5f;
|
const float hullVisibilityInterval = 0.5f;
|
||||||
@@ -215,10 +217,26 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly HashSet<Item> unequippedItems = new HashSet<Item>();
|
private readonly HashSet<Item> unequippedItems = new HashSet<Item>();
|
||||||
public bool TakeItem(Item item, Inventory targetInventory, bool equip, bool dropOtherIfCannotMove = true, bool allowSwapping = false, bool storeUnequipped = false)
|
public bool TakeItem(Item item, CharacterInventory targetInventory, bool equip, bool wear = false, bool dropOtherIfCannotMove = true, bool allowSwapping = false, bool storeUnequipped = false)
|
||||||
{
|
{
|
||||||
var pickable = item.GetComponent<Pickable>();
|
var pickable = item.GetComponent<Pickable>();
|
||||||
if (pickable == null) { return false; }
|
if (pickable == null) { return false; }
|
||||||
|
if (wear)
|
||||||
|
{
|
||||||
|
var wearable = item.GetComponent<Wearable>();
|
||||||
|
if (wearable != null)
|
||||||
|
{
|
||||||
|
pickable = wearable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var holdable = item.GetComponent<Holdable>();
|
||||||
|
if (holdable != null)
|
||||||
|
{
|
||||||
|
pickable = holdable;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (item.ParentInventory is ItemInventory itemInventory)
|
if (item.ParentInventory is ItemInventory itemInventory)
|
||||||
{
|
{
|
||||||
if (!itemInventory.Container.HasRequiredItems(Character, addMessage: false)) { return false; }
|
if (!itemInventory.Container.HasRequiredItems(Character, addMessage: false)) { return false; }
|
||||||
@@ -302,7 +320,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (item != null && !item.Removed && Character.HasItem(item))
|
if (item != null && !item.Removed && Character.HasItem(item))
|
||||||
{
|
{
|
||||||
TakeItem(item, Character.Inventory, equip: true, dropOtherIfCannotMove: true, allowSwapping: true, storeUnequipped: false);
|
TakeItem(item, Character.Inventory, equip: true, wear: true, dropOtherIfCannotMove: true, allowSwapping: true, storeUnequipped: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unequippedItems.Clear();
|
unequippedItems.Clear();
|
||||||
|
|||||||
@@ -144,21 +144,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
if (Static)
|
|
||||||
{
|
|
||||||
SightRange = MaxSightRange;
|
|
||||||
SoundRange = MaxSoundRange;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Non-static ai targets must be kept alive by a custom logic (e.g. item components)
|
|
||||||
SightRange = StaticSight ? MaxSightRange : MinSightRange;
|
|
||||||
SoundRange = StaticSound ? MaxSoundRange : MinSoundRange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AITarget(Entity e, XElement element) : this(e)
|
public AITarget(Entity e, XElement element) : this(e)
|
||||||
{
|
{
|
||||||
SightRange = element.GetAttributeFloat("sightrange", 0.0f);
|
SightRange = element.GetAttributeFloat("sightrange", 0.0f);
|
||||||
@@ -242,5 +227,20 @@ namespace Barotrauma
|
|||||||
List.Remove(this);
|
List.Remove(this);
|
||||||
entity = null;
|
entity = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
if (Static)
|
||||||
|
{
|
||||||
|
SightRange = MaxSightRange;
|
||||||
|
SoundRange = MaxSoundRange;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Non-static ai targets must be kept alive by a custom logic (e.g. item components)
|
||||||
|
SightRange = StaticSight ? MaxSightRange : MinSightRange;
|
||||||
|
SoundRange = StaticSound ? MaxSoundRange : MinSoundRange;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ namespace Barotrauma
|
|||||||
SelectedAiTarget = target;
|
SelectedAiTarget = target;
|
||||||
selectedTargetMemory = GetTargetMemory(target, true);
|
selectedTargetMemory = GetTargetMemory(target, true);
|
||||||
selectedTargetMemory.Priority = priority;
|
selectedTargetMemory.Priority = priority;
|
||||||
|
ignoredTargets.Remove(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float movementMargin;
|
private float movementMargin;
|
||||||
@@ -496,7 +497,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AIParams.Infiltrate)
|
if (AIParams.CanOpenDoors)
|
||||||
{
|
{
|
||||||
bool IsCloseEnoughToTargetSub(float threshold) => SelectedAiTarget?.Entity?.Submarine is Submarine sub && sub != null && Vector2.DistanceSquared(Character.WorldPosition, sub.WorldPosition) < MathUtils.Pow(Math.Max(sub.Borders.Size.X, sub.Borders.Size.Y) / 2 + threshold, 2);
|
bool IsCloseEnoughToTargetSub(float threshold) => SelectedAiTarget?.Entity?.Submarine is Submarine sub && sub != null && Vector2.DistanceSquared(Character.WorldPosition, sub.WorldPosition) < MathUtils.Pow(Math.Max(sub.Borders.Size.X, sub.Borders.Size.Y) / 2 + threshold, 2);
|
||||||
|
|
||||||
@@ -787,7 +788,7 @@ namespace Barotrauma
|
|||||||
if (pathSteering != null && !Character.AnimController.InWater)
|
if (pathSteering != null && !Character.AnimController.InWater)
|
||||||
{
|
{
|
||||||
// Wander around inside
|
// Wander around inside
|
||||||
pathSteering.Wander(deltaTime, ConvertUnits.ToDisplayUnits(colliderLength), stayStillInTightSpace: false);
|
pathSteering.Wander(deltaTime, Math.Max(ConvertUnits.ToDisplayUnits(colliderLength), 100.0f), stayStillInTightSpace: false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1203,7 +1204,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
canAttack = AttackingLimb != null && AttackingLimb.attack.CoolDownTimer <= 0;
|
canAttack = AttackingLimb != null && AttackingLimb.attack.CoolDownTimer <= 0;
|
||||||
}
|
}
|
||||||
if (!AIParams.Infiltrate)
|
if (!AIParams.CanOpenDoors)
|
||||||
{
|
{
|
||||||
if (!Character.AnimController.SimplePhysicsEnabled && SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null && (!canAttackDoors || !canAttackWalls || !AIParams.TargetOuterWalls))
|
if (!Character.AnimController.SimplePhysicsEnabled && SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null && (!canAttackDoors || !canAttackWalls || !AIParams.TargetOuterWalls))
|
||||||
{
|
{
|
||||||
@@ -1777,6 +1778,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (!isFriendly && attackResult.Damage > 0.0f)
|
if (!isFriendly && attackResult.Damage > 0.0f)
|
||||||
{
|
{
|
||||||
|
ignoredTargets.Remove(attacker.AiTarget);
|
||||||
bool canAttack = attacker.Submarine == Character.Submarine && canAttackCharacters || attacker.Submarine != null && canAttackWalls;
|
bool canAttack = attacker.Submarine == Character.Submarine && canAttackCharacters || attacker.Submarine != null && canAttackWalls;
|
||||||
if (AIParams.AttackWhenProvoked && canAttack)
|
if (AIParams.AttackWhenProvoked && canAttack)
|
||||||
{
|
{
|
||||||
@@ -1893,16 +1895,28 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
//simulate attack input to get the character to attack client-side
|
//simulate attack input to get the character to attack client-side
|
||||||
Character.SetInput(InputType.Attack, true, true);
|
Character.SetInput(InputType.Attack, true, true);
|
||||||
|
#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
|
||||||
|
});
|
||||||
|
#endif
|
||||||
if (attackingLimb.UpdateAttack(deltaTime, attackSimPos, damageTarget, out AttackResult attackResult, distance, targetLimb))
|
if (attackingLimb.UpdateAttack(deltaTime, attackSimPos, damageTarget, out AttackResult attackResult, distance, targetLimb))
|
||||||
{
|
{
|
||||||
if (damageTarget.Health > 0)
|
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
|
// 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;
|
selectedTargetMemory.Priority += GetRelativeDamage(attackResult.Damage, damageTarget.Health) * AIParams.AggressionGreed;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
selectedTargetMemory.Priority = 0;
|
selectedTargetMemory.Priority -= Math.Max(selectedTargetMemory.Priority / 2, 1);
|
||||||
|
return selectedTargetMemory.Priority > 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -2184,7 +2198,7 @@ namespace Barotrauma
|
|||||||
bool targetingFromOutsideToInside = item.CurrentHull != null && character.CurrentHull == null;
|
bool targetingFromOutsideToInside = item.CurrentHull != null && character.CurrentHull == null;
|
||||||
if (targetingFromOutsideToInside)
|
if (targetingFromOutsideToInside)
|
||||||
{
|
{
|
||||||
if (door != null && (!canAttackDoors && !AIParams.Infiltrate) || !canAttackWalls)
|
if (door != null && (!canAttackDoors && !AIParams.CanOpenDoors) || !canAttackWalls)
|
||||||
{
|
{
|
||||||
// Can't reach
|
// Can't reach
|
||||||
continue;
|
continue;
|
||||||
@@ -2610,7 +2624,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
wallTarget = null;
|
wallTarget = null;
|
||||||
if (State == AIState.Flee || State == AIState.Escape) { return; }
|
if (State == AIState.Flee || State == AIState.Escape) { return; }
|
||||||
if (AIParams.Infiltrate && HasValidPath(requireNonDirty: true)) { return; }
|
if (AIParams.CanOpenDoors && HasValidPath(requireNonDirty: true)) { return; }
|
||||||
if (SelectedAiTarget == null) { return; }
|
if (SelectedAiTarget == null) { return; }
|
||||||
if (SelectedAiTarget.Entity == null) { return; }
|
if (SelectedAiTarget.Entity == null) { return; }
|
||||||
Vector2 rayStart = SimPosition;
|
Vector2 rayStart = SimPosition;
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ namespace Barotrauma
|
|||||||
private float flipTimer;
|
private float flipTimer;
|
||||||
private const float FlipInterval = 0.5f;
|
private const float FlipInterval = 0.5f;
|
||||||
|
|
||||||
|
private float teamChangeTimer;
|
||||||
|
private const float TeamChangeInterval = 0.5f;
|
||||||
|
|
||||||
public const float HULL_SAFETY_THRESHOLD = 40;
|
public const float HULL_SAFETY_THRESHOLD = 40;
|
||||||
public const float HULL_LOW_OXYGEN_PERCENTAGE = 30;
|
public const float HULL_LOW_OXYGEN_PERCENTAGE = 30;
|
||||||
|
|
||||||
@@ -121,6 +124,32 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MentalStateManager MentalStateManager { get; private set; }
|
||||||
|
|
||||||
|
public void InitMentalStateManager()
|
||||||
|
{
|
||||||
|
if (MentalStateManager == null)
|
||||||
|
{
|
||||||
|
MentalStateManager = new MentalStateManager(Character, this);
|
||||||
|
}
|
||||||
|
MentalStateManager.Active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsMentallyUnstable =>
|
||||||
|
MentalStateManager?.CurrentMentalType != MentalStateManager.MentalType.Normal &&
|
||||||
|
MentalStateManager?.CurrentMentalType != MentalStateManager.MentalType.Confused;
|
||||||
|
|
||||||
|
public ShipCommandManager ShipCommandManager { get; private set; }
|
||||||
|
|
||||||
|
public void InitShipCommandManager()
|
||||||
|
{
|
||||||
|
if (ShipCommandManager == null)
|
||||||
|
{
|
||||||
|
ShipCommandManager = new ShipCommandManager(Character);
|
||||||
|
}
|
||||||
|
ShipCommandManager.Active = true;
|
||||||
|
}
|
||||||
|
|
||||||
public HumanAIController(Character c) : base(c)
|
public HumanAIController(Character c) : base(c)
|
||||||
{
|
{
|
||||||
if (!c.IsHuman)
|
if (!c.IsHuman)
|
||||||
@@ -204,9 +233,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Character.Submarine == null || !IsOnFriendlyTeam(Character.TeamID, Character.Submarine.TeamID))
|
|
||||||
|
if (Character.Submarine == null || !IsOnFriendlyTeam(Character.TeamID, Character.Submarine.TeamID) && !Character.IsEscorted)
|
||||||
{
|
{
|
||||||
// Spot enemies while staying outside or inside an enemy ship.
|
// Spot enemies while staying outside or inside an enemy ship.
|
||||||
|
// does not apply for escorted characters, such as prisoners or terrorists who have their own behavior
|
||||||
enemycheckTimer -= deltaTime;
|
enemycheckTimer -= deltaTime;
|
||||||
if (enemycheckTimer < 0)
|
if (enemycheckTimer < 0)
|
||||||
{
|
{
|
||||||
@@ -287,6 +318,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Character.UpdateTeam();
|
||||||
|
|
||||||
if (Character.CurrentHull != null)
|
if (Character.CurrentHull != null)
|
||||||
{
|
{
|
||||||
if (Character.IsOnPlayerTeam)
|
if (Character.IsOnPlayerTeam)
|
||||||
@@ -301,7 +334,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (Character.SpeechImpediment < 100.0f)
|
if (Character.SpeechImpediment < 100.0f)
|
||||||
{
|
{
|
||||||
if (Character.Submarine != null && Character.Submarine.TeamID == Character.TeamID && !Character.Submarine.Info.IsWreck)
|
if (Character.Submarine != null && (Character.Submarine.TeamID == Character.TeamID || Character.IsEscorted) && !Character.Submarine.Info.IsWreck)
|
||||||
{
|
{
|
||||||
ReportProblems();
|
ReportProblems();
|
||||||
}
|
}
|
||||||
@@ -314,7 +347,7 @@ namespace Barotrauma
|
|||||||
if (objectiveManager.CurrentObjective == null) { return; }
|
if (objectiveManager.CurrentObjective == null) { return; }
|
||||||
|
|
||||||
objectiveManager.DoCurrentObjective(deltaTime);
|
objectiveManager.DoCurrentObjective(deltaTime);
|
||||||
bool run = objectiveManager.CurrentObjective.ForceRun || objectiveManager.GetCurrentPriority() > AIObjectiveManager.RunPriority;
|
bool run = objectiveManager.CurrentObjective.ForceRun || !objectiveManager.CurrentObjective.ForceWalk && objectiveManager.GetCurrentPriority() > AIObjectiveManager.RunPriority;
|
||||||
if (ObjectiveManager.CurrentObjective is AIObjectiveGoTo goTo && goTo.Target != null)
|
if (ObjectiveManager.CurrentObjective is AIObjectiveGoTo goTo && goTo.Target != null)
|
||||||
{
|
{
|
||||||
if (Character.CurrentHull == null)
|
if (Character.CurrentHull == null)
|
||||||
@@ -395,6 +428,9 @@ namespace Barotrauma
|
|||||||
flipTimer = FlipInterval;
|
flipTimer = FlipInterval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MentalStateManager?.Update(deltaTime);
|
||||||
|
ShipCommandManager?.Update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnequipUnnecessaryItems()
|
private void UnequipUnnecessaryItems()
|
||||||
@@ -442,9 +478,8 @@ namespace Barotrauma
|
|||||||
Character.AnimController.InWater ||
|
Character.AnimController.InWater ||
|
||||||
Character.AnimController.HeadInWater ||
|
Character.AnimController.HeadInWater ||
|
||||||
Character.CurrentHull == null ||
|
Character.CurrentHull == null ||
|
||||||
Character.Submarine?.TeamID != Character.TeamID ||
|
(Character.Submarine.TeamID != Character.TeamID && !Character.IsEscorted) || // these instances should maybe be combined to a method
|
||||||
ObjectiveManager.IsCurrentObjective<AIObjectiveFindSafety>() ||
|
ObjectiveManager.IsCurrentObjective<AIObjectiveFindSafety>() ||
|
||||||
ObjectiveManager.CurrentOrder is AIObjectiveGoTo goTo && goTo.Target == Character || // wait order
|
|
||||||
ObjectiveManager.CurrentObjective.GetSubObjectivesRecursive(true).Any(o => o.KeepDivingGearOn);
|
ObjectiveManager.CurrentObjective.GetSubObjectivesRecursive(true).Any(o => o.KeepDivingGearOn);
|
||||||
if (oxygenLow && Character.CurrentHull.Oxygen > 0)
|
if (oxygenLow && Character.CurrentHull.Oxygen > 0)
|
||||||
{
|
{
|
||||||
@@ -454,7 +489,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
shouldKeepTheGearOn = true;
|
shouldKeepTheGearOn = true;
|
||||||
}
|
}
|
||||||
bool removeDivingSuit = !shouldKeepTheGearOn;
|
bool removeDivingSuit = !shouldKeepTheGearOn && Character.Submarine?.TeamID == Character.TeamID && (!(ObjectiveManager.CurrentOrder is AIObjectiveGoTo goTo) || goTo.Target != Character);
|
||||||
bool takeMaskOff = !shouldKeepTheGearOn;
|
bool takeMaskOff = !shouldKeepTheGearOn;
|
||||||
if (!shouldKeepTheGearOn && !oxygenLow)
|
if (!shouldKeepTheGearOn && !oxygenLow)
|
||||||
{
|
{
|
||||||
@@ -505,7 +540,7 @@ namespace Barotrauma
|
|||||||
var divingSuit = Character.Inventory.FindItemByTag(AIObjectiveFindDivingGear.HEAVY_DIVING_GEAR);
|
var divingSuit = Character.Inventory.FindItemByTag(AIObjectiveFindDivingGear.HEAVY_DIVING_GEAR);
|
||||||
if (divingSuit != null)
|
if (divingSuit != null)
|
||||||
{
|
{
|
||||||
if (oxygenLow || ObjectiveManager.GetCurrentPriority() >= AIObjectiveManager.RunPriority)
|
if (oxygenLow || Character.Submarine?.TeamID != Character.TeamID || ObjectiveManager.GetCurrentPriority() >= AIObjectiveManager.RunPriority)
|
||||||
{
|
{
|
||||||
divingSuit.Drop(Character);
|
divingSuit.Drop(Character);
|
||||||
HandleRelocation(divingSuit);
|
HandleRelocation(divingSuit);
|
||||||
@@ -550,7 +585,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (!mask.AllowedSlots.Contains(InvSlotType.Any) || !Character.Inventory.TryPutItem(mask, Character, new List<InvSlotType>() { InvSlotType.Any }))
|
if (!mask.AllowedSlots.Contains(InvSlotType.Any) || !Character.Inventory.TryPutItem(mask, Character, new List<InvSlotType>() { InvSlotType.Any }))
|
||||||
{
|
{
|
||||||
if (ObjectiveManager.GetCurrentPriority() >= AIObjectiveManager.RunPriority)
|
if (Character.Submarine?.TeamID != Character.TeamID || ObjectiveManager.GetCurrentPriority() >= AIObjectiveManager.RunPriority)
|
||||||
{
|
{
|
||||||
mask.Drop(Character);
|
mask.Drop(Character);
|
||||||
HandleRelocation(mask);
|
HandleRelocation(mask);
|
||||||
@@ -603,7 +638,7 @@ namespace Barotrauma
|
|||||||
Item item = Character.Inventory.GetItemInLimbSlot(hand);
|
Item item = Character.Inventory.GetItemInLimbSlot(hand);
|
||||||
if (item == null) { continue; }
|
if (item == null) { continue; }
|
||||||
|
|
||||||
if (!item.AllowedSlots.Contains(InvSlotType.Any) || !Character.Inventory.TryPutItem(item, Character, new List<InvSlotType>() { InvSlotType.Any }))
|
if (!item.AllowedSlots.Contains(InvSlotType.Any) || !Character.Inventory.TryPutItem(item, Character, new List<InvSlotType>() { InvSlotType.Any }) && Character.Submarine?.TeamID == Character.TeamID )
|
||||||
{
|
{
|
||||||
findItemState = FindItemState.OtherItem;
|
findItemState = FindItemState.OtherItem;
|
||||||
if (FindSuitableContainer(item, out Item targetContainer))
|
if (FindSuitableContainer(item, out Item targetContainer))
|
||||||
@@ -743,6 +778,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Order newOrder = null;
|
Order newOrder = null;
|
||||||
Hull targetHull = null;
|
Hull targetHull = null;
|
||||||
|
bool speak = true;
|
||||||
if (Character.CurrentHull != null)
|
if (Character.CurrentHull != null)
|
||||||
{
|
{
|
||||||
bool isFighting = ObjectiveManager.HasActiveObjective<AIObjectiveCombat>();
|
bool isFighting = ObjectiveManager.HasActiveObjective<AIObjectiveCombat>();
|
||||||
@@ -759,6 +795,21 @@ namespace Barotrauma
|
|||||||
var orderPrefab = Order.GetPrefab("reportintruders");
|
var orderPrefab = Order.GetPrefab("reportintruders");
|
||||||
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
|
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
|
||||||
targetHull = hull;
|
targetHull = hull;
|
||||||
|
if (target.IsEscorted)
|
||||||
|
{
|
||||||
|
if (!Character.IsPrisoner && target.IsPrisoner)
|
||||||
|
{
|
||||||
|
string msg = TextManager.GetWithVariables("orderdialog.prisonerescaped", new string[] { "[roomname]" }, new string[] { targetHull.DisplayName }, new bool[] { false, true }, true);
|
||||||
|
Character.Speak(msg, ChatMessageType.Order);
|
||||||
|
speak = false;
|
||||||
|
}
|
||||||
|
else if (!IsMentallyUnstable && target.AIController.IsMentallyUnstable)
|
||||||
|
{
|
||||||
|
string msg = TextManager.GetWithVariables("orderdialog.mentalcase", new string[] { "[roomname]" }, new string[] { targetHull.DisplayName }, new bool[] { false, true }, true);
|
||||||
|
Character.Speak(msg, ChatMessageType.Order);
|
||||||
|
speak = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -771,7 +822,7 @@ namespace Barotrauma
|
|||||||
targetHull = hull;
|
targetHull = hull;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (IsBallastFloraNoticeable(Character, hull))
|
if (IsBallastFloraNoticeable(Character, hull) && newOrder == null)
|
||||||
{
|
{
|
||||||
var orderPrefab = Order.GetPrefab("reportballastflora");
|
var orderPrefab = Order.GetPrefab("reportballastflora");
|
||||||
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
|
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
|
||||||
@@ -824,20 +875,24 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (newOrder != null)
|
if (newOrder != null && speak)
|
||||||
{
|
{
|
||||||
if (Character.TeamID == CharacterTeamType.FriendlyNPC)
|
// for now, escorted characters use the report system to get targets but do not speak. escort-character specific dialogue could be implemented
|
||||||
|
if (!Character.IsEscorted)
|
||||||
{
|
{
|
||||||
Character.Speak(newOrder.GetChatMessage("", targetHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Default,
|
if (Character.TeamID == CharacterTeamType.FriendlyNPC)
|
||||||
identifier: newOrder.Prefab.Identifier + (targetHull?.DisplayName ?? "null"),
|
{
|
||||||
minDurationBetweenSimilar: 60.0f);
|
Character.Speak(newOrder.GetChatMessage("", targetHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Default,
|
||||||
}
|
identifier: newOrder.Prefab.Identifier + (targetHull?.DisplayName ?? "null"),
|
||||||
else if (Character.IsOnPlayerTeam && GameMain.GameSession?.CrewManager != null && GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime))
|
minDurationBetweenSimilar: 60.0f);
|
||||||
{
|
}
|
||||||
Character.Speak(newOrder.GetChatMessage("", targetHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Order);
|
else if (Character.IsOnPlayerTeam && GameMain.GameSession?.CrewManager != null && GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime))
|
||||||
|
{
|
||||||
|
Character.Speak(newOrder.GetChatMessage("", targetHull?.DisplayName, givingOrderToSelf: false), ChatMessageType.Order);
|
||||||
#if SERVER
|
#if SERVER
|
||||||
GameMain.Server.SendOrderChatMessage(new OrderChatMessage(newOrder, "", CharacterInfo.HighestManualOrderPriority, targetHull, null, Character));
|
GameMain.Server.SendOrderChatMessage(new OrderChatMessage(newOrder, "", CharacterInfo.HighestManualOrderPriority, targetHull, null, Character));
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -977,11 +1032,11 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float cumulativeDamage = GetDamageDoneByAttacker(attacker);
|
float cumulativeDamage = GetDamageDoneByAttacker(attacker);
|
||||||
if (!Character.IsSecurity && attacker.IsBot && Character.CombatAction == null)
|
if (!Character.IsSecurity && attacker.IsBot && !IsMentallyUnstable && !attacker.AIController.IsMentallyUnstable && Character.CombatAction == null)
|
||||||
{
|
{
|
||||||
if (cumulativeDamage > 1)
|
if (cumulativeDamage > 1)
|
||||||
{
|
{
|
||||||
// Don't retaliate on damage done by friendly NPC, because we know it's accidental
|
// Don't retaliate on damage done by friendly NPC, because we know it's accidental, unless if it's a berserking AI
|
||||||
AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, attacker);
|
AddCombatObjective(AIObjectiveCombat.CombatMode.Retreat, attacker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1039,8 +1094,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Non-friendly
|
if (Character.Submarine != null && Character.Submarine.GetConnectedSubs().Contains(attacker.Submarine))
|
||||||
InformOtherNPCs(GetDamageDoneByAttacker(attacker));
|
{
|
||||||
|
// Non-friendly
|
||||||
|
InformOtherNPCs(GetDamageDoneByAttacker(attacker));
|
||||||
|
}
|
||||||
if (Character.IsBot)
|
if (Character.IsBot)
|
||||||
{
|
{
|
||||||
AddCombatObjective(DetermineCombatMode(Character, cumulativeDamage: realDamage), attacker);
|
AddCombatObjective(DetermineCombatMode(Character, cumulativeDamage: realDamage), attacker);
|
||||||
@@ -1070,12 +1128,27 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (!IsFriendly(attacker))
|
if (!IsFriendly(attacker))
|
||||||
{
|
{
|
||||||
return c.AIController is HumanAIController humanAI &&
|
if (Character.Submarine == null)
|
||||||
|
{
|
||||||
|
// Outside -> don't react.
|
||||||
|
return AIObjectiveCombat.CombatMode.None;
|
||||||
|
}
|
||||||
|
if (!Character.Submarine.GetConnectedSubs().Contains(attacker.Submarine))
|
||||||
|
{
|
||||||
|
// Attacked from an unconnected submarine.
|
||||||
|
return Character.SelectedConstruction?.GetComponent<Turret>() != null ? AIObjectiveCombat.CombatMode.None : AIObjectiveCombat.CombatMode.Retreat;
|
||||||
|
}
|
||||||
|
return c.AIController is HumanAIController humanAI &&
|
||||||
(humanAI.ObjectiveManager.IsCurrentOrder<AIObjectiveFightIntruders>() || humanAI.ObjectiveManager.Objectives.Any(o => o is AIObjectiveFightIntruders))
|
(humanAI.ObjectiveManager.IsCurrentOrder<AIObjectiveFightIntruders>() || humanAI.ObjectiveManager.Objectives.Any(o => o is AIObjectiveFightIntruders))
|
||||||
? AIObjectiveCombat.CombatMode.Offensive : AIObjectiveCombat.CombatMode.Defensive;
|
? AIObjectiveCombat.CombatMode.Offensive : AIObjectiveCombat.CombatMode.Defensive;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (Character.Submarine == null || !Character.Submarine.GetConnectedSubs().Contains(attacker.Submarine))
|
||||||
|
{
|
||||||
|
// Outside or attacked from an unconnected submarine -> don't react.
|
||||||
|
return AIObjectiveCombat.CombatMode.None;
|
||||||
|
}
|
||||||
// If there are any enemies around, just ignore the friendly fire
|
// If there are any enemies around, just ignore the friendly fire
|
||||||
if (Character.CharacterList.Any(ch => ch.Submarine == Character.Submarine && !ch.Removed && !ch.IsDead && !ch.IsIncapacitated && !IsFriendly(ch) && VisibleHulls.Contains(ch.CurrentHull)))
|
if (Character.CharacterList.Any(ch => ch.Submarine == Character.Submarine && !ch.Removed && !ch.IsDead && !ch.IsIncapacitated && !IsFriendly(ch) && VisibleHulls.Contains(ch.CurrentHull)))
|
||||||
{
|
{
|
||||||
@@ -1090,7 +1163,7 @@ namespace Barotrauma
|
|||||||
// The guards don't react when the player attacks instigators.
|
// The guards don't react when the player attacks instigators.
|
||||||
return c.IsSecurity ? AIObjectiveCombat.CombatMode.None : (Character.CombatAction != null ? Character.CombatAction.WitnessReaction : AIObjectiveCombat.CombatMode.Retreat);
|
return c.IsSecurity ? AIObjectiveCombat.CombatMode.None : (Character.CombatAction != null ? Character.CombatAction.WitnessReaction : AIObjectiveCombat.CombatMode.Retreat);
|
||||||
}
|
}
|
||||||
else if (attacker.TeamID == CharacterTeamType.FriendlyNPC)
|
else if (attacker.TeamID == CharacterTeamType.FriendlyNPC && !(attacker.AIController.IsMentallyUnstable || attacker.AIController.IsMentallyUnstable))
|
||||||
{
|
{
|
||||||
if (c.IsSecurity)
|
if (c.IsSecurity)
|
||||||
{
|
{
|
||||||
@@ -1132,7 +1205,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddCombatObjective(AIObjectiveCombat.CombatMode mode, Character target, float delay = 0, Func<bool> abortCondition = null, Action onAbort = null, Action onCompleted = null, bool allowHoldFire = false)
|
public void AddCombatObjective(AIObjectiveCombat.CombatMode mode, Character target, float delay = 0, Func<AIObjective, bool> abortCondition = null, Action onAbort = null, Action onCompleted = null, bool allowHoldFire = false)
|
||||||
{
|
{
|
||||||
if (mode == AIObjectiveCombat.CombatMode.None) { return; }
|
if (mode == AIObjectiveCombat.CombatMode.None) { return; }
|
||||||
if (Character.IsDead || Character.IsIncapacitated || Character.Removed) { return; }
|
if (Character.IsDead || Character.IsIncapacitated || Character.Removed) { return; }
|
||||||
@@ -1168,7 +1241,7 @@ namespace Barotrauma
|
|||||||
Character.Info?.Job?.Prefab.Identifier == "watchman" ||
|
Character.Info?.Job?.Prefab.Identifier == "watchman" ||
|
||||||
Character.CurrentHull == null ||
|
Character.CurrentHull == null ||
|
||||||
Character.IsOnPlayerTeam && !target.IsPlayer && ObjectiveManager.GetActiveObjective<AIObjectiveGoTo>()?.Target is Character followTarget && followTarget.IsPlayer,
|
Character.IsOnPlayerTeam && !target.IsPlayer && ObjectiveManager.GetActiveObjective<AIObjectiveGoTo>()?.Target is Character followTarget && followTarget.IsPlayer,
|
||||||
abortCondition = abortCondition,
|
AbortCondition = abortCondition,
|
||||||
allowHoldFire = allowHoldFire,
|
allowHoldFire = allowHoldFire,
|
||||||
};
|
};
|
||||||
if (onAbort != null)
|
if (onAbort != null)
|
||||||
@@ -1190,7 +1263,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void SetForcedOrder(Order order, string option, Character orderGiver)
|
public void SetForcedOrder(Order order, string option, Character orderGiver)
|
||||||
{
|
{
|
||||||
var objective = ObjectiveManager.CreateObjective(order, option, orderGiver, false);
|
var objective = ObjectiveManager.CreateObjective(order, option, orderGiver);
|
||||||
ObjectiveManager.SetForcedOrder(objective);
|
ObjectiveManager.SetForcedOrder(objective);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1273,7 +1346,8 @@ namespace Barotrauma
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check whether the character has a diving suit in usable condition plus some oxygen.
|
/// Check whether the character has a diving suit in usable condition plus some oxygen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool HasDivingSuit(Character character, float conditionPercentage = 0) => HasItem(character, AIObjectiveFindDivingGear.HEAVY_DIVING_GEAR, out _, AIObjectiveFindDivingGear.OXYGEN_SOURCE, conditionPercentage, requireEquipped: true);
|
public static bool HasDivingSuit(Character character, float conditionPercentage = 0) => HasItem(character, AIObjectiveFindDivingGear.HEAVY_DIVING_GEAR, out _, AIObjectiveFindDivingGear.OXYGEN_SOURCE, conditionPercentage, requireEquipped: true,
|
||||||
|
predicate: (Item item) => { return character.HasEquippedItem(item, InvSlotType.OuterClothes); });
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check whether the character has a diving mask in usable condition plus some oxygen.
|
/// Check whether the character has a diving mask in usable condition plus some oxygen.
|
||||||
@@ -1464,7 +1538,7 @@ namespace Barotrauma
|
|||||||
if (!humanAI.Character.IsSecurity) { return false; }
|
if (!humanAI.Character.IsSecurity) { return false; }
|
||||||
if (humanAI.ObjectiveManager.IsCurrentObjective<AIObjectiveCombat>()) { return false; }
|
if (humanAI.ObjectiveManager.IsCurrentObjective<AIObjectiveCombat>()) { return false; }
|
||||||
humanAI.AddCombatObjective(AIObjectiveCombat.CombatMode.Arrest, thief, delay: GetReactionTime(),
|
humanAI.AddCombatObjective(AIObjectiveCombat.CombatMode.Arrest, thief, delay: GetReactionTime(),
|
||||||
abortCondition: () => thief.Inventory.FindItem(it => it != null && it.StolenDuringRound, true) == null,
|
abortCondition: obj => thief.Inventory.FindItem(it => it != null && it.StolenDuringRound, true) == null,
|
||||||
onAbort: () =>
|
onAbort: () =>
|
||||||
{
|
{
|
||||||
if (item != null && !item.Removed && humanAI != null && !humanAI.ObjectiveManager.IsCurrentObjective<AIObjectiveGetItem>())
|
if (item != null && !item.Removed && humanAI != null && !humanAI.ObjectiveManager.IsCurrentObjective<AIObjectiveGetItem>())
|
||||||
|
|||||||
@@ -301,34 +301,33 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
Ladder nextLadder = GetNextLadder();
|
Ladder nextLadder = GetNextLadder();
|
||||||
var ladders = currentLadder ?? nextLadder;
|
var ladders = currentLadder ?? nextLadder;
|
||||||
if (canClimb && !isDiving && ladders != null && character.SelectedConstruction != ladders.Item)
|
bool useLadders = canClimb && ladders != null && (!isDiving || Math.Abs(steering.X) < 0.1f && Math.Abs(steering.Y) > 1);
|
||||||
|
if (useLadders && character.SelectedConstruction != ladders.Item)
|
||||||
{
|
{
|
||||||
if (IsNextNodeLadder || currentPath.Finished)
|
if (character.CanInteractWith(ladders.Item))
|
||||||
{
|
|
||||||
if (character.CanInteractWith(ladders.Item))
|
|
||||||
{
|
|
||||||
ladders.Item.TryInteract(character, false, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Cannot interact with the current (or next) ladder,
|
|
||||||
// Try to select the previous ladder, unless it's already selected, unless the previous ladder is not adjacent to the current ladder.
|
|
||||||
// The intention of this code is to prevent the bots from dropping from the "double ladders".
|
|
||||||
var previousLadders = currentPath.PrevNode?.Ladders;
|
|
||||||
if (previousLadders != null && previousLadders != ladders && character.SelectedConstruction != previousLadders.Item &&
|
|
||||||
character.CanInteractWith(previousLadders.Item) && Math.Abs(previousLadders.Item.WorldPosition.X - ladders.Item.WorldPosition.X) < 5)
|
|
||||||
{
|
|
||||||
previousLadders.Item.TryInteract(character, false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!IsNextLadderSameAsCurrent && character.SelectedConstruction?.GetComponent<Ladder>() != null && character.CanInteractWith(ladders.Item))
|
|
||||||
{
|
{
|
||||||
ladders.Item.TryInteract(character, false, true);
|
ladders.Item.TryInteract(character, false, true);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Cannot interact with the current (or next) ladder,
|
||||||
|
// Try to select the previous ladder, unless it's already selected, unless the previous ladder is not adjacent to the current ladder.
|
||||||
|
// The intention of this code is to prevent the bots from dropping from the "double ladders".
|
||||||
|
var previousLadders = currentPath.PrevNode?.Ladders;
|
||||||
|
if (previousLadders != null && previousLadders != ladders && character.SelectedConstruction != previousLadders.Item &&
|
||||||
|
character.CanInteractWith(previousLadders.Item) && Math.Abs(previousLadders.Item.WorldPosition.X - ladders.Item.WorldPosition.X) < 5)
|
||||||
|
{
|
||||||
|
previousLadders.Item.TryInteract(character, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var collider = character.AnimController.Collider;
|
var collider = character.AnimController.Collider;
|
||||||
if (character.IsClimbing && !isDiving)
|
if (character.IsClimbing && !useLadders)
|
||||||
|
{
|
||||||
|
character.AnimController.Anim = AnimController.Animation.None;
|
||||||
|
character.SelectedConstruction = null;
|
||||||
|
}
|
||||||
|
if (character.IsClimbing && useLadders)
|
||||||
{
|
{
|
||||||
Vector2 diff = currentPath.CurrentNode.SimPosition - pos;
|
Vector2 diff = currentPath.CurrentNode.SimPosition - pos;
|
||||||
bool nextLadderSameAsCurrent = IsNextLadderSameAsCurrent;
|
bool nextLadderSameAsCurrent = IsNextLadderSameAsCurrent;
|
||||||
@@ -380,17 +379,12 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (character.AnimController.InWater)
|
else if (character.AnimController.InWater)
|
||||||
{
|
{
|
||||||
// If the character is underwater, we don't need the ladders anymore
|
|
||||||
if (character.IsClimbing && isDiving)
|
|
||||||
{
|
|
||||||
character.AnimController.Anim = AnimController.Animation.None;
|
|
||||||
character.SelectedConstruction = null;
|
|
||||||
}
|
|
||||||
var door = currentPath.CurrentNode.ConnectedDoor;
|
var door = currentPath.CurrentNode.ConnectedDoor;
|
||||||
if (door == null || door.CanBeTraversed)
|
if (door == null || door.CanBeTraversed)
|
||||||
{
|
{
|
||||||
float multiplier = MathHelper.Lerp(1, 10, MathHelper.Clamp(collider.LinearVelocity.Length() / 10, 0, 1));
|
float margin = MathHelper.Lerp(1, 5, MathHelper.Clamp(collider.LinearVelocity.Length() / 10, 0, 1));
|
||||||
float targetDistance = collider.GetSize().X * multiplier;
|
Vector2 colliderSize = collider.GetSize();
|
||||||
|
float targetDistance = Math.Max(Math.Max(colliderSize.X, colliderSize.Y) / 2 * margin, 0.5f);
|
||||||
float horizontalDistance = Math.Abs(character.WorldPosition.X - currentPath.CurrentNode.WorldPosition.X);
|
float horizontalDistance = Math.Abs(character.WorldPosition.X - currentPath.CurrentNode.WorldPosition.X);
|
||||||
float verticalDistance = Math.Abs(character.WorldPosition.Y - currentPath.CurrentNode.WorldPosition.Y);
|
float verticalDistance = Math.Abs(character.WorldPosition.Y - currentPath.CurrentNode.WorldPosition.Y);
|
||||||
if (character.CurrentHull != currentPath.CurrentNode.CurrentHull)
|
if (character.CurrentHull != currentPath.CurrentNode.CurrentHull)
|
||||||
@@ -404,24 +398,25 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!canClimb || !IsNextLadderSameAsCurrent)
|
else
|
||||||
{
|
{
|
||||||
// Walking horizontally
|
// Walking horizontally
|
||||||
Vector2 colliderBottom = character.AnimController.GetColliderBottom();
|
Vector2 colliderBottom = character.AnimController.GetColliderBottom();
|
||||||
Vector2 colliderSize = collider.GetSize();
|
Vector2 colliderSize = collider.GetSize();
|
||||||
Vector2 velocity = collider.LinearVelocity;
|
Vector2 velocity = collider.LinearVelocity;
|
||||||
// If the character is smaller than this, it would fail to use the waypoint nodes because they are always too high.
|
// If the character is very short, it would fail to use the waypoint nodes because they are always too high.
|
||||||
float minHeight = 1;
|
// If the character is very thin, it would often fail to reach the waypoints, because the horizontal distance is too small.
|
||||||
// If the character is very thin, without a min value, it would often fail to reach the waypoints, because the horizontal distance is too small.
|
// Both values are based on the human size. So basically anything smaller than humans are considered as equal in size.
|
||||||
float minWidth = 0.17f;
|
float minHeight = 1.6125001f;
|
||||||
|
float minWidth = 0.3225f;
|
||||||
// Cannot use the head position, because not all characters have head or it can be below the total height of the character
|
// Cannot use the head position, because not all characters have head or it can be below the total height of the character
|
||||||
float characterHeight = Math.Max(colliderSize.Y + character.AnimController.ColliderHeightFromFloor, minHeight);
|
float characterHeight = Math.Max(colliderSize.Y + character.AnimController.ColliderHeightFromFloor, minHeight);
|
||||||
float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X);
|
float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X);
|
||||||
bool isAboveFeet = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y;
|
bool isAboveFeet = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y;
|
||||||
bool isNotTooHigh = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight;
|
bool isNotTooHigh = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight;
|
||||||
var door = currentPath.CurrentNode.ConnectedDoor;
|
var door = currentPath.CurrentNode.ConnectedDoor;
|
||||||
float margin = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 10, 0, 1));
|
float margin = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 5, 0, 1));
|
||||||
float targetDistance = Math.Max(collider.radius * margin, minWidth);
|
float targetDistance = Math.Max(colliderSize.X / 2 * margin, minWidth / 2);
|
||||||
if (horizontalDistance < targetDistance && isAboveFeet && isNotTooHigh && (door == null || door.CanBeTraversed))
|
if (horizontalDistance < targetDistance && isAboveFeet && isNotTooHigh && (door == null || door.CanBeTraversed))
|
||||||
{
|
{
|
||||||
currentPath.SkipToNextNode();
|
currentPath.SkipToNextNode();
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
using Barotrauma.Extensions;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
partial class MentalStateManager
|
||||||
|
{
|
||||||
|
private float mentalStateTimer;
|
||||||
|
private const float MentalStateInterval = 7.5f;
|
||||||
|
|
||||||
|
private float mentalBehaviorTimer;
|
||||||
|
private const float MentalBehaviorInterval = 7.5f;
|
||||||
|
|
||||||
|
private readonly Character character;
|
||||||
|
private readonly HumanAIController humanAIController;
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
public MentalType CurrentMentalType { get; private set; }
|
||||||
|
public enum MentalType
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
Confused, // No effects other than special dialogue
|
||||||
|
Afraid, // Will retreat from whoever is nearby
|
||||||
|
Desperate, // Will defensively attack/arrest whoever is nearby
|
||||||
|
Berserk // turns fully hostile using team change logic
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string MentalTeamChange = "mental";
|
||||||
|
|
||||||
|
public MentalStateManager(Character character, HumanAIController humanAIController)
|
||||||
|
{
|
||||||
|
this.character = character;
|
||||||
|
this.humanAIController = humanAIController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
if (!Active) { return; }
|
||||||
|
mentalStateTimer -= deltaTime;
|
||||||
|
if (mentalStateTimer <= 0.0f)
|
||||||
|
{
|
||||||
|
UpdateMentalState();
|
||||||
|
mentalStateTimer = MentalStateInterval * Rand.Range(0.75f, 1.25f);
|
||||||
|
}
|
||||||
|
|
||||||
|
mentalBehaviorTimer = Math.Max(0f, mentalBehaviorTimer - deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateMentalState()
|
||||||
|
{
|
||||||
|
MentalType newMentalType = GetMentalType(character.CharacterHealth.GetAffliction("psychosis"));
|
||||||
|
bool createdCombat = false;
|
||||||
|
|
||||||
|
switch (newMentalType)
|
||||||
|
{
|
||||||
|
case MentalType.Normal:
|
||||||
|
case MentalType.Confused:
|
||||||
|
// remove combat if we became normal again
|
||||||
|
mentalBehaviorTimer = 0f;
|
||||||
|
break;
|
||||||
|
case MentalType.Afraid:
|
||||||
|
case MentalType.Desperate:
|
||||||
|
case MentalType.Berserk:
|
||||||
|
// berserk is not removed unless we drop to normal behavior again
|
||||||
|
if (CurrentMentalType == MentalType.Berserk)
|
||||||
|
{
|
||||||
|
newMentalType = MentalType.Berserk;
|
||||||
|
}
|
||||||
|
// give players a full interval to react to mental changes
|
||||||
|
if (newMentalType == CurrentMentalType)
|
||||||
|
{
|
||||||
|
createdCombat = CreateCombatBehavior(CurrentMentalType);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!createdCombat)
|
||||||
|
{
|
||||||
|
CreateDialogueBehavior(newMentalType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newMentalType != MentalType.Berserk)
|
||||||
|
{
|
||||||
|
character.TryRemoveTeamChange(MentalTeamChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentMentalType = newMentalType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int mentalTypeCount;
|
||||||
|
private int MentalTypeCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (mentalTypeCount == 0)
|
||||||
|
{
|
||||||
|
mentalTypeCount = Enum.GetNames(typeof(MentalType)).Length;
|
||||||
|
}
|
||||||
|
return mentalTypeCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MentalType GetMentalType(Affliction affliction)
|
||||||
|
{
|
||||||
|
if (affliction == null)
|
||||||
|
{
|
||||||
|
return MentalType.Normal;
|
||||||
|
}
|
||||||
|
// test this later
|
||||||
|
int psychosisIndex = (int)(affliction.Strength / (affliction.Prefab.MaxStrength / MentalTypeCount) * Rand.Range(1f, 1.2f));
|
||||||
|
psychosisIndex = Math.Clamp(psychosisIndex, 0, 4);
|
||||||
|
MentalType mentalType = psychosisIndex switch
|
||||||
|
{
|
||||||
|
0 => MentalType.Normal,
|
||||||
|
1 => MentalType.Confused,
|
||||||
|
2 => MentalType.Afraid,
|
||||||
|
3 => MentalType.Desperate,
|
||||||
|
4 => MentalType.Berserk,
|
||||||
|
_ => throw new ArgumentOutOfRangeException(psychosisIndex.ToString()),
|
||||||
|
};
|
||||||
|
return mentalType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CreateCombatBehavior(MentalType mentalType)
|
||||||
|
{
|
||||||
|
Character mentalAttackTarget = Character.CharacterList.Where(
|
||||||
|
possibleTarget => HumanAIController.IsActive(possibleTarget) &&
|
||||||
|
(possibleTarget.TeamID != character.TeamID || mentalType == MentalType.Berserk) &&
|
||||||
|
humanAIController.VisibleHulls.Contains(possibleTarget.CurrentHull) &&
|
||||||
|
possibleTarget != character).GetRandom();
|
||||||
|
|
||||||
|
if (mentalAttackTarget == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var combatMode = AIObjectiveCombat.CombatMode.None;
|
||||||
|
bool holdFire = mentalType == MentalType.Afraid && character.IsSecurity;
|
||||||
|
switch (mentalType)
|
||||||
|
{
|
||||||
|
case MentalType.Afraid:
|
||||||
|
combatMode = character.IsSecurity ? AIObjectiveCombat.CombatMode.Arrest : AIObjectiveCombat.CombatMode.Retreat;
|
||||||
|
break;
|
||||||
|
case MentalType.Desperate:
|
||||||
|
// might be unnecessary to explicitly declare as arrest against non-humans
|
||||||
|
combatMode = character.IsSecurity && mentalAttackTarget.IsHuman ? AIObjectiveCombat.CombatMode.Arrest : AIObjectiveCombat.CombatMode.Defensive;
|
||||||
|
break;
|
||||||
|
case MentalType.Berserk:
|
||||||
|
combatMode = AIObjectiveCombat.CombatMode.Offensive;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// using this as an explicit time-out for the behavior. it's possible it will never run out because of the manager being disabled, but combat objective has failsafes for that
|
||||||
|
mentalBehaviorTimer = MentalBehaviorInterval;
|
||||||
|
humanAIController.AddCombatObjective(combatMode, mentalAttackTarget, allowHoldFire: holdFire, abortCondition: obj => mentalBehaviorTimer <= 0f);
|
||||||
|
string textIdentifier = $"dialogmentalstatereaction{combatMode.ToString().ToLowerInvariant()}";
|
||||||
|
character.Speak(TextManager.Get(textIdentifier), delay: Rand.Range(0.5f, 1.0f), identifier: textIdentifier, minDurationBetweenSimilar: 25f);
|
||||||
|
|
||||||
|
if (mentalType == MentalType.Berserk && !character.HasTeamChange(MentalTeamChange))
|
||||||
|
{
|
||||||
|
// TODO: could this be handled in the switch block above?
|
||||||
|
character.TryAddNewTeamChange(MentalTeamChange, new ActiveTeamChange(CharacterTeamType.None, ActiveTeamChange.TeamChangePriorities.Absolute, aggressiveBehavior: true));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateDialogueBehavior(MentalType mentalType)
|
||||||
|
{
|
||||||
|
if (mentalType == MentalType.Normal) { return; }
|
||||||
|
string textIdentifier = $"dialogmentalstate{mentalType.ToString().ToLowerInvariant()}";
|
||||||
|
character.Speak(TextManager.Get(textIdentifier), delay: Rand.Range(0.5f, 1.0f), identifier: textIdentifier, minDurationBetweenSimilar: 35f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,6 +64,10 @@ namespace Barotrauma
|
|||||||
public readonly List<NPCConversation> Responses;
|
public readonly List<NPCConversation> Responses;
|
||||||
private readonly int speakerIndex;
|
private readonly int speakerIndex;
|
||||||
private readonly List<string> allowedSpeakerTags;
|
private readonly List<string> allowedSpeakerTags;
|
||||||
|
private readonly bool requireNextLine;
|
||||||
|
// used primarily for team1 characters interacting with escorted personnel (TODO: not used anywhere)
|
||||||
|
private readonly bool requireSight;
|
||||||
|
|
||||||
public static void LoadAll(IEnumerable<ContentFile> files)
|
public static void LoadAll(IEnumerable<ContentFile> files)
|
||||||
{
|
{
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
@@ -161,6 +165,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Responses.Add(new NPCConversation(subElement, filePath));
|
Responses.Add(new NPCConversation(subElement, filePath));
|
||||||
}
|
}
|
||||||
|
requireNextLine = element.GetAttributeBool("requirenextline", false);
|
||||||
|
requireSight = element.GetAttributeBool("requiresight", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<string> GetCurrentFlags(Character speaker)
|
private static List<string> GetCurrentFlags(Character speaker)
|
||||||
@@ -211,7 +217,7 @@ namespace Barotrauma
|
|||||||
var afflictions = speaker.CharacterHealth.GetAllAfflictions();
|
var afflictions = speaker.CharacterHealth.GetAllAfflictions();
|
||||||
foreach (Affliction affliction in afflictions)
|
foreach (Affliction affliction in afflictions)
|
||||||
{
|
{
|
||||||
var currentEffect = affliction.Prefab.GetActiveEffect(affliction.Strength);
|
var currentEffect = affliction.GetActiveEffect();
|
||||||
if (currentEffect != null && !string.IsNullOrEmpty(currentEffect.DialogFlag) && !currentFlags.Contains(currentEffect.DialogFlag))
|
if (currentEffect != null && !string.IsNullOrEmpty(currentEffect.DialogFlag) && !currentFlags.Contains(currentEffect.DialogFlag))
|
||||||
{
|
{
|
||||||
currentFlags.Add(currentEffect.DialogFlag);
|
currentFlags.Add(currentEffect.DialogFlag);
|
||||||
@@ -226,7 +232,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
currentFlags.Add("CampaignNPC." + speaker.CampaignInteractionType);
|
currentFlags.Add("CampaignNPC." + speaker.CampaignInteractionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameMain.GameSession?.GameMode is CampaignMode campaignMode &&
|
if (GameMain.GameSession?.GameMode is CampaignMode campaignMode &&
|
||||||
(campaignMode.Map?.CurrentLocation?.Type?.Identifier.Equals("abandoned", StringComparison.OrdinalIgnoreCase) ?? false))
|
(campaignMode.Map?.CurrentLocation?.Type?.Identifier.Equals("abandoned", StringComparison.OrdinalIgnoreCase) ?? false))
|
||||||
{
|
{
|
||||||
@@ -239,6 +244,10 @@ namespace Barotrauma
|
|||||||
currentFlags.Add("Hostage");
|
currentFlags.Add("Hostage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (speaker.IsEscorted)
|
||||||
|
{
|
||||||
|
currentFlags.Add("escort");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentFlags;
|
return currentFlags;
|
||||||
@@ -325,43 +334,15 @@ namespace Barotrauma
|
|||||||
|
|
||||||
foreach (Character potentialSpeaker in availableSpeakers)
|
foreach (Character potentialSpeaker in availableSpeakers)
|
||||||
{
|
{
|
||||||
//check if the character has an appropriate job to say the line
|
if (CheckSpeakerViability(potentialSpeaker, selectedConversation, assignedSpeakers.Values.ToList(), ignoreFlags))
|
||||||
if ((potentialSpeaker.Info?.Job != null && potentialSpeaker.Info.Job.Prefab.OnlyJobSpecificDialog) ||
|
|
||||||
selectedConversation.AllowedJobs.Count > 0)
|
|
||||||
{
|
{
|
||||||
if (!selectedConversation.AllowedJobs.Contains(potentialSpeaker.Info?.Job.Prefab)) { continue; }
|
allowedSpeakers.Add(potentialSpeaker);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if the character has all required flags to say the line
|
|
||||||
if (!ignoreFlags)
|
|
||||||
{
|
|
||||||
var characterFlags = GetCurrentFlags(potentialSpeaker);
|
|
||||||
if (!selectedConversation.Flags.All(flag => characterFlags.Contains(flag))) { continue; }
|
|
||||||
}
|
|
||||||
|
|
||||||
//check if the character is close enough to hear the rest of the speakers
|
|
||||||
if (assignedSpeakers.Values.Any(s => !potentialSpeaker.CanHearCharacter(s))) { continue; }
|
|
||||||
|
|
||||||
//check if the character has an appropriate personality
|
|
||||||
if (selectedConversation.allowedSpeakerTags.Count > 0)
|
|
||||||
{
|
|
||||||
if (potentialSpeaker.Info?.PersonalityTrait == null) { continue; }
|
|
||||||
if (!selectedConversation.allowedSpeakerTags.Any(t => potentialSpeaker.Info.PersonalityTrait.AllowedDialogTags.Any(t2 => t2 == t))) { continue; }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (potentialSpeaker.Info?.PersonalityTrait != null &&
|
|
||||||
!potentialSpeaker.Info.PersonalityTrait.AllowedDialogTags.Contains("none"))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allowedSpeakers.Add(potentialSpeaker);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowedSpeakers.Count == 0)
|
if (allowedSpeakers.Count == 0 || NextLineFailure(selectedConversation, availableSpeakers, allowedSpeakers, ignoreFlags))
|
||||||
{
|
{
|
||||||
|
allowedSpeakers.Clear();
|
||||||
potentialLines.Remove(selectedConversation);
|
potentialLines.Remove(selectedConversation);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -385,6 +366,62 @@ namespace Barotrauma
|
|||||||
CreateConversation(availableSpeakers, assignedSpeakers, selectedConversation, lineList, availableConversations);
|
CreateConversation(availableSpeakers, assignedSpeakers, selectedConversation, lineList, availableConversations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool NextLineFailure(NPCConversation selectedConversation, List<Character> availableSpeakers, List<Character> allowedSpeakers, bool ignoreFlags)
|
||||||
|
{
|
||||||
|
if (selectedConversation.requireNextLine)
|
||||||
|
{
|
||||||
|
foreach (NPCConversation nextConversation in selectedConversation.Responses)
|
||||||
|
{
|
||||||
|
foreach (Character potentialNextSpeaker in availableSpeakers)
|
||||||
|
{
|
||||||
|
if (CheckSpeakerViability(potentialNextSpeaker, nextConversation, allowedSpeakers, ignoreFlags))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool CheckSpeakerViability(Character potentialSpeaker, NPCConversation selectedConversation, List<Character> checkedSpeakers, bool ignoreFlags)
|
||||||
|
{
|
||||||
|
//check if the character has an appropriate job to say the line
|
||||||
|
if ((potentialSpeaker.Info?.Job != null && potentialSpeaker.Info.Job.Prefab.OnlyJobSpecificDialog) || selectedConversation.AllowedJobs.Count > 0)
|
||||||
|
{
|
||||||
|
if (!selectedConversation.AllowedJobs.Contains(potentialSpeaker.Info?.Job.Prefab)) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if the character has all required flags to say the line
|
||||||
|
if (!ignoreFlags)
|
||||||
|
{
|
||||||
|
var characterFlags = GetCurrentFlags(potentialSpeaker);
|
||||||
|
if (!selectedConversation.Flags.All(flag => characterFlags.Contains(flag))) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if the character is close enough to hear the rest of the speakers
|
||||||
|
if (checkedSpeakers.Any(s => !potentialSpeaker.CanHearCharacter(s))) { return false; }
|
||||||
|
|
||||||
|
//check if the character is close enough to see the rest of the speakers (this should be replaced with a more performant method)
|
||||||
|
if (checkedSpeakers.Any(s => !potentialSpeaker.CanSeeCharacter(s))) { return false; }
|
||||||
|
|
||||||
|
//check if the character has an appropriate personality
|
||||||
|
if (selectedConversation.allowedSpeakerTags.Count > 0)
|
||||||
|
{
|
||||||
|
if (potentialSpeaker.Info?.PersonalityTrait == null) { return false; }
|
||||||
|
if (!selectedConversation.allowedSpeakerTags.Any(t => potentialSpeaker.Info.PersonalityTrait.AllowedDialogTags.Any(t2 => t2 == t))) { return false; }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (potentialSpeaker.Info?.PersonalityTrait != null &&
|
||||||
|
!potentialSpeaker.Info.PersonalityTrait.AllowedDialogTags.Contains("none"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
private static NPCConversation GetRandomConversation(List<NPCConversation> conversations, bool avoidPreviouslyUsed)
|
private static NPCConversation GetRandomConversation(List<NPCConversation> conversations, bool avoidPreviouslyUsed)
|
||||||
{
|
{
|
||||||
if (!avoidPreviouslyUsed)
|
if (!avoidPreviouslyUsed)
|
||||||
|
|||||||
@@ -6,16 +6,18 @@ using Barotrauma.Extensions;
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
abstract class AIObjective
|
abstract partial class AIObjective
|
||||||
{
|
{
|
||||||
public virtual float Devotion => AIObjectiveManager.baseDevotion;
|
public virtual float Devotion => AIObjectiveManager.baseDevotion;
|
||||||
|
|
||||||
public abstract string DebugTag { get; }
|
public abstract string Identifier { get; set; }
|
||||||
|
public virtual string DebugTag => Identifier;
|
||||||
public virtual bool ForceRun => false;
|
public virtual bool ForceRun => false;
|
||||||
public virtual bool IgnoreUnsafeHulls => false;
|
public virtual bool IgnoreUnsafeHulls => false;
|
||||||
public virtual bool AbandonWhenCannotCompleteSubjectives => true;
|
public virtual bool AbandonWhenCannotCompleteSubjectives => true;
|
||||||
public virtual bool AllowSubObjectiveSorting => false;
|
public virtual bool AllowSubObjectiveSorting => false;
|
||||||
public virtual bool ForceOrderPriority => true;
|
public virtual bool ForceOrderPriority => true;
|
||||||
|
public virtual bool PrioritizeIfSubObjectivesActive => false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Can there be multiple objective instaces of the same type?
|
/// Can there be multiple objective instaces of the same type?
|
||||||
@@ -52,8 +54,17 @@ namespace Barotrauma
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float Priority { get; set; }
|
public float Priority { get; set; }
|
||||||
public float BasePriority { get; set; }
|
public float BasePriority { get; set; }
|
||||||
|
|
||||||
public float PriorityModifier { get; private set; } = 1;
|
public float PriorityModifier { get; private set; } = 1;
|
||||||
|
|
||||||
|
// For forcing the highest priority temporarily. Will reset after each priority calculation, so it will need to be kept alive by something.
|
||||||
|
public bool ForceHighestPriority { get; set; }
|
||||||
|
|
||||||
|
// For temporarily forcing walking. Will reset after each priority calculation, so it will need to be kept alive by something.
|
||||||
|
// The intention of this boolean to allow walking even when the priority is higher than AIObjectiveManager.RunPriority.
|
||||||
|
public bool ForceWalk { get; set; }
|
||||||
|
|
||||||
|
public bool IgnoreAtOutpost { get; set; }
|
||||||
|
|
||||||
public readonly Character character;
|
public readonly Character character;
|
||||||
public readonly AIObjectiveManager objectiveManager;
|
public readonly AIObjectiveManager objectiveManager;
|
||||||
public string Option { get; private set; }
|
public string Option { get; private set; }
|
||||||
@@ -102,6 +113,13 @@ namespace Barotrauma
|
|||||||
return all;
|
return all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS0649
|
||||||
|
/// <summary>
|
||||||
|
/// Aborts the objective when this condition is true.
|
||||||
|
/// </summary>
|
||||||
|
public Func<AIObjective, bool> AbortCondition;
|
||||||
|
#pragma warning restore CS0649
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A single shot event. Automatically cleared after launching. Use OnCompleted method for implementing (internal) persistent behavior.
|
/// A single shot event. Automatically cleared after launching. Use OnCompleted method for implementing (internal) persistent behavior.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -217,18 +235,22 @@ namespace Barotrauma
|
|||||||
protected bool IsAllowed
|
protected bool IsAllowed
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
if (IgnoreAtOutpost && Level.IsLoadedOutpost && character.TeamID != CharacterTeamType.FriendlyNPC)
|
||||||
|
{
|
||||||
|
if (Submarine.MainSub != null && Submarine.MainSub.DockedTo.None(s => s.TeamID != CharacterTeamType.FriendlyNPC && s.TeamID != character.TeamID))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!AllowOutsideSubmarine && character.Submarine == null) { return false; }
|
if (!AllowOutsideSubmarine && character.Submarine == null) { return false; }
|
||||||
if (AllowInAnySub) { return true; }
|
if (AllowInAnySub) { return true; }
|
||||||
if (AllowInFriendlySubs && character.Submarine.TeamID == CharacterTeamType.FriendlyNPC) { return true; }
|
if ((AllowInFriendlySubs && character.Submarine.TeamID == CharacterTeamType.FriendlyNPC) || character.IsEscorted) { return true; }
|
||||||
return character.Submarine.TeamID == character.TeamID || character.Submarine.DockedTo.Any(sub => sub.TeamID == character.TeamID);
|
return character.Submarine.TeamID == character.TeamID || character.Submarine.DockedTo.Any(sub => sub.TeamID == character.TeamID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
protected virtual float GetPriority()
|
||||||
/// Call this only when the priority needs to be recalculated. Use the cached Priority property when you don't need to recalculate.
|
|
||||||
/// </summary>
|
|
||||||
public virtual float GetPriority()
|
|
||||||
{
|
{
|
||||||
bool isOrder = objectiveManager.IsOrder(this);
|
bool isOrder = objectiveManager.IsOrder(this);
|
||||||
if (!IsAllowed)
|
if (!IsAllowed)
|
||||||
@@ -248,6 +270,17 @@ namespace Barotrauma
|
|||||||
return Priority;
|
return Priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Call this only when the priority needs to be recalculated. Use the cached Priority property when you don't need to recalculate.
|
||||||
|
/// </summary>
|
||||||
|
public float CalculatePriority()
|
||||||
|
{
|
||||||
|
Priority = GetPriority();
|
||||||
|
ForceHighestPriority = false;
|
||||||
|
ForceWalk = false;
|
||||||
|
return Priority;
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateDevotion(float deltaTime)
|
private void UpdateDevotion(float deltaTime)
|
||||||
{
|
{
|
||||||
var currentObjective = objectiveManager.CurrentObjective;
|
var currentObjective = objectiveManager.CurrentObjective;
|
||||||
@@ -393,7 +426,17 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract bool Check();
|
protected virtual bool Check()
|
||||||
|
{
|
||||||
|
if (AbortCondition != null && AbortCondition(this))
|
||||||
|
{
|
||||||
|
Abandon = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return CheckObjectiveSpecific();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract bool CheckObjectiveSpecific();
|
||||||
|
|
||||||
private bool CheckState()
|
private bool CheckState()
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
class AIObjectiveChargeBatteries : AIObjectiveLoop<PowerContainer>
|
class AIObjectiveChargeBatteries : AIObjectiveLoop<PowerContainer>
|
||||||
{
|
{
|
||||||
public override string DebugTag => "charge batteries";
|
public override string Identifier { get; set; } = "charge batteries";
|
||||||
public override bool AllowAutomaticItemUnequipping => true;
|
public override bool AllowAutomaticItemUnequipping => true;
|
||||||
private IEnumerable<PowerContainer> batteryList;
|
private IEnumerable<PowerContainer> batteryList;
|
||||||
|
|
||||||
|
|||||||
+11
-11
@@ -9,7 +9,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
class AIObjectiveCleanupItem : AIObjective
|
class AIObjectiveCleanupItem : AIObjective
|
||||||
{
|
{
|
||||||
public override string DebugTag => "cleanup item";
|
public override string Identifier { get; set; } = "cleanup item";
|
||||||
public override bool KeepDivingGearOn => true;
|
public override bool KeepDivingGearOn => true;
|
||||||
public override bool AllowAutomaticItemUnequipping => false;
|
public override bool AllowAutomaticItemUnequipping => false;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ namespace Barotrauma
|
|||||||
this.item = item;
|
this.item = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override float GetPriority()
|
protected override float GetPriority()
|
||||||
{
|
{
|
||||||
if (!IsAllowed)
|
if (!IsAllowed)
|
||||||
{
|
{
|
||||||
@@ -68,7 +68,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (item.ParentInventory != null)
|
if (item.ParentInventory != null)
|
||||||
{
|
{
|
||||||
if (item.Container != null && !AIObjectiveCleanupItems.IsValidContainer(item.Container, character, allowUnloading: objectiveManager.HasOrders()))
|
if (item.Container != null && !AIObjectiveCleanupItems.IsValidContainer(item.Container, character, allowUnloading: objectiveManager.HasOrder<AIObjectiveCleanupItems>()))
|
||||||
{
|
{
|
||||||
// Target was picked up or moved by someone.
|
// Target was picked up or moved by someone.
|
||||||
Abandon = true;
|
Abandon = true;
|
||||||
@@ -82,14 +82,14 @@ namespace Barotrauma
|
|||||||
itemIndex = 0;
|
itemIndex = 0;
|
||||||
if (suitableContainer != null)
|
if (suitableContainer != null)
|
||||||
{
|
{
|
||||||
bool equip = item.HasTag(AIObjectiveFindDivingGear.HEAVY_DIVING_GEAR) || (
|
bool equip = item.GetComponent<Holdable>() != null ||
|
||||||
item.GetComponent<Wearable>() == null &&
|
|
||||||
item.AllowedSlots.None(s =>
|
item.AllowedSlots.None(s =>
|
||||||
s == InvSlotType.Card ||
|
s == InvSlotType.Card ||
|
||||||
s == InvSlotType.Head ||
|
s == InvSlotType.Head ||
|
||||||
s == InvSlotType.Headset ||
|
s == InvSlotType.Headset ||
|
||||||
s == InvSlotType.InnerClothes ||
|
s == InvSlotType.InnerClothes ||
|
||||||
s == InvSlotType.OuterClothes));
|
s == InvSlotType.OuterClothes);
|
||||||
|
|
||||||
TryAddSubObjective(ref decontainObjective, () => new AIObjectiveDecontainItem(character, item, objectiveManager, targetContainer: suitableContainer.GetComponent<ItemContainer>())
|
TryAddSubObjective(ref decontainObjective, () => new AIObjectiveDecontainItem(character, item, objectiveManager, targetContainer: suitableContainer.GetComponent<ItemContainer>())
|
||||||
{
|
{
|
||||||
Equip = equip,
|
Equip = equip,
|
||||||
@@ -131,7 +131,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool Check() => IsCompleted;
|
protected override bool CheckObjectiveSpecific() => IsCompleted;
|
||||||
|
|
||||||
public override void Reset()
|
public override void Reset()
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user