Unstable 0.1400.2.0 (a mimir edition)
This commit is contained in:
@@ -9,7 +9,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
public override void DebugDraw(SpriteBatch spriteBatch)
|
public override void DebugDraw(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
if (Character.IsDead) return;
|
if (Character.IsUnconscious || !Character.Enabled || !Enabled) { return; }
|
||||||
|
|
||||||
Vector2 pos = Character.WorldPosition;
|
Vector2 pos = Character.WorldPosition;
|
||||||
pos.Y = -pos.Y;
|
pos.Y = -pos.Y;
|
||||||
@@ -38,7 +38,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
targetPos.Y = -targetPos.Y;
|
targetPos.Y = -targetPos.Y;
|
||||||
GUI.DrawLine(spriteBatch, pos, targetPos, GUI.Style.Red * 0.5f, 0, 4);
|
GUI.DrawLine(spriteBatch, pos, targetPos, GUI.Style.Red * 0.5f, 0, 4);
|
||||||
if (wallTarget != null && (State == AIState.Attack || State == AIState.Aggressive || State == AIState.PassiveAggressive))
|
if (wallTarget != null)
|
||||||
{
|
{
|
||||||
Vector2 wallTargetPos = wallTarget.Position;
|
Vector2 wallTargetPos = wallTarget.Position;
|
||||||
if (wallTarget.Structure.Submarine != null) { wallTargetPos += wallTarget.Structure.Submarine.Position; }
|
if (wallTarget.Structure.Submarine != null) { wallTargetPos += wallTarget.Structure.Submarine.Position; }
|
||||||
|
|||||||
@@ -507,9 +507,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (item.body != null && !item.body.Enabled) continue;
|
if (item.body != null && !item.body.Enabled) { continue; }
|
||||||
if (item.ParentInventory != null) continue;
|
if (item.ParentInventory != null) { continue; }
|
||||||
if (ignoredItems != null && ignoredItems.Contains(item)) continue;
|
if (ignoredItems != null && ignoredItems.Contains(item)) { continue; }
|
||||||
|
if (item.Prefab.RequireCampaignInteract && item.CampaignInteractionType == CampaignMode.InteractionType.None) { continue; }
|
||||||
if (Screen.Selected is SubEditorScreen editor && editor.WiringMode && item.GetComponent<ConnectionPanel>() == null) { continue; }
|
if (Screen.Selected is SubEditorScreen editor && editor.WiringMode && item.GetComponent<ConnectionPanel>() == null) { continue; }
|
||||||
|
|
||||||
if (draggingItemToWorld)
|
if (draggingItemToWorld)
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ namespace Barotrauma
|
|||||||
if (Vector2.DistanceSquared(character.Position, item.Position) > 500f*500f) { continue; }
|
if (Vector2.DistanceSquared(character.Position, item.Position) > 500f*500f) { continue; }
|
||||||
var body = Submarine.CheckVisibility(character.SimPosition, item.SimPosition, ignoreLevel: true);
|
var body = Submarine.CheckVisibility(character.SimPosition, item.SimPosition, ignoreLevel: true);
|
||||||
if (body != null && body.UserData as Item != item) { continue; }
|
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);
|
GUI.DrawIndicator(spriteBatch, item.WorldPosition + new Vector2(0f, item.RectHeight * 0.65f), cam, new Vector2(-100f, 500.0f), item.IconStyle.GetDefaultSprite(), item.IconStyle.Color, createOffset: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -396,7 +396,9 @@ namespace Barotrauma
|
|||||||
break;
|
break;
|
||||||
case 6: //NetEntityEvent.Type.AssignCampaignInteraction
|
case 6: //NetEntityEvent.Type.AssignCampaignInteraction
|
||||||
byte campaignInteractionType = msg.ReadByte();
|
byte campaignInteractionType = msg.ReadByte();
|
||||||
|
bool requireConsciousness = msg.ReadBoolean();
|
||||||
(GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType);
|
(GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType);
|
||||||
|
RequireConsciousnessForCustomInteract = requireConsciousness;
|
||||||
break;
|
break;
|
||||||
case 7: //NetEntityEvent.Type.ObjectiveManagerState
|
case 7: //NetEntityEvent.Type.ObjectiveManagerState
|
||||||
// 1 = order, 2 = objective
|
// 1 = order, 2 = objective
|
||||||
@@ -458,7 +460,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
DebugConsole.Log("Reading character spawn data");
|
DebugConsole.Log("Reading character spawn data");
|
||||||
|
|
||||||
if (GameMain.Client == null) return null;
|
if (GameMain.Client == null) { return null; }
|
||||||
|
|
||||||
bool noInfo = inc.ReadBoolean();
|
bool noInfo = inc.ReadBoolean();
|
||||||
ushort id = inc.ReadUInt16();
|
ushort id = inc.ReadUInt16();
|
||||||
@@ -474,7 +476,15 @@ namespace Barotrauma
|
|||||||
Character character = null;
|
Character character = null;
|
||||||
if (noInfo)
|
if (noInfo)
|
||||||
{
|
{
|
||||||
character = Create(speciesName, position, seed, characterInfo: null, id: id, isRemotePlayer: false);
|
try
|
||||||
|
{
|
||||||
|
character = Create(speciesName, position, seed, characterInfo: null, id: id, isRemotePlayer: false);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"Failed to spawn character {speciesName}", e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
bool containsStatusData = inc.ReadBoolean();
|
bool containsStatusData = inc.ReadBoolean();
|
||||||
if (containsStatusData)
|
if (containsStatusData)
|
||||||
{
|
{
|
||||||
@@ -490,8 +500,15 @@ namespace Barotrauma
|
|||||||
string infoSpeciesName = inc.ReadString();
|
string infoSpeciesName = inc.ReadString();
|
||||||
|
|
||||||
CharacterInfo info = CharacterInfo.ClientRead(infoSpeciesName, inc);
|
CharacterInfo info = CharacterInfo.ClientRead(infoSpeciesName, inc);
|
||||||
|
try
|
||||||
character = Create(speciesName, position, seed, characterInfo: info, id: id, isRemotePlayer: ownerId > 0 && GameMain.Client.ID != ownerId, hasAi: hasAi);
|
{
|
||||||
|
character = Create(speciesName, position, seed, characterInfo: info, id: id, isRemotePlayer: ownerId > 0 && GameMain.Client.ID != ownerId, hasAi: hasAi);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"Failed to spawn character {speciesName}", e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
character.TeamID = (CharacterTeamType)teamID;
|
character.TeamID = (CharacterTeamType)teamID;
|
||||||
character.CampaignInteractionType = (CampaignMode.InteractionType)inc.ReadByte();
|
character.CampaignInteractionType = (CampaignMode.InteractionType)inc.ReadByte();
|
||||||
if (character.CampaignInteractionType != CampaignMode.InteractionType.None)
|
if (character.CampaignInteractionType != CampaignMode.InteractionType.None)
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ namespace Barotrauma
|
|||||||
case "toggleupperhud":
|
case "toggleupperhud":
|
||||||
case "togglecharacternames":
|
case "togglecharacternames":
|
||||||
case "fpscounter":
|
case "fpscounter":
|
||||||
|
case "showperf":
|
||||||
case "dumptofile":
|
case "dumptofile":
|
||||||
case "findentityids":
|
case "findentityids":
|
||||||
case "setfreecamspeed":
|
case "setfreecamspeed":
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ namespace Barotrauma
|
|||||||
for (int j = 0; j < itemCount; j++)
|
for (int j = 0; j < itemCount; j++)
|
||||||
{
|
{
|
||||||
Item.ReadSpawnData(msg);
|
Item.ReadSpawnData(msg);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (characters.Contains(null))
|
if (characters.Contains(null))
|
||||||
|
|||||||
@@ -239,6 +239,9 @@ namespace Barotrauma
|
|||||||
private static SavingIndicatorState savingIndicatorState = SavingIndicatorState.None;
|
private static SavingIndicatorState savingIndicatorState = SavingIndicatorState.None;
|
||||||
private static float? timeUntilSavingIndicatorDisabled;
|
private static float? timeUntilSavingIndicatorDisabled;
|
||||||
|
|
||||||
|
private static string loadedSpritesText;
|
||||||
|
private static DateTime loadedSpritesUpdateTime;
|
||||||
|
|
||||||
private enum SavingIndicatorState
|
private enum SavingIndicatorState
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
@@ -454,9 +457,12 @@ namespace Barotrauma
|
|||||||
"Particle count: " + GameMain.ParticleManager.ParticleCount + "/" + GameMain.ParticleManager.MaxParticles,
|
"Particle count: " + GameMain.ParticleManager.ParticleCount + "/" + GameMain.ParticleManager.MaxParticles,
|
||||||
Color.Lerp(GUI.Style.Green, GUI.Style.Red, (GameMain.ParticleManager.ParticleCount / (float)GameMain.ParticleManager.MaxParticles)), Color.Black * 0.5f, 0, SmallFont);
|
Color.Lerp(GUI.Style.Green, GUI.Style.Red, (GameMain.ParticleManager.ParticleCount / (float)GameMain.ParticleManager.MaxParticles)), Color.Black * 0.5f, 0, SmallFont);
|
||||||
|
|
||||||
DrawString(spriteBatch, new Vector2(10, 115),
|
if (loadedSpritesText == null || DateTime.Now > loadedSpritesUpdateTime)
|
||||||
"Loaded sprites: " + Sprite.LoadedSprites.Count() + "\n(" + Sprite.LoadedSprites.Select(s => s.FilePath).Distinct().Count() + " unique textures)",
|
{
|
||||||
Color.White, Color.Black * 0.5f, 0, SmallFont);
|
loadedSpritesText = "Loaded sprites: " + Sprite.LoadedSprites.Count() + "\n(" + Sprite.LoadedSprites.Select(s => s.FilePath).Distinct().Count() + " unique textures)";
|
||||||
|
loadedSpritesUpdateTime = DateTime.Now + new TimeSpan(0, 0, seconds: 5);
|
||||||
|
}
|
||||||
|
DrawString(spriteBatch, new Vector2(10, 115), loadedSpritesText, Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||||
|
|
||||||
if (debugDrawSounds)
|
if (debugDrawSounds)
|
||||||
{
|
{
|
||||||
@@ -1365,8 +1371,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
float screenDist = Vector2.Distance(cam.WorldToScreen(cam.WorldViewCenter), targetScreenPos);
|
float screenDist = Vector2.Distance(cam.WorldToScreen(cam.WorldViewCenter), targetScreenPos);
|
||||||
float angle = MathUtils.VectorToAngle(diff);
|
float angle = MathUtils.VectorToAngle(diff);
|
||||||
|
float originalAngle = angle;
|
||||||
|
|
||||||
float minAngleDiff = 0.05f;
|
const float minAngleDiff = 0.05f;
|
||||||
bool overlapFound = true;
|
bool overlapFound = true;
|
||||||
int iterations = 0;
|
int iterations = 0;
|
||||||
while (overlapFound && iterations < 10)
|
while (overlapFound && iterations < 10)
|
||||||
@@ -1388,18 +1395,24 @@ namespace Barotrauma
|
|||||||
|
|
||||||
usedIndicatorAngles.Add(angle);
|
usedIndicatorAngles.Add(angle);
|
||||||
|
|
||||||
Vector2 unclampedDiff = new Vector2(
|
|
||||||
(float)Math.Cos(angle) * screenDist,
|
|
||||||
(float)-Math.Sin(angle) * screenDist);
|
|
||||||
|
|
||||||
Vector2 iconDiff = new Vector2(
|
Vector2 iconDiff = new Vector2(
|
||||||
|
(float)Math.Cos(angle) * Math.Min(GameMain.GraphicsWidth * 0.4f, screenDist + 10),
|
||||||
|
(float)-Math.Sin(angle) * Math.Min(GameMain.GraphicsHeight * 0.4f, screenDist + 10));
|
||||||
|
|
||||||
|
angle = MathHelper.Lerp(originalAngle, angle, MathHelper.Clamp(((screenDist + 10f) - iconDiff.Length()) / 10f, 0f, 1f));
|
||||||
|
|
||||||
|
/*Vector2 unclampedDiff = new Vector2(
|
||||||
|
(float)Math.Cos(angle) * screenDist,
|
||||||
|
(float)-Math.Sin(angle) * screenDist);*/
|
||||||
|
|
||||||
|
iconDiff = new Vector2(
|
||||||
(float)Math.Cos(angle) * Math.Min(GameMain.GraphicsWidth * 0.4f, screenDist),
|
(float)Math.Cos(angle) * Math.Min(GameMain.GraphicsWidth * 0.4f, screenDist),
|
||||||
(float)-Math.Sin(angle) * Math.Min(GameMain.GraphicsHeight * 0.4f, screenDist));
|
(float)-Math.Sin(angle) * Math.Min(GameMain.GraphicsHeight * 0.4f, screenDist));
|
||||||
|
|
||||||
Vector2 iconPos = cam.WorldToScreen(cam.WorldViewCenter) + iconDiff;
|
Vector2 iconPos = cam.WorldToScreen(cam.WorldViewCenter) + iconDiff;
|
||||||
sprite.Draw(spriteBatch, iconPos, color * alpha, rotate: 0.0f, scale: symbolScale);
|
sprite.Draw(spriteBatch, iconPos, color * alpha, rotate: 0.0f, scale: symbolScale);
|
||||||
|
|
||||||
if (unclampedDiff.Length() - 10 > iconDiff.Length())
|
if (/*unclampedDiff.Length()*/ screenDist - 10 > iconDiff.Length())
|
||||||
{
|
{
|
||||||
Vector2 normalizedDiff = Vector2.Normalize(targetScreenPos - iconPos);
|
Vector2 normalizedDiff = Vector2.Normalize(targetScreenPos - iconPos);
|
||||||
Vector2 arrowOffset = normalizedDiff * sprite.size.X * symbolScale * 0.7f;
|
Vector2 arrowOffset = normalizedDiff * sprite.size.X * symbolScale * 0.7f;
|
||||||
|
|||||||
@@ -838,6 +838,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
bool hasPermissions = HasPermissions;
|
bool hasPermissions = HasPermissions;
|
||||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||||
|
bool refreshingBuyList = listBox == shoppingCrateBuyList;
|
||||||
int totalPrice = 0;
|
int totalPrice = 0;
|
||||||
foreach (PurchasedItem item in items)
|
foreach (PurchasedItem item in items)
|
||||||
{
|
{
|
||||||
@@ -859,6 +860,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
numInput.UserData = item;
|
numInput.UserData = item;
|
||||||
numInput.Enabled = hasPermissions;
|
numInput.Enabled = hasPermissions;
|
||||||
|
numInput.MaxValueInt = GetMaxAvailable(item.ItemPrefab, refreshingBuyList ? StoreTab.Buy : StoreTab.Sell);
|
||||||
}
|
}
|
||||||
SetOwnedLabelText(itemFrame);
|
SetOwnedLabelText(itemFrame);
|
||||||
SetItemFrameStatus(itemFrame, hasPermissions);
|
SetItemFrameStatus(itemFrame, hasPermissions);
|
||||||
@@ -873,7 +875,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
suppressBuySell = false;
|
suppressBuySell = false;
|
||||||
|
|
||||||
var price = listBox == shoppingCrateBuyList ?
|
var price = refreshingBuyList ?
|
||||||
CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo) :
|
CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo) :
|
||||||
CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
|
CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
|
||||||
totalPrice += item.Quantity * price;
|
totalPrice += item.Quantity * price;
|
||||||
@@ -884,7 +886,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
SortItems(listBox, SortingMethod.CategoryAsc);
|
SortItems(listBox, SortingMethod.CategoryAsc);
|
||||||
listBox.UpdateScrollBarSize();
|
listBox.UpdateScrollBarSize();
|
||||||
if (listBox == shoppingCrateBuyList)
|
if (refreshingBuyList)
|
||||||
{
|
{
|
||||||
buyTotal = totalPrice;
|
buyTotal = totalPrice;
|
||||||
if (IsBuying) { SetShoppingCrateTotalText(); }
|
if (IsBuying) { SetShoppingCrateTotalText(); }
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ namespace Barotrauma
|
|||||||
private const int submarinesPerPage = 4;
|
private const int submarinesPerPage = 4;
|
||||||
private int currentPage = 1;
|
private int currentPage = 1;
|
||||||
private int pageCount;
|
private int pageCount;
|
||||||
private bool transferService, purchaseService, initialized;
|
private readonly bool transferService, purchaseService;
|
||||||
|
private bool initialized;
|
||||||
private int deliveryFee;
|
private int deliveryFee;
|
||||||
private string deliveryLocationName;
|
private string deliveryLocationName;
|
||||||
|
|
||||||
@@ -27,12 +28,12 @@ namespace Barotrauma
|
|||||||
private int selectionIndicatorThickness;
|
private int selectionIndicatorThickness;
|
||||||
private GUIImage listBackground;
|
private GUIImage listBackground;
|
||||||
|
|
||||||
private List<SubmarineInfo> subsToShow;
|
private readonly List<SubmarineInfo> subsToShow;
|
||||||
private SubmarineDisplayContent[] submarineDisplays = new SubmarineDisplayContent[submarinesPerPage];
|
private readonly SubmarineDisplayContent[] submarineDisplays = new SubmarineDisplayContent[submarinesPerPage];
|
||||||
private SubmarineInfo selectedSubmarine = null;
|
private SubmarineInfo selectedSubmarine = null;
|
||||||
private string purchaseAndSwitchText, purchaseOnlyText, deliveryText, currentSubText, deliveryFeeText, priceText, switchText, missingPreviewText, currencyShorthandText, currencyLongText;
|
private string purchaseAndSwitchText, purchaseOnlyText, deliveryText, currentSubText, deliveryFeeText, priceText, switchText, missingPreviewText, currencyShorthandText, currencyLongText;
|
||||||
private RectTransform parent;
|
private readonly RectTransform parent;
|
||||||
private Action closeAction;
|
private readonly Action closeAction;
|
||||||
private Sprite pageIndicator;
|
private Sprite pageIndicator;
|
||||||
|
|
||||||
public static readonly string[] DeliveryTextVariables = new string[] { "[submarinename1]", "[location1]", "[location2]", "[submarinename2]", "[amount]", "[currencyname]" };
|
public static readonly string[] DeliveryTextVariables = new string[] { "[submarinename1]", "[location1]", "[location2]", "[submarinename2]", "[amount]", "[currencyname]" };
|
||||||
@@ -42,7 +43,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private static readonly string[] notEnoughCreditsDeliveryTextVariables = new string[] { "[currencyname]", "[submarinename]", "[location1]", "[location2]" };
|
private static readonly string[] notEnoughCreditsDeliveryTextVariables = new string[] { "[currencyname]", "[submarinename]", "[location1]", "[location2]" };
|
||||||
private static readonly string[] notEnoughCreditsPurchaseTextVariables = new string[] { "[currencyname]", "[submarinename]" };
|
private static readonly string[] notEnoughCreditsPurchaseTextVariables = new string[] { "[currencyname]", "[submarinename]" };
|
||||||
private string[] messageBoxOptions;
|
private readonly string[] messageBoxOptions;
|
||||||
|
|
||||||
public const int DeliveryFeePerDistanceTravelled = 1000;
|
public const int DeliveryFeePerDistanceTravelled = 1000;
|
||||||
public static bool ContentRefreshRequired = false;
|
public static bool ContentRefreshRequired = false;
|
||||||
@@ -65,7 +66,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public SubmarineSelection(bool transfer, Action closeAction, RectTransform parent)
|
public SubmarineSelection(bool transfer, Action closeAction, RectTransform parent)
|
||||||
{
|
{
|
||||||
if (GameMain.GameSession.Campaign == null) return;
|
if (GameMain.GameSession.Campaign == null) { return; }
|
||||||
|
|
||||||
transferService = transfer;
|
transferService = transfer;
|
||||||
purchaseService = !transfer;
|
purchaseService = !transfer;
|
||||||
@@ -83,7 +84,7 @@ namespace Barotrauma
|
|||||||
messageBoxOptions = new string[2] { TextManager.Get("Yes") + " " + TextManager.Get("initiatevoting"), TextManager.Get("Cancel") };
|
messageBoxOptions = new string[2] { TextManager.Get("Yes") + " " + TextManager.Get("initiatevoting"), TextManager.Get("Cancel") };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Submarine.MainSub?.Info == null) return;
|
if (Submarine.MainSub?.Info == null) { return; }
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,8 +185,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
for (int i = 0; i < submarineDisplays.Length; i++)
|
for (int i = 0; i < submarineDisplays.Length; i++)
|
||||||
{
|
{
|
||||||
SubmarineDisplayContent submarineDisplayElement = new SubmarineDisplayContent();
|
SubmarineDisplayContent submarineDisplayElement = new SubmarineDisplayContent
|
||||||
submarineDisplayElement.background = new GUIFrame(new RectTransform(new Vector2(1f / submarinesPerPage, 1f), submarineHorizontalGroup.RectTransform), style: null, new Color(8, 13, 19));
|
{
|
||||||
|
background = new GUIFrame(new RectTransform(new Vector2(1f / submarinesPerPage, 1f), submarineHorizontalGroup.RectTransform), style: null, new Color(8, 13, 19))
|
||||||
|
};
|
||||||
submarineDisplayElement.submarineImage = new GUIImage(new RectTransform(new Vector2(0.8f, 1f), submarineDisplayElement.background.RectTransform, Anchor.Center), null, true);
|
submarineDisplayElement.submarineImage = new GUIImage(new RectTransform(new Vector2(0.8f, 1f), submarineDisplayElement.background.RectTransform, Anchor.Center), null, true);
|
||||||
submarineDisplayElement.middleTextBlock = new GUITextBlock(new RectTransform(new Vector2(0.8f, 1f), submarineDisplayElement.background.RectTransform, Anchor.Center), string.Empty, textAlignment: Alignment.Center);
|
submarineDisplayElement.middleTextBlock = new GUITextBlock(new RectTransform(new Vector2(0.8f, 1f), submarineDisplayElement.background.RectTransform, Anchor.Center), string.Empty, textAlignment: Alignment.Center);
|
||||||
submarineDisplayElement.submarineName = new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), submarineDisplayElement.background.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, HUDLayoutSettings.Padding) }, string.Empty, textAlignment: Alignment.Center, font: GUI.SubHeadingFont);
|
submarineDisplayElement.submarineName = new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), submarineDisplayElement.background.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, HUDLayoutSettings.Padding) }, string.Empty, textAlignment: Alignment.Center, font: GUI.SubHeadingFont);
|
||||||
@@ -433,7 +436,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private SubmarineInfo GetSubToDisplay(int index)
|
private SubmarineInfo GetSubToDisplay(int index)
|
||||||
{
|
{
|
||||||
if (subsToShow.Count <= index || index < 0) return null;
|
if (subsToShow.Count <= index || index < 0) { return null; }
|
||||||
return subsToShow[index];
|
return subsToShow[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -170,6 +170,11 @@ namespace Barotrauma
|
|||||||
// ReSharper disable once PossibleMultipleEnumeration
|
// ReSharper disable once PossibleMultipleEnumeration
|
||||||
UpdateCategoryIndicators(indicators, component, data.Prefabs, data.Category, campaign, drawnSubmarine, applicableCategories);
|
UpdateCategoryIndicators(indicators, component, data.Prefabs, data.Category, campaign, drawnSubmarine, applicableCategories);
|
||||||
}
|
}
|
||||||
|
var customizeButton = component.FindChild("customizebutton", true);
|
||||||
|
if (customizeButton != null)
|
||||||
|
{
|
||||||
|
customizeButton.Visible = HasSwappableItems(data.Category);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset the order first
|
// reset the order first
|
||||||
@@ -625,6 +630,20 @@ namespace Barotrauma
|
|||||||
frameChild.DefaultColor = frameChild.Color;
|
frameChild.DefaultColor = frameChild.Color;
|
||||||
frameChild.Color = Color.Transparent;
|
frameChild.Color = Color.Transparent;
|
||||||
|
|
||||||
|
var weaponSwitchBg = new GUIButton(new RectTransform(new Vector2(0.65f), frameChild.RectTransform, Anchor.TopRight, scaleBasis: ScaleBasis.Smallest)
|
||||||
|
{ RelativeOffset = new Vector2(0.04f, 0.0f) }, style: "WeaponSwitchTab")
|
||||||
|
{
|
||||||
|
Visible = false,
|
||||||
|
CanBeSelected = false,
|
||||||
|
UserData = "customizebutton"
|
||||||
|
};
|
||||||
|
weaponSwitchBg.DefaultColor = weaponSwitchBg.Frame.DefaultColor = weaponSwitchBg.Color;
|
||||||
|
var weaponSwitchImg = new GUIImage(new RectTransform(new Vector2(0.7f), weaponSwitchBg.RectTransform, Anchor.Center), "WeaponSwitchIcon", scaleToFit: true)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
weaponSwitchImg.DefaultColor = weaponSwitchImg.Color;
|
||||||
|
|
||||||
/* UPGRADE CATEGORY
|
/* UPGRADE CATEGORY
|
||||||
* |--------------------------------------------------------|
|
* |--------------------------------------------------------|
|
||||||
* | |
|
* | |
|
||||||
@@ -670,6 +689,7 @@ namespace Barotrauma
|
|||||||
foreach (GUIComponent itemFrame in itemPreviews.Values)
|
foreach (GUIComponent itemFrame in itemPreviews.Values)
|
||||||
{
|
{
|
||||||
itemFrame.OutlineColor = itemFrame.Color = previewWhite;
|
itemFrame.OutlineColor = itemFrame.Color = previewWhite;
|
||||||
|
itemFrame.Children.ForEach(c => c.Color = itemFrame.Color);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -679,6 +699,9 @@ namespace Barotrauma
|
|||||||
TrySelectCategory(prefabs, categoryData.Category, sub);
|
TrySelectCategory(prefabs, categoryData.Category, sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var customizeCategoryButton = selectedUpgradeCategoryLayout?.FindChild("customizebutton", recursive: true) as GUIButton;
|
||||||
|
customizeCategoryButton?.OnClicked(customizeCategoryButton, customizeCategoryButton.UserData);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -688,6 +711,16 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private bool customizeTabOpen;
|
private bool customizeTabOpen;
|
||||||
|
|
||||||
|
private static bool HasSwappableItems(UpgradeCategory category)
|
||||||
|
{
|
||||||
|
if (Submarine.MainSub == null) { return false; }
|
||||||
|
return Submarine.MainSub.GetItems(true).Any(i =>
|
||||||
|
i.Prefab.SwappableItem != null &&
|
||||||
|
!i.HiddenInGame && i.AllowSwapping &&
|
||||||
|
(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)));
|
||||||
|
}
|
||||||
|
|
||||||
private void SelectUpgradeCategory(List<UpgradePrefab> prefabs, UpgradeCategory category, Submarine submarine)
|
private void SelectUpgradeCategory(List<UpgradePrefab> prefabs, UpgradeCategory category, Submarine submarine)
|
||||||
{
|
{
|
||||||
if (selectedUpgradeCategoryLayout == null) { return; }
|
if (selectedUpgradeCategoryLayout == null) { return; }
|
||||||
@@ -698,6 +731,7 @@ namespace Barotrauma
|
|||||||
foreach (GUIComponent itemFrame in itemPreviews.Values)
|
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;
|
||||||
|
itemFrame.Children.ForEach(c => c.Color = itemFrame.Color);
|
||||||
}
|
}
|
||||||
|
|
||||||
highlightWalls = category.IsWallUpgrade;
|
highlightWalls = category.IsWallUpgrade;
|
||||||
@@ -706,11 +740,7 @@ namespace Barotrauma
|
|||||||
GUIFrame frame = new GUIFrame(rectT(1.0f, 0.4f, selectedUpgradeCategoryLayout));
|
GUIFrame frame = new GUIFrame(rectT(1.0f, 0.4f, selectedUpgradeCategoryLayout));
|
||||||
GUIFrame paddedFrame = new GUIFrame(rectT(0.93f, 0.9f, frame, Anchor.Center), style: null);
|
GUIFrame paddedFrame = new GUIFrame(rectT(0.93f, 0.9f, frame, Anchor.Center), style: null);
|
||||||
|
|
||||||
bool hasSwappableItems = Submarine.MainSub.GetItems(true).Any(i =>
|
bool hasSwappableItems = HasSwappableItems(category);
|
||||||
i.Prefab.SwappableItem != null &&
|
|
||||||
!i.HiddenInGame && i.AllowSwapping &&
|
|
||||||
(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;
|
float listHeight = hasSwappableItems ? 0.9f : 1.0f;
|
||||||
|
|
||||||
@@ -725,12 +755,19 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
GUILayoutGroup buttonLayout = new GUILayoutGroup(rectT(1.0f, 0.1f, paddedFrame, anchor: Anchor.TopLeft), isHorizontal: true);
|
GUILayoutGroup buttonLayout = new GUILayoutGroup(rectT(1.0f, 0.1f, paddedFrame, anchor: Anchor.TopLeft), isHorizontal: true);
|
||||||
|
|
||||||
|
GUIButton customizeButton = new GUIButton(rectT(0.5f, 1f, buttonLayout), text: TextManager.Get("uicategory.customize"), style: "GUITabButton")
|
||||||
|
{
|
||||||
|
UserData = "customizebutton"
|
||||||
|
};
|
||||||
|
new GUIImage(new RectTransform(new Vector2(1.0f, 0.75f), customizeButton.RectTransform, Anchor.CenterLeft, scaleBasis: ScaleBasis.Smallest) { RelativeOffset = new Vector2(0.015f, 0.0f) }, "WeaponSwitchIcon", scaleToFit: true);
|
||||||
|
customizeButton.TextBlock.RectTransform.RelativeSize = new Vector2(0.7f, 1.0f);
|
||||||
|
|
||||||
GUIButton upgradeButton = new GUIButton(rectT(0.5f, 1f, buttonLayout), text: TextManager.Get("uicategory.upgrades"), style: "GUITabButton")
|
GUIButton upgradeButton = new GUIButton(rectT(0.5f, 1f, buttonLayout), text: TextManager.Get("uicategory.upgrades"), style: "GUITabButton")
|
||||||
{
|
{
|
||||||
Selected = true
|
Selected = true
|
||||||
};
|
};
|
||||||
|
|
||||||
GUIButton customizeButton = new GUIButton(rectT(0.5f, 1f, buttonLayout), text: TextManager.Get("uicategory.customize"), style: "GUITabButton");
|
GUITextBlock.AutoScaleAndNormalize(upgradeButton.TextBlock, customizeButton.TextBlock);
|
||||||
|
|
||||||
upgradeButton.OnClicked = delegate
|
upgradeButton.OnClicked = delegate
|
||||||
{
|
{
|
||||||
@@ -742,6 +779,7 @@ namespace Barotrauma
|
|||||||
foreach (GUIComponent itemFrame in itemPreviews.Values)
|
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;
|
||||||
|
itemFrame.Children.ForEach(c => c.Color = itemFrame.Color);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -754,7 +792,6 @@ namespace Barotrauma
|
|||||||
CreateSwappableItemList(prefabList, category, submarine);
|
CreateSwappableItemList(prefabList, category, submarine);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateUpgradePrefabList(prefabList, category, prefabs, submarine);
|
CreateUpgradePrefabList(prefabList, category, prefabs, submarine);
|
||||||
@@ -779,23 +816,25 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
parent.Content.ClearChildren();
|
parent.Content.ClearChildren();
|
||||||
currentUpgradeCategory = category;
|
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) && !i.HiddenInGame && i.AllowSwapping && category.ItemTags.Any(t => i.HasTag(t))).ToList();
|
var entitiesOnSub = submarine.GetItems(true).Where(i => submarine.IsEntityFoundOnThisSub(i, true) && !i.HiddenInGame && i.AllowSwapping && category.ItemTags.Any(t => i.HasTag(t))).ToList();
|
||||||
|
|
||||||
int slotIndex = 0;
|
int slotIndex = 0;
|
||||||
foreach (Item item in entitiesOnSub)
|
foreach (Item item in entitiesOnSub)
|
||||||
{
|
{
|
||||||
slotIndex++;
|
slotIndex++;
|
||||||
CreateSwappableItemSlideDown(parent, slotIndex, item, availableReplacements);
|
CreateSwappableItemSlideDown(parent, slotIndex, item, submarine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateSwappableItemSlideDown(GUIListBox parent, int slotIndex, Item item, IEnumerable<ItemPrefab> availableReplacements)
|
private void CreateSwappableItemSlideDown(GUIListBox parent, int slotIndex, Item item, Submarine submarine)
|
||||||
{
|
{
|
||||||
if (Campaign == null) { return; }
|
if (Campaign == null || submarine == null) { return; }
|
||||||
|
|
||||||
|
IEnumerable<ItemPrefab> availableReplacements = MapEntityPrefab.List.Where(p =>
|
||||||
|
p is ItemPrefab itemPrefab &&
|
||||||
|
itemPrefab.SwappableItem != null &&
|
||||||
|
itemPrefab.SwappableItem.CanBeBought &&
|
||||||
|
itemPrefab.SwappableItem.SwapIdentifier.Equals(item.Prefab.SwappableItem.SwapIdentifier, StringComparison.OrdinalIgnoreCase)).Cast<ItemPrefab>();
|
||||||
|
|
||||||
var currentOrPending = item.PendingItemSwap ?? item.Prefab;
|
var currentOrPending = item.PendingItemSwap ?? item.Prefab;
|
||||||
|
|
||||||
@@ -833,7 +872,7 @@ namespace Barotrauma
|
|||||||
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), currentOrPending.UpgradePreviewSprite,
|
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), currentOrPending.UpgradePreviewSprite,
|
||||||
TextManager.GetWithVariable(item.PendingItemSwap != null ? "upgrades.pendingitem" : "upgrades.installeditem", "[itemname]", currentOrPending.Name),
|
TextManager.GetWithVariable(item.PendingItemSwap != null ? "upgrades.pendingitem" : "upgrades.installeditem", "[itemname]", currentOrPending.Name),
|
||||||
currentOrPending.Description,
|
currentOrPending.Description,
|
||||||
0, null, addBuyButton: canUninstall, addProgressBar: false, buttonStyle: "StoreRemoveFromCrateButton"));
|
0, null, addBuyButton: canUninstall, addProgressBar: false, buttonStyle: "WeaponUninstallButton"));
|
||||||
|
|
||||||
if (canUninstall && frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton refundButton)
|
if (canUninstall && frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton refundButton)
|
||||||
{
|
{
|
||||||
@@ -876,7 +915,7 @@ namespace Barotrauma
|
|||||||
price, replacement,
|
price, replacement,
|
||||||
addBuyButton: true,
|
addBuyButton: true,
|
||||||
addProgressBar: false,
|
addProgressBar: false,
|
||||||
buttonStyle: isPurchased ? "UpgradeBuyButton" : "StoreAddToCrateButton"));
|
buttonStyle: isPurchased ? "WeaponInstallButton" : "StoreAddToCrateButton"));
|
||||||
|
|
||||||
if (!(frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton buyButton)) { continue; }
|
if (!(frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton buyButton)) { continue; }
|
||||||
if (Campaign.Money >= price)
|
if (Campaign.Money >= price)
|
||||||
@@ -1234,9 +1273,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (selectedUpgradeCategoryLayout != null)
|
if (selectedUpgradeCategoryLayout != null)
|
||||||
{
|
{
|
||||||
if (selectedUpgradeCategoryLayout.FindChild(c => c.UserData as Item == HoveredItem, recursive: true) is GUIButton itemElement && !itemElement.Selected)
|
if (selectedUpgradeCategoryLayout.FindChild(c => c.UserData as Item == HoveredItem, recursive: true) is GUIButton itemElement)
|
||||||
{
|
{
|
||||||
itemElement.OnClicked(itemElement, itemElement.UserData);
|
if (!itemElement.Selected) { itemElement.OnClicked(itemElement, itemElement.UserData); }
|
||||||
|
//TODO: enable this if/when we make ScrollToElement work with child elements of different sizes
|
||||||
|
//(itemElement.Parent?.Parent?.Parent as GUIListBox)?.ScrollToElement(itemElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1343,6 +1384,15 @@ namespace Barotrauma
|
|||||||
HoverCursor = CursorState.Hand,
|
HoverCursor = CursorState.Hand,
|
||||||
SpriteEffects = item.Rotation > 90.0f && item.Rotation < 270.0f ? SpriteEffects.FlipVertically : SpriteEffects.None
|
SpriteEffects = item.Rotation > 90.0f && item.Rotation < 270.0f ? SpriteEffects.FlipVertically : SpriteEffects.None
|
||||||
};
|
};
|
||||||
|
if (item.Prefab.SwappableItem != null)
|
||||||
|
{
|
||||||
|
new GUIImage(new RectTransform(new Vector2(0.8f), itemFrame.RectTransform, Anchor.TopLeft) { RelativeOffset = new Vector2(-0.2f) }, "WeaponSwitchIcon.DropShadow", scaleToFit: true)
|
||||||
|
{
|
||||||
|
SelectedColor = GUI.Style.Orange,
|
||||||
|
Color = previewWhite,
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1287,18 +1287,28 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private int TryAdjustIndex(int amount)
|
private int TryAdjustIndex(int amount)
|
||||||
{
|
{
|
||||||
int index = Character.Controlled == null ? 0 :
|
if (Character.Controlled == null) { return 0; }
|
||||||
crewList.Content.GetChildIndex(crewList.Content.GetChildByUserData(Character.Controlled)) + amount;
|
|
||||||
|
int currentIndex = crewList.Content.GetChildIndex(crewList.Content.GetChildByUserData(Character.Controlled));
|
||||||
|
if (currentIndex == -1) { return 0; }
|
||||||
|
|
||||||
int lastIndex = crewList.Content.CountChildren - 1;
|
int lastIndex = crewList.Content.CountChildren - 1;
|
||||||
if (index > lastIndex)
|
|
||||||
|
int index = currentIndex + amount;
|
||||||
|
for (int i = 0; i < crewList.Content.CountChildren; i++)
|
||||||
{
|
{
|
||||||
index = 0;
|
if (index > lastIndex) { index = 0; }
|
||||||
|
if (index < 0) { index = lastIndex; }
|
||||||
|
|
||||||
|
if ((crewList.Content.GetChild(index)?.UserData as Character)?.IsOnPlayerTeam ?? false)
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
index += amount;
|
||||||
}
|
}
|
||||||
if (index < 0)
|
|
||||||
{
|
return 0;
|
||||||
index = lastIndex;
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void UpdateProjectSpecific(float deltaTime)
|
partial void UpdateProjectSpecific(float deltaTime)
|
||||||
|
|||||||
+5
-1
@@ -445,9 +445,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Submarine.MainSub = leavingSub;
|
Submarine.MainSub = leavingSub;
|
||||||
GameMain.GameSession.Submarine = leavingSub;
|
GameMain.GameSession.Submarine = leavingSub;
|
||||||
|
GameMain.GameSession.SubmarineInfo = leavingSub.Info;
|
||||||
|
leavingSub.Info.FilePath = System.IO.Path.Combine(SaveUtil.TempPath, leavingSub.Info.Name + ".sub");
|
||||||
var subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
var subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
||||||
|
GameMain.GameSession.OwnedSubmarines.Add(leavingSub.Info);
|
||||||
foreach (Submarine sub in subsToLeaveBehind)
|
foreach (Submarine sub in subsToLeaveBehind)
|
||||||
{
|
{
|
||||||
|
GameMain.GameSession.OwnedSubmarines.RemoveAll(s => s != leavingSub.Info && s.Name == sub.Info.Name);
|
||||||
MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine);
|
MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine);
|
||||||
LinkedSubmarine.CreateDummy(leavingSub, sub);
|
LinkedSubmarine.CreateDummy(leavingSub, sub);
|
||||||
}
|
}
|
||||||
@@ -559,7 +563,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.R))
|
if (GUI.KeyboardDispatcher.Subscriber == null && PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.M))
|
||||||
{
|
{
|
||||||
if (GUIMessageBox.MessageBoxes.Any()) { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.MessageBoxes.Last()); }
|
if (GUIMessageBox.MessageBoxes.Any()) { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.MessageBoxes.Last()); }
|
||||||
|
|
||||||
|
|||||||
@@ -537,9 +537,12 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<SlotReference> hideSubInventories = new List<SlotReference>();
|
List<SlotReference> hideSubInventories = new List<SlotReference>();
|
||||||
|
//remove highlighted subinventory slots that can no longer be accessed
|
||||||
highlightedSubInventorySlots.RemoveWhere(s =>
|
highlightedSubInventorySlots.RemoveWhere(s =>
|
||||||
s.ParentInventory == this &&
|
s.ParentInventory == this &&
|
||||||
((s.SlotIndex < 0 || s.SlotIndex >= slots.Length || slots[s.SlotIndex] == null) || (Character.Controlled != null && !Character.Controlled.CanAccessInventory(s.Inventory))));
|
((s.SlotIndex < 0 || s.SlotIndex >= slots.Length || slots[s.SlotIndex] == null) || (Character.Controlled != null && !Character.Controlled.CanAccessInventory(s.Inventory))));
|
||||||
|
//remove highlighted subinventory slots that refer to items no longer in this inventory
|
||||||
|
highlightedSubInventorySlots.RemoveWhere(s => s.Item != null && s.ParentInventory == this && s.Item.ParentInventory != this);
|
||||||
foreach (var highlightedSubInventorySlot in highlightedSubInventorySlots)
|
foreach (var highlightedSubInventorySlot in highlightedSubInventorySlots)
|
||||||
{
|
{
|
||||||
if (highlightedSubInventorySlot.ParentInventory == this)
|
if (highlightedSubInventorySlot.ParentInventory == this)
|
||||||
|
|||||||
@@ -611,5 +611,6 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
OnResolutionChanged();
|
OnResolutionChanged();
|
||||||
}
|
}
|
||||||
|
public virtual void AddTooltipInfo(ref string description) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1094,7 +1094,10 @@ namespace Barotrauma.Items.Components
|
|||||||
if (!dockingPort.Item.Submarine.ShowSonarMarker && dockingPort.Item.Submarine != item.Submarine && !dockingPort.Item.Submarine.Info.IsOutpost) { continue; }
|
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 && item.Submarine != GameMain.NetworkMember?.RespawnManager?.RespawnShuttle && dockingPort.Item.Submarine.Info.Type != SubmarineType.Outpost)
|
if (item.Submarine != null &&
|
||||||
|
item.Submarine != GameMain.NetworkMember?.RespawnManager?.RespawnShuttle &&
|
||||||
|
dockingPort.Item.Submarine != GameMain.NetworkMember?.RespawnManager?.RespawnShuttle &&
|
||||||
|
dockingPort.Item.Submarine.Info.Type != SubmarineType.Outpost)
|
||||||
{
|
{
|
||||||
// specifically checking for friendlyNPC seems more logical here
|
// specifically checking for friendlyNPC seems more logical here
|
||||||
if (dockingPort.Item.Submarine.TeamID != item.Submarine.TeamID && dockingPort.Item.Submarine.TeamID != CharacterTeamType.FriendlyNPC) { continue; }
|
if (dockingPort.Item.Submarine.TeamID != item.Submarine.TeamID && dockingPort.Item.Submarine.TeamID != CharacterTeamType.FriendlyNPC) { continue; }
|
||||||
|
|||||||
@@ -367,9 +367,9 @@ namespace Barotrauma.Items.Components
|
|||||||
//a wire has been selected -> check if we should start dragging one of the nodes
|
//a wire has been selected -> check if we should start dragging one of the nodes
|
||||||
float nodeSelectDist = 10, sectionSelectDist = 5;
|
float nodeSelectDist = 10, sectionSelectDist = 5;
|
||||||
highlightedNodeIndex = null;
|
highlightedNodeIndex = null;
|
||||||
if (MapEntity.SelectedList.Count == 1 && MapEntity.SelectedList[0] is Item)
|
if (MapEntity.SelectedList.Count == 1 && MapEntity.SelectedList.FirstOrDefault() is Item selectedItem)
|
||||||
{
|
{
|
||||||
Wire selectedWire = ((Item)MapEntity.SelectedList[0]).GetComponent<Wire>();
|
Wire selectedWire = selectedItem.GetComponent<Wire>();
|
||||||
|
|
||||||
if (selectedWire != null)
|
if (selectedWire != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
else if (chargeSoundChannel != null)
|
else if (chargeSoundChannel != null)
|
||||||
{
|
{
|
||||||
chargeSoundChannel.FrequencyMultiplier = MathHelper.Lerp(1f, 2f, chargeRatio);
|
chargeSoundChannel.FrequencyMultiplier = MathHelper.Lerp(0.5f, 1.5f, chargeRatio);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -363,13 +363,13 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
float chargeRatio = currentChargeTime / MaxChargeTime;
|
float chargeRatio = currentChargeTime / MaxChargeTime;
|
||||||
|
|
||||||
foreach (Tuple<Sprite, Vector2> chargeSprite in chargeSprites)
|
foreach ((Sprite chargeSprite, Vector2 position) in chargeSprites)
|
||||||
{
|
{
|
||||||
chargeSprite.Item1?.Draw(spriteBatch,
|
chargeSprite?.Draw(spriteBatch,
|
||||||
drawPos - MathUtils.RotatePoint(new Vector2(chargeSprite.Item2.X * chargeRatio, chargeSprite.Item2.Y * chargeRatio) * item.Scale, rotation + MathHelper.PiOver2),
|
drawPos - MathUtils.RotatePoint(new Vector2(position.X * chargeRatio, position.Y * chargeRatio) * item.Scale, rotation + MathHelper.PiOver2),
|
||||||
item.SpriteColor,
|
item.SpriteColor,
|
||||||
rotation + MathHelper.PiOver2, item.Scale,
|
rotation + MathHelper.PiOver2, item.Scale,
|
||||||
SpriteEffects.None, item.SpriteDepth + (chargeSprite.Item1.Depth - item.Sprite.Depth));
|
SpriteEffects.None, item.SpriteDepth + (chargeSprite.Depth - item.Sprite.Depth));
|
||||||
}
|
}
|
||||||
|
|
||||||
int spinningBarrelCount = spinningBarrelSprites.Count;
|
int spinningBarrelCount = spinningBarrelSprites.Count;
|
||||||
@@ -380,7 +380,7 @@ namespace Barotrauma.Items.Components
|
|||||||
Sprite spinningBarrel = spinningBarrelSprites[i];
|
Sprite spinningBarrel = spinningBarrelSprites[i];
|
||||||
float barrelCirclePosition = (MaxCircle * i / spinningBarrelCount + currentBarrelSpin) % MaxCircle;
|
float barrelCirclePosition = (MaxCircle * i / spinningBarrelCount + currentBarrelSpin) % MaxCircle;
|
||||||
|
|
||||||
float newDepth = spinningBarrel.Depth + (barrelCirclePosition > HalfCircle ? -0.001f : 0.001f);
|
float newDepth = item.SpriteDepth + (spinningBarrel.Depth - item.Sprite.Depth) + (barrelCirclePosition > HalfCircle ? 0.0f : 0.001f);
|
||||||
|
|
||||||
float barrelColorPosition = (barrelCirclePosition + QuarterCircle) % MaxCircle;
|
float barrelColorPosition = (barrelCirclePosition + QuarterCircle) % MaxCircle;
|
||||||
float colorOffset = Math.Abs(barrelColorPosition - HalfCircle) / HalfCircle;
|
float colorOffset = Math.Abs(barrelColorPosition - HalfCircle) / HalfCircle;
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Items.Components
|
||||||
|
{
|
||||||
|
partial class Wearable
|
||||||
|
{
|
||||||
|
private void GetDamageModifierText(ref string description, float damageMultiplier, string afflictionIdentifier)
|
||||||
|
{
|
||||||
|
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
|
||||||
|
description += $"\n ‖color:{colorStr}‖-{Math.Round((1 - damageMultiplier) * 100)}%‖color:end‖ {TextManager.Get("AfflictionName." + afflictionIdentifier, true) ?? afflictionIdentifier}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AddTooltipInfo(ref string description)
|
||||||
|
{
|
||||||
|
if (damageModifiers.Any(d => d.DamageMultiplier != 1f) || SkillModifiers.Any())
|
||||||
|
{
|
||||||
|
description += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (damageModifiers.Any())
|
||||||
|
{
|
||||||
|
foreach (DamageModifier damageModifier in damageModifiers)
|
||||||
|
{
|
||||||
|
if (damageModifier.DamageMultiplier == 1f)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionIdentifiers)
|
||||||
|
{
|
||||||
|
GetDamageModifierText(ref description, damageModifier.DamageMultiplier, afflictionIdentifier);
|
||||||
|
}
|
||||||
|
foreach (string afflictionIdentifier in damageModifier.ParsedAfflictionTypes)
|
||||||
|
{
|
||||||
|
GetDamageModifierText(ref description, damageModifier.DamageMultiplier, afflictionIdentifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SkillModifiers.Any())
|
||||||
|
{
|
||||||
|
foreach (var skillModifier in SkillModifiers)
|
||||||
|
{
|
||||||
|
string colorStr = XMLExtensions.ColorToString(GUI.Style.Green);
|
||||||
|
description += $"\n ‖color:{colorStr}‖+{skillModifier.Value}‖color:end‖ {TextManager.Get("SkillName." + skillModifier.Key, true) ?? skillModifier.Key}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -296,6 +296,12 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (ItemComponent component in item.Components)
|
||||||
|
{
|
||||||
|
component.AddTooltipInfo(ref description);
|
||||||
|
}
|
||||||
|
|
||||||
if (item.Prefab.ShowContentsInTooltip && item.OwnInventory != null)
|
if (item.Prefab.ShowContentsInTooltip && item.OwnInventory != null)
|
||||||
{
|
{
|
||||||
foreach (string itemName in item.OwnInventory.AllItems.Select(it => it.Name).Distinct())
|
foreach (string itemName in item.OwnInventory.AllItems.Select(it => it.Name).Distinct())
|
||||||
@@ -950,6 +956,15 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
return CursorState.Hand;
|
return CursorState.Hand;
|
||||||
}
|
}
|
||||||
|
var container = item?.GetComponent<ItemContainer>();
|
||||||
|
if (container == null) { continue; }
|
||||||
|
if (container.Inventory.visualSlots != null)
|
||||||
|
{
|
||||||
|
if (container.Inventory.visualSlots.Any(slot => slot.IsHighlighted))
|
||||||
|
{
|
||||||
|
return CursorState.Hand;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1586,11 +1586,20 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var item = new Item(itemPrefab, pos, sub, id: itemId)
|
Item item = null;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
SpawnedInOutpost = spawnedInOutpost,
|
item = new Item(itemPrefab, pos, sub, id: itemId)
|
||||||
AllowStealing = allowStealing
|
{
|
||||||
};
|
SpawnedInOutpost = spawnedInOutpost,
|
||||||
|
AllowStealing = allowStealing
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"Failed to spawn item {itemPrefab.Name}", e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
if (item.body != null)
|
if (item.body != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace Barotrauma
|
|||||||
if (sparks)
|
if (sparks)
|
||||||
{
|
{
|
||||||
GameMain.ParticleManager.CreateParticle("spark", worldPosition,
|
GameMain.ParticleManager.CreateParticle("spark", worldPosition,
|
||||||
Rand.Vector(Rand.Range(500.0f, 800.0f)), 0.0f, hull);
|
Rand.Vector(Rand.Range(1200.0f, 2400.0f)), 0.0f, hull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,20 +29,14 @@ namespace Barotrauma
|
|||||||
public static bool SelectionChanged;
|
public static bool SelectionChanged;
|
||||||
|
|
||||||
//which entities have been selected for editing
|
//which entities have been selected for editing
|
||||||
private static List<MapEntity> selectedList = new List<MapEntity>();
|
public static HashSet<MapEntity> SelectedList { get; private set; } = new HashSet<MapEntity>();
|
||||||
public static List<MapEntity> SelectedList
|
|
||||||
{
|
public static List<MapEntity> CopiedList = new List<MapEntity>();
|
||||||
get
|
|
||||||
{
|
|
||||||
return selectedList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static List<MapEntity> copiedList = new List<MapEntity>();
|
|
||||||
|
|
||||||
private static List<MapEntity> highlightedList = new List<MapEntity>();
|
private static List<MapEntity> highlightedList = new List<MapEntity>();
|
||||||
|
|
||||||
// Test feature. Not yet saved.
|
// Test feature. Not yet saved.
|
||||||
public static Dictionary<MapEntity, List<MapEntity>> SelectionGroups { get; private set; } = new Dictionary<MapEntity, List<MapEntity>>();
|
public static Dictionary<MapEntity, HashSet<MapEntity>> SelectionGroups { get; private set; } = new Dictionary<MapEntity, HashSet<MapEntity>>();
|
||||||
|
|
||||||
private static float highlightTimer;
|
private static float highlightTimer;
|
||||||
|
|
||||||
@@ -78,25 +72,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool SelectableInEditor
|
public virtual bool SelectableInEditor => true;
|
||||||
{
|
|
||||||
get { return true; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool SelectedAny
|
public static bool SelectedAny => SelectedList.Count > 0;
|
||||||
{
|
|
||||||
get { return selectedList.Count > 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<MapEntity> CopiedList
|
public bool IsSelected => SelectedList.Contains(this);
|
||||||
{
|
|
||||||
get { return copiedList; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSelected
|
|
||||||
{
|
|
||||||
get { return selectedList.Contains(this); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsIncludedInSelection { get; set; }
|
public bool IsIncludedInSelection { get; set; }
|
||||||
|
|
||||||
@@ -131,7 +111,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (resizing)
|
if (resizing)
|
||||||
{
|
{
|
||||||
if (selectedList.Count == 0) resizing = false;
|
if (!SelectedAny)
|
||||||
|
{
|
||||||
|
resizing = false;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,19 +142,19 @@ namespace Barotrauma
|
|||||||
if (MapEntityPrefab.Selected != null)
|
if (MapEntityPrefab.Selected != null)
|
||||||
{
|
{
|
||||||
selectionPos = Vector2.Zero;
|
selectionPos = Vector2.Zero;
|
||||||
selectedList.Clear();
|
SelectedList.Clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (GUI.KeyboardDispatcher.Subscriber == null)
|
if (GUI.KeyboardDispatcher.Subscriber == null)
|
||||||
{
|
{
|
||||||
if (PlayerInput.KeyHit(Keys.Delete))
|
if (PlayerInput.KeyHit(Keys.Delete))
|
||||||
{
|
{
|
||||||
if (selectedList.Any())
|
if (SelectedAny)
|
||||||
{
|
{
|
||||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(selectedList, true));
|
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List<MapEntity>(SelectedList), true));
|
||||||
}
|
}
|
||||||
selectedList.ForEach(e => { if (!e.Removed) { e.Remove(); } });
|
SelectedList.ForEach(e => { if (!e.Removed) { e.Remove(); } });
|
||||||
selectedList.Clear();
|
SelectedList.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PlayerInput.IsCtrlDown())
|
if (PlayerInput.IsCtrlDown())
|
||||||
@@ -180,7 +163,7 @@ namespace Barotrauma
|
|||||||
if (PlayerInput.KeyHit(Keys.D))
|
if (PlayerInput.KeyHit(Keys.D))
|
||||||
{
|
{
|
||||||
bool terminate = false;
|
bool terminate = false;
|
||||||
foreach (MapEntity entity in selectedList)
|
foreach (MapEntity entity in SelectedList)
|
||||||
{
|
{
|
||||||
if (entity is Item item && item.GetComponent<Planter>() is { } planter)
|
if (entity is Item item && item.GetComponent<Planter>() is { } planter)
|
||||||
{
|
{
|
||||||
@@ -203,11 +186,11 @@ namespace Barotrauma
|
|||||||
#endif
|
#endif
|
||||||
if (PlayerInput.KeyHit(Keys.C))
|
if (PlayerInput.KeyHit(Keys.C))
|
||||||
{
|
{
|
||||||
Copy(selectedList);
|
Copy(SelectedList.ToList());
|
||||||
}
|
}
|
||||||
else if (PlayerInput.KeyHit(Keys.X))
|
else if (PlayerInput.KeyHit(Keys.X))
|
||||||
{
|
{
|
||||||
Cut(selectedList);
|
Cut(SelectedList.ToList());
|
||||||
}
|
}
|
||||||
else if (PlayerInput.KeyHit(Keys.V))
|
else if (PlayerInput.KeyHit(Keys.V))
|
||||||
{
|
{
|
||||||
@@ -215,21 +198,21 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (PlayerInput.KeyHit(Keys.G))
|
else if (PlayerInput.KeyHit(Keys.G))
|
||||||
{
|
{
|
||||||
if (selectedList.Any())
|
if (SelectedList.Any())
|
||||||
{
|
{
|
||||||
if (SelectionGroups.ContainsKey(selectedList.Last()))
|
if (SelectionGroups.ContainsKey(SelectedList.Last()))
|
||||||
{
|
{
|
||||||
// Ungroup all selected
|
// Ungroup all selected
|
||||||
selectedList.ForEach(e => SelectionGroups.Remove(e));
|
SelectedList.ForEach(e => SelectionGroups.Remove(e));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var entity in selectedList)
|
foreach (var entity in SelectedList)
|
||||||
{
|
{
|
||||||
// Remove the old group, if any
|
// Remove the old group, if any
|
||||||
SelectionGroups.Remove(entity);
|
SelectionGroups.Remove(entity);
|
||||||
// Create a group that can be accessed with any member
|
// Create a group that can be accessed with any member
|
||||||
SelectionGroups.Add(entity, selectedList);
|
SelectionGroups.Add(entity, SelectedList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,7 +262,7 @@ namespace Barotrauma
|
|||||||
Vector2 nudge = GetNudgeAmount();
|
Vector2 nudge = GetNudgeAmount();
|
||||||
if (nudge != Vector2.Zero)
|
if (nudge != Vector2.Zero)
|
||||||
{
|
{
|
||||||
foreach (MapEntity entityToNudge in selectedList) { entityToNudge.Move(nudge); }
|
foreach (MapEntity entityToNudge in SelectedList) { entityToNudge.Move(nudge); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -292,7 +275,7 @@ namespace Barotrauma
|
|||||||
//started moving selected entities
|
//started moving selected entities
|
||||||
if (startMovingPos != Vector2.Zero)
|
if (startMovingPos != Vector2.Zero)
|
||||||
{
|
{
|
||||||
Item targetContainer = GetPotentialContainer(position, selectedList);
|
Item targetContainer = GetPotentialContainer(position, SelectedList);
|
||||||
|
|
||||||
if (targetContainer != null) { targetContainer.IsHighlighted = true; }
|
if (targetContainer != null) { targetContainer.IsHighlighted = true; }
|
||||||
|
|
||||||
@@ -315,16 +298,16 @@ namespace Barotrauma
|
|||||||
//clone
|
//clone
|
||||||
if (PlayerInput.IsCtrlDown())
|
if (PlayerInput.IsCtrlDown())
|
||||||
{
|
{
|
||||||
var clones = Clone(selectedList).Where(c => c != null).ToList();
|
HashSet<MapEntity> clones = Clone(SelectedList.ToList()).Where(c => c != null).ToHashSet();
|
||||||
selectedList = clones;
|
SelectedList = clones;
|
||||||
selectedList.ForEach(c => c.Move(moveAmount));
|
SelectedList.ForEach(c => c.Move(moveAmount));
|
||||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(clones, false));
|
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List<MapEntity>(clones), false));
|
||||||
}
|
}
|
||||||
else // move
|
else // move
|
||||||
{
|
{
|
||||||
var oldRects = selectedList.Select(e => e.Rect).ToList();
|
var oldRects = SelectedList.Select(e => e.Rect).ToList();
|
||||||
List<MapEntity> deposited = new List<MapEntity>();
|
List<MapEntity> deposited = new List<MapEntity>();
|
||||||
foreach (MapEntity e in selectedList)
|
foreach (MapEntity e in SelectedList)
|
||||||
{
|
{
|
||||||
e.Move(moveAmount);
|
e.Move(moveAmount);
|
||||||
|
|
||||||
@@ -342,14 +325,14 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SubEditorScreen.StoreCommand(new TransformCommand(new List<MapEntity>(selectedList),selectedList.Select(entity => entity.Rect).ToList(), oldRects, false));
|
SubEditorScreen.StoreCommand(new TransformCommand(new List<MapEntity>(SelectedList),SelectedList.Select(entity => entity.Rect).ToList(), oldRects, false));
|
||||||
if (deposited.Any() && deposited.Any(entity => entity is Item))
|
if (deposited.Any() && deposited.Any(entity => entity is Item))
|
||||||
{
|
{
|
||||||
var depositedItems = deposited.Where(entity => entity is Item).Cast<Item>().ToList();
|
var depositedItems = deposited.Where(entity => entity is Item).Cast<Item>().ToList();
|
||||||
SubEditorScreen.StoreCommand(new InventoryPlaceCommand(targetContainer.OwnInventory, depositedItems, false));
|
SubEditorScreen.StoreCommand(new InventoryPlaceCommand(targetContainer.OwnInventory, depositedItems, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
deposited.ForEach(entity => { selectedList.Remove(entity); });
|
deposited.ForEach(entity => { SelectedList.Remove(entity); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
startMovingPos = Vector2.Zero;
|
startMovingPos = Vector2.Zero;
|
||||||
@@ -367,7 +350,7 @@ namespace Barotrauma
|
|||||||
entity.IsIncludedInSelection = false;
|
entity.IsIncludedInSelection = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MapEntity> newSelection = new List<MapEntity>();// FindSelectedEntities(selectionPos, selectionSize);
|
HashSet<MapEntity> newSelection = new HashSet<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)
|
||||||
{
|
{
|
||||||
newSelection = FindSelectedEntities(selectionPos, selectionSize);
|
newSelection = FindSelectedEntities(selectionPos, selectionSize);
|
||||||
@@ -376,9 +359,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (highLightedEntity != null)
|
if (highLightedEntity != null)
|
||||||
{
|
{
|
||||||
if (SelectionGroups.TryGetValue(highLightedEntity, out List<MapEntity> group))
|
if (SelectionGroups.TryGetValue(highLightedEntity, out HashSet<MapEntity> group))
|
||||||
{
|
{
|
||||||
newSelection.AddRange(group);
|
foreach (MapEntity entity in group.Where(e => !newSelection.Contains(e)))
|
||||||
|
{
|
||||||
|
newSelection.Add(entity);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (MapEntity entity in group)
|
foreach (MapEntity entity in group)
|
||||||
{
|
{
|
||||||
entity.IsIncludedInSelection = true;
|
entity.IsIncludedInSelection = true;
|
||||||
@@ -398,7 +385,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (MapEntity e in newSelection)
|
foreach (MapEntity e in newSelection)
|
||||||
{
|
{
|
||||||
if (selectedList.Contains(e))
|
if (SelectedList.Contains(e))
|
||||||
{
|
{
|
||||||
RemoveSelection(e);
|
RemoveSelection(e);
|
||||||
}
|
}
|
||||||
@@ -410,7 +397,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
selectedList = new List<MapEntity>(newSelection);
|
SelectedList = new HashSet<MapEntity>(newSelection);
|
||||||
//selectedList.Clear();
|
//selectedList.Clear();
|
||||||
//newSelection.ForEach(e => AddSelection(e));
|
//newSelection.ForEach(e => AddSelection(e));
|
||||||
foreach (var entity in newSelection)
|
foreach (var entity in newSelection)
|
||||||
@@ -419,23 +406,23 @@ namespace Barotrauma
|
|||||||
onGapFound: (door, gap) =>
|
onGapFound: (door, gap) =>
|
||||||
{
|
{
|
||||||
door.RefreshLinkedGap();
|
door.RefreshLinkedGap();
|
||||||
if (!selectedList.Contains(gap))
|
if (!SelectedList.Contains(gap))
|
||||||
{
|
{
|
||||||
selectedList.Add(gap);
|
SelectedList.Add(gap);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDoorFound: (door, gap) =>
|
onDoorFound: (door, gap) =>
|
||||||
{
|
{
|
||||||
if (!selectedList.Contains(door.Item))
|
if (!SelectedList.Contains(door.Item))
|
||||||
{
|
{
|
||||||
selectedList.Add(door.Item);
|
SelectedList.Add(door.Item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//select wire if both items it's connected to are selected
|
//select wire if both items it's connected to are selected
|
||||||
var selectedItems = selectedList.Where(e => e is Item).Cast<Item>().ToList();
|
var selectedItems = SelectedList.Where(e => e is Item).Cast<Item>().ToList();
|
||||||
foreach (Item item in selectedItems)
|
foreach (Item item in selectedItems)
|
||||||
{
|
{
|
||||||
if (item.Connections == null) continue;
|
if (item.Connections == null) continue;
|
||||||
@@ -443,11 +430,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (Wire w in c.Wires)
|
foreach (Wire w in c.Wires)
|
||||||
{
|
{
|
||||||
if (w == null || selectedList.Contains(w.Item)) continue;
|
if (w == null || SelectedList.Contains(w.Item)) continue;
|
||||||
|
|
||||||
if (w.OtherConnection(c) != null && selectedList.Contains(w.OtherConnection(c).Item))
|
if (w.OtherConnection(c) != null && SelectedList.Contains(w.OtherConnection(c).Item))
|
||||||
{
|
{
|
||||||
selectedList.Add(w.Item);
|
SelectedList.Add(w.Item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -471,7 +458,7 @@ namespace Barotrauma
|
|||||||
(highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))))
|
(highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))))
|
||||||
{
|
{
|
||||||
//if clicking a selected entity, start moving it
|
//if clicking a selected entity, start moving it
|
||||||
foreach (MapEntity e in selectedList)
|
foreach (MapEntity e in SelectedList)
|
||||||
{
|
{
|
||||||
if (e.IsMouseOn(position)) startMovingPos = position;
|
if (e.IsMouseOn(position)) startMovingPos = position;
|
||||||
}
|
}
|
||||||
@@ -519,7 +506,7 @@ namespace Barotrauma
|
|||||||
return ReplacedBy?.GetReplacementOrThis() ?? this;
|
return ReplacedBy?.GetReplacementOrThis() ?? this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Item GetPotentialContainer(Vector2 position, List<MapEntity> entities = null)
|
public static Item GetPotentialContainer(Vector2 position, HashSet<MapEntity> entities = null)
|
||||||
{
|
{
|
||||||
Item targetContainer = null;
|
Item targetContainer = null;
|
||||||
bool isShiftDown = PlayerInput.IsShiftDown();
|
bool isShiftDown = PlayerInput.IsShiftDown();
|
||||||
@@ -654,7 +641,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (PlayerInput.IsCtrlDown() && !wiringMode)
|
if (PlayerInput.IsCtrlDown() && !wiringMode)
|
||||||
{
|
{
|
||||||
if (selectedList.Contains(entity))
|
if (SelectedList.Contains(entity))
|
||||||
{
|
{
|
||||||
RemoveSelection(entity);
|
RemoveSelection(entity);
|
||||||
}
|
}
|
||||||
@@ -673,56 +660,60 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static void AddSelection(MapEntity entity)
|
public static void AddSelection(MapEntity entity)
|
||||||
{
|
{
|
||||||
if (selectedList.Contains(entity)) { return; }
|
if (SelectedList.Contains(entity)) { return; }
|
||||||
selectedList.Add(entity);
|
SelectedList.Add(entity);
|
||||||
HandleDoorGapLinks(entity,
|
HandleDoorGapLinks(entity,
|
||||||
onGapFound: (door, gap) =>
|
onGapFound: (door, gap) =>
|
||||||
{
|
{
|
||||||
door.RefreshLinkedGap();
|
door.RefreshLinkedGap();
|
||||||
if (!selectedList.Contains(gap))
|
if (!SelectedList.Contains(gap))
|
||||||
{
|
{
|
||||||
selectedList.Add(gap);
|
SelectedList.Add(gap);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDoorFound: (door, gap) =>
|
onDoorFound: (door, gap) =>
|
||||||
{
|
{
|
||||||
if (!selectedList.Contains(door.Item))
|
if (!SelectedList.Contains(door.Item))
|
||||||
{
|
{
|
||||||
selectedList.Add(door.Item);
|
SelectedList.Add(door.Item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandleDoorGapLinks(MapEntity entity, Action<Door, Gap> onGapFound, Action<Door, Gap> onDoorFound)
|
private static void HandleDoorGapLinks(MapEntity entity, Action<Door, Gap> onGapFound, Action<Door, Gap> onDoorFound)
|
||||||
{
|
{
|
||||||
if (entity is Item i)
|
switch (entity)
|
||||||
{
|
{
|
||||||
var door = i.GetComponent<Door>();
|
case Item i:
|
||||||
if (door != null)
|
|
||||||
{
|
{
|
||||||
var gap = door.LinkedGap;
|
var door = i.GetComponent<Door>();
|
||||||
|
var gap = door?.LinkedGap;
|
||||||
if (gap != null)
|
if (gap != null)
|
||||||
{
|
{
|
||||||
onGapFound(door, gap);
|
onGapFound(door, gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
case Gap gap:
|
||||||
else if (entity is Gap gap)
|
|
||||||
{
|
|
||||||
var door = gap.ConnectedDoor;
|
|
||||||
if (door != null)
|
|
||||||
{
|
{
|
||||||
onDoorFound(door, gap);
|
var door = gap.ConnectedDoor;
|
||||||
|
if (door != null)
|
||||||
|
{
|
||||||
|
onDoorFound(door, gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RemoveSelection(MapEntity entity)
|
public static void RemoveSelection(MapEntity entity)
|
||||||
{
|
{
|
||||||
selectedList.Remove(entity);
|
SelectedList.Remove(entity);
|
||||||
HandleDoorGapLinks(entity,
|
HandleDoorGapLinks(entity,
|
||||||
onGapFound: (door, gap) => selectedList.Remove(gap),
|
onGapFound: (door, gap) => SelectedList.Remove(gap),
|
||||||
onDoorFound: (door, gap) => selectedList.Remove(door.Item));
|
onDoorFound: (door, gap) => SelectedList.Remove(door.Item));
|
||||||
}
|
}
|
||||||
|
|
||||||
static partial void UpdateAllProjSpecific(float deltaTime)
|
static partial void UpdateAllProjSpecific(float deltaTime)
|
||||||
@@ -767,7 +758,7 @@ namespace Barotrauma
|
|||||||
//started moving the selected entities
|
//started moving the selected entities
|
||||||
if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y || isShiftDown)
|
if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y || isShiftDown)
|
||||||
{
|
{
|
||||||
foreach (MapEntity e in selectedList)
|
foreach (MapEntity e in SelectedList)
|
||||||
{
|
{
|
||||||
SpriteEffects spriteEffects = SpriteEffects.None;
|
SpriteEffects spriteEffects = SpriteEffects.None;
|
||||||
switch (e)
|
switch (e)
|
||||||
@@ -865,8 +856,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
FilteredSelectedList.Clear();
|
FilteredSelectedList.Clear();
|
||||||
if (selectedList.Count == 0) return;
|
if (SelectedList.Count == 0) return;
|
||||||
foreach (var e in selectedList)
|
foreach (var e in SelectedList)
|
||||||
{
|
{
|
||||||
if (e is Gap gap && gap.ConnectedDoor != null) { continue; }
|
if (e is Gap gap && gap.ConnectedDoor != null) { continue; }
|
||||||
FilteredSelectedList.Add(e);
|
FilteredSelectedList.Add(e);
|
||||||
@@ -885,15 +876,19 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (PlayerInput.KeyHit(Keys.N))
|
if (PlayerInput.KeyHit(Keys.N))
|
||||||
{
|
{
|
||||||
float minX = selectedList[0].WorldRect.X, maxX = selectedList[0].WorldRect.Right;
|
MapEntity firstSelected = SelectedList.First();
|
||||||
for (int i = 0; i < selectedList.Count; i++)
|
|
||||||
|
float minX = firstSelected.WorldRect.X,
|
||||||
|
maxX = firstSelected.WorldRect.Right;
|
||||||
|
|
||||||
|
foreach (MapEntity entity in SelectedList)
|
||||||
{
|
{
|
||||||
minX = Math.Min(minX, selectedList[i].WorldRect.X);
|
minX = Math.Min(minX, entity.WorldRect.X);
|
||||||
maxX = Math.Max(maxX, selectedList[i].WorldRect.Right);
|
maxX = Math.Max(maxX, entity.WorldRect.Right);
|
||||||
}
|
}
|
||||||
|
|
||||||
float centerX = (minX + maxX) / 2.0f;
|
float centerX = (minX + maxX) / 2.0f;
|
||||||
foreach (MapEntity me in selectedList)
|
foreach (MapEntity me in SelectedList)
|
||||||
{
|
{
|
||||||
me.FlipX(false);
|
me.FlipX(false);
|
||||||
me.Move(new Vector2((centerX - me.WorldPosition.X) * 2.0f, 0.0f));
|
me.Move(new Vector2((centerX - me.WorldPosition.X) * 2.0f, 0.0f));
|
||||||
@@ -901,15 +896,20 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (PlayerInput.KeyHit(Keys.M))
|
else if (PlayerInput.KeyHit(Keys.M))
|
||||||
{
|
{
|
||||||
float minY = selectedList[0].WorldRect.Y - selectedList[0].WorldRect.Height, maxY = selectedList[0].WorldRect.Y;
|
MapEntity firstSelected = SelectedList.First();
|
||||||
for (int i = 0; i < selectedList.Count; i++)
|
|
||||||
|
float minY = firstSelected.WorldRect.Y - firstSelected.WorldRect.Height,
|
||||||
|
maxY = firstSelected.WorldRect.Y;
|
||||||
|
|
||||||
|
foreach (MapEntity entity in SelectedList)
|
||||||
{
|
{
|
||||||
minY = Math.Min(minY, selectedList[i].WorldRect.Y - selectedList[i].WorldRect.Height);
|
|
||||||
maxY = Math.Max(maxY, selectedList[i].WorldRect.Y);
|
minY = Math.Min(minY, entity.WorldRect.Y - entity.WorldRect.Height);
|
||||||
|
maxY = Math.Max(maxY, entity.WorldRect.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
float centerY = (minY + maxY) / 2.0f;
|
float centerY = (minY + maxY) / 2.0f;
|
||||||
foreach (MapEntity me in selectedList)
|
foreach (MapEntity me in SelectedList)
|
||||||
{
|
{
|
||||||
me.FlipY(false);
|
me.FlipY(false);
|
||||||
me.Move(new Vector2(0.0f, (centerY - me.WorldPosition.Y) * 2.0f));
|
me.Move(new Vector2(0.0f, (centerY - me.WorldPosition.Y) * 2.0f));
|
||||||
@@ -920,19 +920,20 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static void DrawEditor(SpriteBatch spriteBatch, Camera cam)
|
public static void DrawEditor(SpriteBatch spriteBatch, Camera cam)
|
||||||
{
|
{
|
||||||
if (selectedList.Count == 1)
|
if (SelectedList.Count == 1)
|
||||||
{
|
{
|
||||||
selectedList[0].DrawEditing(spriteBatch, cam);
|
MapEntity firstSelected = SelectedList.First();
|
||||||
if (selectedList[0].ResizeHorizontal || selectedList[0].ResizeVertical)
|
firstSelected.DrawEditing(spriteBatch, cam);
|
||||||
|
if (firstSelected.ResizeHorizontal || firstSelected.ResizeVertical)
|
||||||
{
|
{
|
||||||
selectedList[0].DrawResizing(spriteBatch, cam);
|
firstSelected.DrawResizing(spriteBatch, cam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DeselectAll()
|
public static void DeselectAll()
|
||||||
{
|
{
|
||||||
selectedList.Clear();
|
SelectedList.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SelectEntity(MapEntity entity)
|
public static void SelectEntity(MapEntity entity)
|
||||||
@@ -967,10 +968,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static void Paste(Vector2 position)
|
public static void Paste(Vector2 position)
|
||||||
{
|
{
|
||||||
if (copiedList.Count == 0) { return; }
|
if (CopiedList.Count == 0) { return; }
|
||||||
|
|
||||||
List<MapEntity> prevEntities = new List<MapEntity>(mapEntityList);
|
List<MapEntity> prevEntities = new List<MapEntity>(mapEntityList);
|
||||||
Clone(copiedList);
|
Clone(CopiedList);
|
||||||
|
|
||||||
var clones = mapEntityList.Except(prevEntities).ToList();
|
var clones = mapEntityList.Except(prevEntities).ToList();
|
||||||
var nonWireClones = clones.Where(c => !(c is Item item) || item.GetComponent<Wire>() == null);
|
var nonWireClones = clones.Where(c => !(c is Item item) || item.GetComponent<Wire>() == null);
|
||||||
@@ -982,8 +983,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
Vector2 moveAmount = Submarine.VectorToWorldGrid(position - center);
|
Vector2 moveAmount = Submarine.VectorToWorldGrid(position - center);
|
||||||
|
|
||||||
selectedList = new List<MapEntity>(clones);
|
SelectedList = new HashSet<MapEntity>(clones);
|
||||||
foreach (MapEntity clone in selectedList)
|
foreach (MapEntity clone in SelectedList)
|
||||||
{
|
{
|
||||||
clone.Move(moveAmount);
|
clone.Move(moveAmount);
|
||||||
clone.Submarine = Submarine.MainSub;
|
clone.Submarine = Submarine.MainSub;
|
||||||
@@ -999,7 +1000,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
List<MapEntity> prevEntities = new List<MapEntity>(mapEntityList);
|
List<MapEntity> prevEntities = new List<MapEntity>(mapEntityList);
|
||||||
|
|
||||||
copiedList = Clone(entities);
|
CopiedList = Clone(entities);
|
||||||
|
|
||||||
//find all new entities created during cloning
|
//find all new entities created during cloning
|
||||||
var newEntities = mapEntityList.Except(prevEntities).ToList();
|
var newEntities = mapEntityList.Except(prevEntities).ToList();
|
||||||
@@ -1172,9 +1173,9 @@ namespace Barotrauma
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Find entities whose rect intersects with the "selection rect"
|
/// Find entities whose rect intersects with the "selection rect"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static List<MapEntity> FindSelectedEntities(Vector2 pos, Vector2 size)
|
public static HashSet<MapEntity> FindSelectedEntities(Vector2 pos, Vector2 size)
|
||||||
{
|
{
|
||||||
List<MapEntity> foundEntities = new List<MapEntity>();
|
HashSet<MapEntity> foundEntities = new HashSet<MapEntity>();
|
||||||
|
|
||||||
Rectangle selectionRect = Submarine.AbsRect(pos, size);
|
Rectangle selectionRect = Submarine.AbsRect(pos, size);
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ namespace Barotrauma.Particles
|
|||||||
|
|
||||||
private float angularVelocity;
|
private float angularVelocity;
|
||||||
|
|
||||||
private Vector2 dragVec = Vector2.Zero;
|
|
||||||
private float dragWait = 0;
|
|
||||||
private float collisionIgnoreTimer = 0;
|
private float collisionIgnoreTimer = 0;
|
||||||
|
|
||||||
private Vector2 size;
|
private Vector2 size;
|
||||||
@@ -35,6 +33,7 @@ namespace Barotrauma.Particles
|
|||||||
|
|
||||||
private Color color;
|
private Color color;
|
||||||
private bool changeColor;
|
private bool changeColor;
|
||||||
|
private bool UseMiddleColor;
|
||||||
|
|
||||||
private int spriteIndex;
|
private int spriteIndex;
|
||||||
|
|
||||||
@@ -112,8 +111,6 @@ namespace Barotrauma.Particles
|
|||||||
|
|
||||||
animState = 0;
|
animState = 0;
|
||||||
animFrame = 0;
|
animFrame = 0;
|
||||||
dragWait = 0;
|
|
||||||
dragVec = Vector2.Zero;
|
|
||||||
|
|
||||||
currentHull = Hull.FindHull(position, hullGuess);
|
currentHull = Hull.FindHull(position, hullGuess);
|
||||||
|
|
||||||
@@ -144,10 +141,21 @@ namespace Barotrauma.Particles
|
|||||||
|
|
||||||
angularVelocity = Rand.Range(prefab.AngularVelocityMinRad, prefab.AngularVelocityMaxRad);
|
angularVelocity = Rand.Range(prefab.AngularVelocityMinRad, prefab.AngularVelocityMaxRad);
|
||||||
|
|
||||||
totalLifeTime = prefab.LifeTime;
|
|
||||||
lifeTime = prefab.LifeTime;
|
if (prefab.LifeTimeMin <= 0.0f)
|
||||||
|
{
|
||||||
|
totalLifeTime = prefab.LifeTime;
|
||||||
|
lifeTime = prefab.LifeTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
totalLifeTime = Rand.Range(prefab.LifeTimeMin, prefab.LifeTime);
|
||||||
|
lifeTime = totalLifeTime;
|
||||||
|
}
|
||||||
|
|
||||||
startDelay = Rand.Range(prefab.StartDelayMin, prefab.StartDelayMax);
|
startDelay = Rand.Range(prefab.StartDelayMin, prefab.StartDelayMax);
|
||||||
|
|
||||||
|
UseMiddleColor = prefab.UseMiddleColor;
|
||||||
color = prefab.StartColor;
|
color = prefab.StartColor;
|
||||||
changeColor = prefab.StartColor != prefab.EndColor;
|
changeColor = prefab.StartColor != prefab.EndColor;
|
||||||
ColorMultiplier = Vector4.One;
|
ColorMultiplier = Vector4.One;
|
||||||
@@ -245,9 +253,23 @@ namespace Barotrauma.Particles
|
|||||||
size.X += sizeChange.X * deltaTime;
|
size.X += sizeChange.X * deltaTime;
|
||||||
size.Y += sizeChange.Y * deltaTime;
|
size.Y += sizeChange.Y * deltaTime;
|
||||||
|
|
||||||
if (changeColor)
|
if (UseMiddleColor)
|
||||||
{
|
{
|
||||||
color = Color.Lerp(prefab.EndColor, prefab.StartColor, lifeTime / prefab.LifeTime);
|
if (lifeTime > totalLifeTime * 0.5f)
|
||||||
|
{
|
||||||
|
color = Color.Lerp(prefab.MiddleColor, prefab.StartColor, (lifeTime / totalLifeTime - 0.5f) * 2.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
color = Color.Lerp(prefab.EndColor, prefab.MiddleColor, lifeTime / totalLifeTime * 2.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (changeColor)
|
||||||
|
{
|
||||||
|
color = Color.Lerp(prefab.EndColor, prefab.StartColor, lifeTime / totalLifeTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefab.Sprites[spriteIndex] is SpriteSheet)
|
if (prefab.Sprites[spriteIndex] is SpriteSheet)
|
||||||
@@ -399,29 +421,24 @@ namespace Barotrauma.Particles
|
|||||||
|
|
||||||
private void ApplyDrag(float dragCoefficient, float deltaTime)
|
private void ApplyDrag(float dragCoefficient, float deltaTime)
|
||||||
{
|
{
|
||||||
if (velocity.LengthSquared() < dragVec.LengthSquared())
|
|
||||||
|
float speed = velocity.Length();
|
||||||
|
velocity /= speed;
|
||||||
|
|
||||||
|
float drag = speed * speed * dragCoefficient * 0.01f * deltaTime;
|
||||||
|
if (drag > speed)
|
||||||
{
|
{
|
||||||
velocity = Vector2.Zero;
|
velocity = Vector2.Zero;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (Math.Abs(velocity.X) < 0.0001f && Math.Abs(velocity.Y) < 0.0001f) return;
|
else
|
||||||
|
|
||||||
//TODO: some better way to handle particle drag
|
|
||||||
//this doesn't work that well because the drag vector is only updated every 0.5 seconds, allowing the particle to accelerate way more than it should
|
|
||||||
//(e.g. a falling particle can freely accelerate for 0.5 seconds before the drag takes effect)
|
|
||||||
dragWait-=deltaTime;
|
|
||||||
if (dragWait <= 0f)
|
|
||||||
{
|
{
|
||||||
dragWait = 0.5f;
|
speed -= drag;
|
||||||
|
velocity *= speed;
|
||||||
float speed = velocity.Length();
|
|
||||||
|
|
||||||
dragVec = (velocity / speed) * Math.Min(speed * speed * dragCoefficient * deltaTime, 1.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
velocity -= dragVec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnWallCollisionInside(Hull prevHull, Vector2 collisionNormal)
|
private void OnWallCollisionInside(Hull prevHull, Vector2 collisionNormal)
|
||||||
{
|
{
|
||||||
if (prevHull == null) { return; }
|
if (prevHull == null) { return; }
|
||||||
|
|||||||
@@ -51,25 +51,31 @@ namespace Barotrauma.Particles
|
|||||||
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = MaxValue, MinValueFloat = MinValue), Serialize(0f, true)]
|
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = MaxValue, MinValueFloat = MinValue), Serialize(0f, true)]
|
||||||
public float VelocityMax { get; set; }
|
public float VelocityMax { get; set; }
|
||||||
|
|
||||||
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = MaxValue, MinValueFloat = MinValue), Serialize(1f, true)]
|
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = 100.0f, MinValueFloat = 0.0f), Serialize(1f, true)]
|
||||||
public float ScaleMin { get; set; }
|
public float ScaleMin { get; set; }
|
||||||
|
|
||||||
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = MaxValue, MinValueFloat = MinValue), Serialize(1f, true)]
|
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = 100.0f, MinValueFloat = 0.0f), Serialize(1f, true)]
|
||||||
public float ScaleMax { get; set; }
|
public float ScaleMax { get; set; }
|
||||||
|
|
||||||
|
|
||||||
[Editable(), Serialize("1,1", true)]
|
[Editable(), Serialize("1,1", true)]
|
||||||
public Vector2 ScaleMultiplier { get; set; }
|
public Vector2 ScaleMultiplier { get; set; }
|
||||||
|
|
||||||
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = MaxValue, MinValueFloat = MinValue), Serialize(0f, true)]
|
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = 100.0f, MinValueFloat = 0.0f), Serialize(0f, true)]
|
||||||
public float EmitInterval { get; set; }
|
public float EmitInterval { get; set; }
|
||||||
|
|
||||||
[Editable, Serialize(0, true)]
|
[Editable(ValueStep = 1, MinValueInt = 0, MaxValueInt = 1000), Serialize(0, true, description: "The number of particles to spawn per frame, or every x seconds if EmitInterval is set.")]
|
||||||
public int ParticleAmount { get; set; }
|
public int ParticleAmount { get; set; }
|
||||||
|
|
||||||
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = MaxValue, MinValueFloat = 0), Serialize(0f, true)]
|
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = 1000.0f, MinValueFloat = 0.0f), Serialize(0f, true)]
|
||||||
public float ParticlesPerSecond { get; set; }
|
public float ParticlesPerSecond { get; set; }
|
||||||
|
|
||||||
|
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = 10.0f, MinValueFloat = 0.0f), Serialize(0f, true, description: "If larger than 0, a particle is spawned every x pixels across the ray cast by a hitscan weapon.")]
|
||||||
|
public float EmitAcrossRayInterval { get; set; }
|
||||||
|
|
||||||
|
[Editable(ValueStep = 1, DecimalCount = 2, MaxValueFloat = 100.0f, MinValueFloat = 0.0f), Serialize(0f, true, description: "Delay before the emitter becomes active after being created.")]
|
||||||
|
public float InitialDelay { get; set; }
|
||||||
|
|
||||||
[Editable, Serialize(false, true)]
|
[Editable, Serialize(false, true)]
|
||||||
public bool HighQualityCollisionDetection { get; set; }
|
public bool HighQualityCollisionDetection { get; set; }
|
||||||
|
|
||||||
@@ -115,6 +121,7 @@ namespace Barotrauma.Particles
|
|||||||
{
|
{
|
||||||
private float emitTimer;
|
private float emitTimer;
|
||||||
private float burstEmitTimer;
|
private float burstEmitTimer;
|
||||||
|
private float initialDelay;
|
||||||
|
|
||||||
public readonly ParticleEmitterPrefab Prefab;
|
public readonly ParticleEmitterPrefab Prefab;
|
||||||
|
|
||||||
@@ -131,9 +138,30 @@ namespace Barotrauma.Particles
|
|||||||
|
|
||||||
public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, Tuple<Vector2, Vector2> tracerPoints = null)
|
public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||||
{
|
{
|
||||||
|
if (initialDelay < Prefab.Properties.InitialDelay)
|
||||||
|
{
|
||||||
|
initialDelay += deltaTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
emitTimer += deltaTime * amountMultiplier;
|
emitTimer += deltaTime * amountMultiplier;
|
||||||
burstEmitTimer -= deltaTime;
|
burstEmitTimer -= deltaTime;
|
||||||
|
|
||||||
|
if (Prefab.Properties.EmitAcrossRayInterval > 0.0f && tracerPoints != null)
|
||||||
|
{
|
||||||
|
Vector2 dir = tracerPoints.Item2 - tracerPoints.Item1;
|
||||||
|
if (dir.LengthSquared() > 0.001f)
|
||||||
|
{
|
||||||
|
float dist = dir.Length();
|
||||||
|
dir /= dist;
|
||||||
|
for (float z = 0.0f; z < dist; z += Prefab.Properties.EmitAcrossRayInterval)
|
||||||
|
{
|
||||||
|
Vector2 pos = tracerPoints.Item1 + dir * z;
|
||||||
|
Emit(pos, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, tracerPoints: null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Prefab.Properties.ParticlesPerSecond > 0)
|
if (Prefab.Properties.ParticlesPerSecond > 0)
|
||||||
{
|
{
|
||||||
float emitInterval = 1.0f / Prefab.Properties.ParticlesPerSecond;
|
float emitInterval = 1.0f / Prefab.Properties.ParticlesPerSecond;
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ namespace Barotrauma.Particles
|
|||||||
[Editable(0.0f, float.MaxValue), Serialize(5.0f, false, description: "How many seconds the particle remains alive.")]
|
[Editable(0.0f, float.MaxValue), Serialize(5.0f, false, description: "How many seconds the particle remains alive.")]
|
||||||
public float LifeTime { get; private set; }
|
public float LifeTime { get; private set; }
|
||||||
|
|
||||||
|
[Editable(0.0f, float.MaxValue), Serialize(0.0f, false, description: "Will randomize lifetime value between lifetime and lifetimeMin. If left to 0 will use only lifetime value.")]
|
||||||
|
public float LifeTimeMin { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
[Editable, Serialize(0.0f, false, description: "How long it takes for the particle to appear after spawning it.")]
|
[Editable, Serialize(0.0f, false, description: "How long it takes for the particle to appear after spawning it.")]
|
||||||
public float StartDelayMin { get; private set; }
|
public float StartDelayMin { get; private set; }
|
||||||
[Editable, Serialize(0.0f, false, description: "How long it takes for the particle to appear after spawning it.")]
|
[Editable, Serialize(0.0f, false, description: "How long it takes for the particle to appear after spawning it.")]
|
||||||
@@ -118,10 +122,10 @@ namespace Barotrauma.Particles
|
|||||||
[Editable, Serialize(false, false, description: "Should the particle face the direction it's moving towards.")]
|
[Editable, Serialize(false, false, description: "Should the particle face the direction it's moving towards.")]
|
||||||
public bool RotateToDirection { get; private set; }
|
public bool RotateToDirection { get; private set; }
|
||||||
|
|
||||||
[Editable, Serialize(0.0f, false, description: "Drag applied to the particle when it's moving through air.")]
|
[Editable(0.0f, float.MaxValue, DecimalCount = 3), Serialize(0.0f, false, description: "Drag applied to the particle when it's moving through air.")]
|
||||||
public float Drag { get; private set; }
|
public float Drag { get; private set; }
|
||||||
|
|
||||||
[Editable, Serialize(0.0f, false, description: "Drag applied to the particle when it's moving through water.")]
|
[Editable(0.0f, float.MaxValue, DecimalCount = 3), Serialize(0.0f, false, description: "Drag applied to the particle when it's moving through water.")]
|
||||||
public float WaterDrag { get; private set; }
|
public float WaterDrag { get; private set; }
|
||||||
|
|
||||||
private Vector2 velocityChange;
|
private Vector2 velocityChange;
|
||||||
@@ -193,9 +197,15 @@ namespace Barotrauma.Particles
|
|||||||
[Editable, Serialize("1.0,1.0,1.0,1.0", false, description: "The initial color of the particle.")]
|
[Editable, Serialize("1.0,1.0,1.0,1.0", false, description: "The initial color of the particle.")]
|
||||||
public Color StartColor { get; private set; }
|
public Color StartColor { get; private set; }
|
||||||
|
|
||||||
|
[Editable, Serialize("1.0,1.0,1.0,1.0", false, description: "The initial color of the particle.")]
|
||||||
|
public Color MiddleColor { get; private set; }
|
||||||
|
|
||||||
[Editable, Serialize("1.0,1.0,1.0,1.0", false, description: "The color of the particle at the end of its lifetime.")]
|
[Editable, Serialize("1.0,1.0,1.0,1.0", false, description: "The color of the particle at the end of its lifetime.")]
|
||||||
public Color EndColor { get; private set; }
|
public Color EndColor { get; private set; }
|
||||||
|
|
||||||
|
[Editable, Serialize(false, false, description: "If true the color will go from StartColor to EndcColor and back to StartColor.")]
|
||||||
|
public bool UseMiddleColor { get; private set; }
|
||||||
|
|
||||||
[Editable, Serialize(DrawTargetType.Air, false, description: "Should the particle be rendered in air, water or both.")]
|
[Editable, Serialize(DrawTargetType.Air, false, description: "Should the particle be rendered in air, water or both.")]
|
||||||
public DrawTargetType DrawTarget { get; private set; }
|
public DrawTargetType DrawTarget { get; private set; }
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace Barotrauma
|
|||||||
private GUIComponent locationInfoPanel;
|
private GUIComponent locationInfoPanel;
|
||||||
|
|
||||||
private GUIListBox missionList;
|
private GUIListBox missionList;
|
||||||
|
private readonly List<GUITickBox> missionTickBoxes = new List<GUITickBox>();
|
||||||
|
|
||||||
private GUIButton repairHullsButton, replaceShuttlesButton, repairItemsButton;
|
private GUIButton repairHullsButton, replaceShuttlesButton, repairItemsButton;
|
||||||
|
|
||||||
@@ -320,6 +321,10 @@ namespace Barotrauma
|
|||||||
map.SelectLocation(-1);
|
map.SelectLocation(-1);
|
||||||
}
|
}
|
||||||
map.Update(deltaTime, mapContainer);
|
map.Update(deltaTime, mapContainer);
|
||||||
|
foreach (GUITickBox tickBox in missionTickBoxes)
|
||||||
|
{
|
||||||
|
tickBox.Enabled = Campaign.AllowedToManageCampaign();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(float deltaTime)
|
public void Update(float deltaTime)
|
||||||
@@ -350,6 +355,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void SelectLocation(Location location, LocationConnection connection)
|
public void SelectLocation(Location location, LocationConnection connection)
|
||||||
{
|
{
|
||||||
|
missionTickBoxes.Clear();
|
||||||
locationInfoPanel.ClearChildren();
|
locationInfoPanel.ClearChildren();
|
||||||
//don't select the map panel if we're looking at some other tab
|
//don't select the map panel if we're looking at some other tab
|
||||||
if (selectedTab == CampaignMode.InteractionType.Map)
|
if (selectedTab == CampaignMode.InteractionType.Map)
|
||||||
@@ -451,7 +457,10 @@ namespace Barotrauma
|
|||||||
if (GUI.MouseOn == tickBox) { return false; }
|
if (GUI.MouseOn == tickBox) { return false; }
|
||||||
if (tickBox != null)
|
if (tickBox != null)
|
||||||
{
|
{
|
||||||
tickBox.Selected = !tickBox.Selected;
|
if (Campaign.AllowedToManageCampaign() && tickBox.Enabled)
|
||||||
|
{
|
||||||
|
tickBox.Selected = !tickBox.Selected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -489,26 +498,28 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
tickBox.RectTransform.MinSize = new Point(tickBox.Rect.Height, 0);
|
tickBox.RectTransform.MinSize = new Point(tickBox.Rect.Height, 0);
|
||||||
tickBox.RectTransform.IsFixedSize = true;
|
tickBox.RectTransform.IsFixedSize = true;
|
||||||
if (Campaign.AllowedToManageCampaign())
|
tickBox.Box.DisabledColor = tickBox.Box.Color * 0.8f;
|
||||||
|
tickBox.Enabled = Campaign.AllowedToManageCampaign();
|
||||||
|
tickBox.OnSelected += (GUITickBox tb) =>
|
||||||
{
|
{
|
||||||
tickBox.OnSelected += (GUITickBox tb) =>
|
if (!Campaign.AllowedToManageCampaign()) { return false; }
|
||||||
|
|
||||||
|
if (tb.Selected)
|
||||||
{
|
{
|
||||||
if (tb.Selected)
|
Campaign.Map.CurrentLocation.SelectMission(mission);
|
||||||
{
|
}
|
||||||
Campaign.Map.CurrentLocation.SelectMission(mission);
|
else
|
||||||
}
|
{
|
||||||
else
|
Campaign.Map.CurrentLocation.DeselectMission(mission);
|
||||||
{
|
}
|
||||||
Campaign.Map.CurrentLocation.DeselectMission(mission);
|
if ((Campaign is MultiPlayerCampaign multiPlayerCampaign) && !multiPlayerCampaign.SuppressStateSending &&
|
||||||
}
|
Campaign.AllowedToManageCampaign())
|
||||||
if ((Campaign is MultiPlayerCampaign multiPlayerCampaign) && !multiPlayerCampaign.SuppressStateSending &&
|
{
|
||||||
Campaign.AllowedToManageCampaign())
|
GameMain.Client?.SendCampaignState();
|
||||||
{
|
}
|
||||||
GameMain.Client?.SendCampaignState();
|
return true;
|
||||||
}
|
};
|
||||||
return true;
|
missionTickBoxes.Add(tickBox);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayoutGroup difficultyIndicatorGroup = null;
|
GUILayoutGroup difficultyIndicatorGroup = null;
|
||||||
if (mission.Difficulty.HasValue)
|
if (mission.Difficulty.HasValue)
|
||||||
@@ -578,6 +589,8 @@ namespace Barotrauma
|
|||||||
if (prevSelectedLocation == selectedLocation)
|
if (prevSelectedLocation == selectedLocation)
|
||||||
{
|
{
|
||||||
missionList.BarScroll = prevMissionListScroll;
|
missionList.BarScroll = prevMissionListScroll;
|
||||||
|
missionList.UpdateDimensions();
|
||||||
|
missionList.UpdateScrollBarSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,6 +628,7 @@ namespace Barotrauma
|
|||||||
StartButton.Visible = false;
|
StartButton.Visible = false;
|
||||||
missionList.Enabled = false;
|
missionList.Enabled = false;
|
||||||
}
|
}
|
||||||
|
//locationInfoPanel?.UpdateAuto(1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectTab(CampaignMode.InteractionType tab)
|
public void SelectTab(CampaignMode.InteractionType tab)
|
||||||
|
|||||||
@@ -867,9 +867,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
int.TryParse(maxPlayersBox.Text, out int currMaxPlayers);
|
int.TryParse(maxPlayersBox.Text, out int currMaxPlayers);
|
||||||
currMaxPlayers = (int)MathHelper.Clamp(currMaxPlayers + (int)button.UserData, 1, NetConfig.MaxPlayers);
|
currMaxPlayers = (int)MathHelper.Clamp(currMaxPlayers + (int)button.UserData, 1, NetConfig.MaxPlayers);
|
||||||
|
|
||||||
maxPlayersBox.Text = currMaxPlayers.ToString();
|
maxPlayersBox.Text = currMaxPlayers.ToString();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1322,8 +1320,18 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
maxPlayersBox = new GUITextBox(new RectTransform(new Vector2(0.6f, 1.0f), buttonContainer.RectTransform), textAlignment: Alignment.Center)
|
maxPlayersBox = new GUITextBox(new RectTransform(new Vector2(0.6f, 1.0f), buttonContainer.RectTransform), textAlignment: Alignment.Center)
|
||||||
{
|
{
|
||||||
Text = maxPlayers.ToString(),
|
Text = maxPlayers.ToString()
|
||||||
CanBeFocused = false
|
};
|
||||||
|
maxPlayersBox.OnEnterPressed += (GUITextBox sender, string text) =>
|
||||||
|
{
|
||||||
|
maxPlayersBox.Deselect();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
maxPlayersBox.OnDeselected += (GUITextBox sender, Microsoft.Xna.Framework.Input.Keys key) =>
|
||||||
|
{
|
||||||
|
int.TryParse(maxPlayersBox.Text, out int currMaxPlayers);
|
||||||
|
currMaxPlayers = (int)MathHelper.Clamp(currMaxPlayers, 1, NetConfig.MaxPlayers);
|
||||||
|
maxPlayersBox.Text = currMaxPlayers.ToString();
|
||||||
};
|
};
|
||||||
new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIPlusButton", textAlignment: Alignment.Center)
|
new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIPlusButton", textAlignment: Alignment.Center)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ namespace Barotrauma
|
|||||||
element.Add(new XAttribute("particle", prefab.Identifier));
|
element.Add(new XAttribute("particle", prefab.Identifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializableProperty.SerializeProperties(emitterProperties, element, saveIfDefault: false);
|
SerializableProperty.SerializeProperties(emitterProperties, element, saveIfDefault: false, ignoreEditable: true);
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
|||||||
@@ -2373,10 +2373,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, saveFrame.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
|
new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, saveFrame.RectTransform, Anchor.Center), style: "GUIBackgroundBlocker");
|
||||||
|
|
||||||
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.25f, 0.3f), saveFrame.RectTransform, Anchor.Center) { MinSize = new Point(400, 300) });
|
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.25f, 0.35f), saveFrame.RectTransform, Anchor.Center) { MinSize = new Point(400, 350) });
|
||||||
GUILayoutGroup paddedSaveFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), innerFrame.RectTransform, Anchor.Center))
|
GUILayoutGroup paddedSaveFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), innerFrame.RectTransform, Anchor.Center))
|
||||||
{
|
{
|
||||||
AbsoluteSpacing = 5,
|
AbsoluteSpacing = GUI.IntScale(5),
|
||||||
Stretch = true
|
Stretch = true
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2393,13 +2393,20 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedSaveFrame.RectTransform),
|
var descriptionContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), paddedSaveFrame.RectTransform));
|
||||||
TextManager.Get("SaveItemAssemblyDialogDescription"));
|
descriptionBox = new GUITextBox(new RectTransform(Vector2.One, descriptionContainer.Content.RectTransform, Anchor.TopLeft),
|
||||||
descriptionBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.3f), paddedSaveFrame.RectTransform))
|
font: GUI.SmallFont, style: "GUITextBoxNoBorder", wrap: true, textAlignment: Alignment.TopLeft)
|
||||||
{
|
{
|
||||||
UserData = "description",
|
Padding = new Vector4(10 * GUI.Scale)
|
||||||
Wrap = true,
|
};
|
||||||
Text = ""
|
|
||||||
|
descriptionBox.OnTextChanged += (textBox, text) =>
|
||||||
|
{
|
||||||
|
Vector2 textSize = textBox.Font.MeasureString(descriptionBox.WrappedText);
|
||||||
|
textBox.RectTransform.NonScaledSize = new Point(textBox.RectTransform.NonScaledSize.X, Math.Max(descriptionContainer.Content.Rect.Height, (int)textSize.Y + 10));
|
||||||
|
descriptionContainer.UpdateScrollBarSize();
|
||||||
|
descriptionContainer.BarScroll = 1.0f;
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
var buttonArea = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), paddedSaveFrame.RectTransform), style: null);
|
var buttonArea = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), paddedSaveFrame.RectTransform), style: null);
|
||||||
@@ -2417,6 +2424,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
OnClicked = SaveAssembly
|
OnClicked = SaveAssembly
|
||||||
};
|
};
|
||||||
|
buttonArea.RectTransform.MinSize = new Point(0, buttonArea.Children.First().RectTransform.MinSize.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -2460,7 +2468,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hideInMenus = !(nameBox.Parent.GetChildByUserData("hideinmenus") is GUITickBox hideInMenusTickBox) ? false : hideInMenusTickBox.Selected;
|
bool hideInMenus = nameBox.Parent.GetChildByUserData("hideinmenus") is GUITickBox hideInMenusTickBox && hideInMenusTickBox.Selected;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
string saveFolder = ItemAssemblyPrefab.VanillaSaveFolder;
|
string saveFolder = ItemAssemblyPrefab.VanillaSaveFolder;
|
||||||
#else
|
#else
|
||||||
@@ -2479,7 +2487,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
string filePath = Path.Combine(saveFolder, nameBox.Text + ".xml");
|
string filePath = Path.Combine(saveFolder, nameBox.Text + ".xml");
|
||||||
|
|
||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
{
|
{
|
||||||
var msgBox = new GUIMessageBox(TextManager.Get("Warning"), TextManager.Get("ItemAssemblyFileExistsWarning"), new[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
var msgBox = new GUIMessageBox(TextManager.Get("Warning"), TextManager.Get("ItemAssemblyFileExistsWarning"), new[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||||
@@ -2494,18 +2501,27 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Save();
|
var identifier = nameBox.Text.ToLowerInvariant().Replace(" ", "");
|
||||||
|
var existingPrefab = MapEntityPrefab.Find(null, identifier, showErrorMessages: false);
|
||||||
|
if (existingPrefab != null && System.IO.Path.GetDirectoryName(existingPrefab.FilePath) == ItemAssemblyPrefab.VanillaSaveFolder)
|
||||||
|
{
|
||||||
|
var msgBox = new GUIMessageBox(TextManager.Get("Warning"), TextManager.Get("ItemAssemblyVanillaFileExistsWarning"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Save()
|
void Save()
|
||||||
{
|
{
|
||||||
XDocument doc = new XDocument(ItemAssemblyPrefab.Save(MapEntity.SelectedList, nameBox.Text, descriptionBox.Text, hideInMenus));
|
XDocument doc = new XDocument(ItemAssemblyPrefab.Save(MapEntity.SelectedList.ToList(), nameBox.Text, descriptionBox.Text, hideInMenus));
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
doc.Save(filePath);
|
doc.Save(filePath);
|
||||||
#else
|
#else
|
||||||
doc.SaveSafe(filePath);
|
doc.SaveSafe(filePath);
|
||||||
#endif
|
#endif
|
||||||
new ItemAssemblyPrefab(filePath);
|
new ItemAssemblyPrefab(filePath, allowOverwrite: true);
|
||||||
UpdateEntityList();
|
UpdateEntityList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3002,8 +3018,11 @@ namespace Barotrauma
|
|||||||
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));
|
foreach (MapEntity match in MapEntity.mapEntityList.Where(e => e.prefab != null && targets.Any(t => t.prefab?.Identifier == e.prefab.Identifier) && !MapEntity.SelectedList.Contains(e)))
|
||||||
MapEntity.SelectedList.AddRange(matching);
|
{
|
||||||
|
if (MapEntity.SelectedList.Contains(match)) { continue; }
|
||||||
|
MapEntity.SelectedList.Add(match);
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
new ContextMenuOption("SubEditor.AddImage", isEnabled: true, onSelected: ImageManager.CreateImageWizard),
|
new ContextMenuOption("SubEditor.AddImage", isEnabled: true, onSelected: ImageManager.CreateImageWizard),
|
||||||
new ContextMenuOption("SubEditor.ToggleImageEditing", isEnabled: true, onSelected: delegate
|
new ContextMenuOption("SubEditor.ToggleImageEditing", isEnabled: true, onSelected: delegate
|
||||||
@@ -4716,9 +4735,9 @@ namespace Barotrauma
|
|||||||
CloseItem();
|
CloseItem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (MapEntity.SelectedList.Count == 1 && WiringMode)
|
else if (MapEntity.SelectedList.Count == 1 && WiringMode && MapEntity.SelectedList.FirstOrDefault() is Item item)
|
||||||
{
|
{
|
||||||
(MapEntity.SelectedList[0] as Item)?.UpdateHUD(cam, dummyCharacter, (float)deltaTime);
|
item.UpdateHUD(cam, dummyCharacter, (float)deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterHUD.Update((float)deltaTime, dummyCharacter, cam);
|
CharacterHUD.Update((float)deltaTime, dummyCharacter, cam);
|
||||||
|
|||||||
@@ -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.1400.1.0</Version>
|
<Version>0.1400.2.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.1400.1.0</Version>
|
<Version>0.1400.2.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.1400.1.0</Version>
|
<Version>0.1400.2.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.1400.1.0</Version>
|
<Version>0.1400.2.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.1400.1.0</Version>
|
<Version>0.1400.2.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,7 +283,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (extraData != null)
|
if (extraData != null)
|
||||||
{
|
{
|
||||||
int min = 0, max = 9;
|
const int min = 0, max = 9;
|
||||||
switch ((NetEntityEvent.Type)extraData[0])
|
switch ((NetEntityEvent.Type)extraData[0])
|
||||||
{
|
{
|
||||||
case NetEntityEvent.Type.InventoryState:
|
case NetEntityEvent.Type.InventoryState:
|
||||||
@@ -331,6 +331,7 @@ namespace Barotrauma
|
|||||||
case NetEntityEvent.Type.AssignCampaignInteraction:
|
case NetEntityEvent.Type.AssignCampaignInteraction:
|
||||||
msg.WriteRangedInteger(6, min, max);
|
msg.WriteRangedInteger(6, min, max);
|
||||||
msg.Write((byte)CampaignInteractionType);
|
msg.Write((byte)CampaignInteractionType);
|
||||||
|
msg.Write(RequireConsciousnessForCustomInteract);
|
||||||
break;
|
break;
|
||||||
case NetEntityEvent.Type.ObjectiveManagerState:
|
case NetEntityEvent.Type.ObjectiveManagerState:
|
||||||
msg.WriteRangedInteger(7, min, max);
|
msg.WriteRangedInteger(7, min, max);
|
||||||
|
|||||||
@@ -19,12 +19,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
character.WriteSpawnData(msg, character.ID, restrictMessageSize: false);
|
character.WriteSpawnData(msg, character.ID, restrictMessageSize: false);
|
||||||
msg.Write(terroristCharacters.Contains(character));
|
msg.Write(terroristCharacters.Contains(character));
|
||||||
List<Item> characterItems = characterDictionary[character];
|
msg.Write((ushort)characterItems[character].Count());
|
||||||
// items must be written in a specific sequence so that child items aren't written before their parents
|
foreach (Item item in characterItems[character])
|
||||||
msg.Write((ushort)characterItems.Count());
|
|
||||||
foreach (Item item in characterItems)
|
|
||||||
{
|
{
|
||||||
item.WriteSpawnData(msg, item.ID, item.ParentInventory.Owner?.ID ?? Entity.NullEntityID, 0);
|
item.WriteSpawnData(msg, item.ID, item.ParentInventory?.Owner?.ID ?? Entity.NullEntityID, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,10 @@ namespace Barotrauma
|
|||||||
foreach (Character character in characters)
|
foreach (Character character in characters)
|
||||||
{
|
{
|
||||||
character.WriteSpawnData(msg, character.ID, restrictMessageSize: false);
|
character.WriteSpawnData(msg, character.ID, restrictMessageSize: false);
|
||||||
List<Item> characterItems = characterDictionary[character];
|
msg.Write((ushort)characterItems[character].Count());
|
||||||
// items must be written in a specific sequence so that child items aren't written before their parents
|
foreach (Item item in characterItems[character])
|
||||||
msg.Write((ushort)characterItems.Count());
|
|
||||||
foreach (Item item in characterItems)
|
|
||||||
{
|
{
|
||||||
item.WriteSpawnData(msg, item.ID, item.ParentInventory.Owner?.ID ?? Entity.NullEntityID, 0);
|
item.WriteSpawnData(msg, item.ID, item.ParentInventory?.Owner?.ID ?? Entity.NullEntityID, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,9 +260,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Submarine.MainSub = leavingSub;
|
Submarine.MainSub = leavingSub;
|
||||||
GameMain.GameSession.Submarine = leavingSub;
|
GameMain.GameSession.Submarine = leavingSub;
|
||||||
|
GameMain.GameSession.SubmarineInfo = leavingSub.Info;
|
||||||
|
leavingSub.Info.FilePath = System.IO.Path.Combine(SaveUtil.TempPath, leavingSub.Info.Name + ".sub");
|
||||||
var subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
var subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
||||||
|
GameMain.GameSession.OwnedSubmarines.Add(leavingSub.Info);
|
||||||
foreach (Submarine sub in subsToLeaveBehind)
|
foreach (Submarine sub in subsToLeaveBehind)
|
||||||
{
|
{
|
||||||
|
GameMain.GameSession.OwnedSubmarines.RemoveAll(s => s != leavingSub.Info && s.Name == sub.Info.Name);
|
||||||
MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine);
|
MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine);
|
||||||
LinkedSubmarine.CreateDummy(leavingSub, sub);
|
LinkedSubmarine.CreateDummy(leavingSub, sub);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.1400.1.0</Version>
|
<Version>0.1400.2.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>
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
<Character file="Content/Characters/Variants/Hammerheadgold_m.xml" />
|
<Character file="Content/Characters/Variants/Hammerheadgold_m.xml" />
|
||||||
<Character file="Content/Characters/Variants/Crawler_hatchling/Crawler_hatchling.xml" />
|
<Character file="Content/Characters/Variants/Crawler_hatchling/Crawler_hatchling.xml" />
|
||||||
<Character file="Content/Characters/Variants/Mudraptor_hatchling/Mudraptor_hatchling.xml" />
|
<Character file="Content/Characters/Variants/Mudraptor_hatchling/Mudraptor_hatchling.xml" />
|
||||||
|
<Character file="Content/Characters/Variants/Mudraptor_passive/Mudraptor_passive.xml" />
|
||||||
<Character file="Content/Characters/Variants/Tigerthresher_hatchling/Tigerthresher_hatchling.xml" />
|
<Character file="Content/Characters/Variants/Tigerthresher_hatchling/Tigerthresher_hatchling.xml" />
|
||||||
<MapCreature file="Content/Items/Gardening/ballastflora.xml" />
|
<MapCreature file="Content/Items/Gardening/ballastflora.xml" />
|
||||||
<Wreck file="Content/Map/Wrecks/Dugong_Wrecked.sub" />
|
<Wreck file="Content/Map/Wrecks/Dugong_Wrecked.sub" />
|
||||||
@@ -148,7 +149,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" />
|
<Structure file="Content/Map/Pirates/PirateStructures.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" />
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public enum CirclePhase { Start, CloseIn, FallBack, Advance, Strike }
|
public enum CirclePhase { Start, CloseIn, FallBack, Advance, Strike }
|
||||||
|
|
||||||
|
public enum WallTargetingMethod
|
||||||
|
{
|
||||||
|
Target = 0x1,
|
||||||
|
Heading = 0x2,
|
||||||
|
Steering = 0x4
|
||||||
|
}
|
||||||
|
|
||||||
partial class EnemyAIController : AIController
|
partial class EnemyAIController : AIController
|
||||||
{
|
{
|
||||||
public static bool DisableEnemyAI;
|
public static bool DisableEnemyAI;
|
||||||
@@ -54,7 +61,7 @@ namespace Barotrauma
|
|||||||
private float attackLimbResetTimer;
|
private float attackLimbResetTimer;
|
||||||
|
|
||||||
private bool IsAttackRunning => AttackingLimb != null && AttackingLimb.attack.IsRunning;
|
private bool IsAttackRunning => AttackingLimb != null && AttackingLimb.attack.IsRunning;
|
||||||
private bool IsCoolDownRunning => AttackingLimb != null && AttackingLimb.attack.CoolDownTimer > 0;
|
private bool IsCoolDownRunning => AttackingLimb != null && AttackingLimb.attack.CoolDownTimer > 0 || _previousAttackingLimb != null && _previousAttackingLimb.attack.CoolDownTimer > 0;
|
||||||
public float CombatStrength => AIParams.CombatStrength;
|
public float CombatStrength => AIParams.CombatStrength;
|
||||||
private float Sight => AIParams.Sight;
|
private float Sight => AIParams.Sight;
|
||||||
private float Hearing => AIParams.Hearing;
|
private float Hearing => AIParams.Hearing;
|
||||||
@@ -63,14 +70,18 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private FishAnimController FishAnimController => Character.AnimController as FishAnimController;
|
private FishAnimController FishAnimController => Character.AnimController as FishAnimController;
|
||||||
|
|
||||||
//the limb selected for the current attack
|
|
||||||
private Limb _attackingLimb;
|
private Limb _attackingLimb;
|
||||||
|
private Limb _previousAttackingLimb;
|
||||||
public Limb AttackingLimb
|
public Limb AttackingLimb
|
||||||
{
|
{
|
||||||
get { return _attackingLimb; }
|
get { return _attackingLimb; }
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
attackLimbResetTimer = 0;
|
attackLimbResetTimer = 0;
|
||||||
|
if (_attackingLimb != value)
|
||||||
|
{
|
||||||
|
_previousAttackingLimb = _attackingLimb;
|
||||||
|
}
|
||||||
_attackingLimb = value;
|
_attackingLimb = value;
|
||||||
attackVector = null;
|
attackVector = null;
|
||||||
Reverse = _attackingLimb != null && _attackingLimb.attack.Reverse;
|
Reverse = _attackingLimb != null && _attackingLimb.attack.Reverse;
|
||||||
@@ -342,6 +353,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
targetingTag = "weaker";
|
targetingTag = "weaker";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetingTag = "equal";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -480,10 +495,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
CharacterParams.TargetParams targetingParams = null;
|
CharacterParams.TargetParams targetingParams = null;
|
||||||
UpdateTargets(Character, out targetingParams);
|
UpdateTargets(Character, out targetingParams);
|
||||||
if (!IsLatchedOnSub)
|
|
||||||
{
|
|
||||||
UpdateWallTarget(requiredHoleCount);
|
|
||||||
}
|
|
||||||
updateTargetsTimer = updateTargetsInterval * Rand.Range(0.75f, 1.25f);
|
updateTargetsTimer = updateTargetsInterval * Rand.Range(0.75f, 1.25f);
|
||||||
if (SelectedAiTarget == null)
|
if (SelectedAiTarget == null)
|
||||||
{
|
{
|
||||||
@@ -494,6 +505,10 @@ namespace Barotrauma
|
|||||||
selectedTargetingParams = targetingParams;
|
selectedTargetingParams = targetingParams;
|
||||||
State = targetingParams.State;
|
State = targetingParams.State;
|
||||||
}
|
}
|
||||||
|
if (SelectedAiTarget?.Entity != null && !IsLatchedOnSub && State == AIState.Attack || State == AIState.Aggressive || State == AIState.PassiveAggressive)
|
||||||
|
{
|
||||||
|
UpdateWallTarget(requiredHoleCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1004,12 +1019,8 @@ namespace Barotrauma
|
|||||||
if (!w.SectionBodyDisabled(i))
|
if (!w.SectionBodyDisabled(i))
|
||||||
{
|
{
|
||||||
isBroken = false;
|
isBroken = false;
|
||||||
Vector2 sectionPos = w.SectionPosition(i);
|
Vector2 sectionPos = w.SectionPosition(i, world: true);
|
||||||
attackWorldPos = sectionPos;
|
attackWorldPos = sectionPos;
|
||||||
if (w.Submarine != null)
|
|
||||||
{
|
|
||||||
attackWorldPos += w.Submarine.Position;
|
|
||||||
}
|
|
||||||
attackSimPos = ConvertUnits.ToSimUnits(attackWorldPos);
|
attackSimPos = ConvertUnits.ToSimUnits(attackWorldPos);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1027,18 +1038,19 @@ namespace Barotrauma
|
|||||||
bool pursue = false;
|
bool pursue = false;
|
||||||
if (IsCoolDownRunning)
|
if (IsCoolDownRunning)
|
||||||
{
|
{
|
||||||
if (AttackingLimb.attack.CoolDownTimer >= AttackingLimb.attack.CoolDown + AttackingLimb.attack.CurrentRandomCoolDown - AttackingLimb.attack.AfterAttackDelay)
|
var currentAttackLimb = AttackingLimb ?? _previousAttackingLimb;
|
||||||
|
if (currentAttackLimb.attack.CoolDownTimer >= currentAttackLimb.attack.CoolDown + currentAttackLimb.attack.CurrentRandomCoolDown - currentAttackLimb.attack.AfterAttackDelay)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (AttackingLimb.attack.AfterAttack)
|
switch (currentAttackLimb.attack.AfterAttack)
|
||||||
{
|
{
|
||||||
case AIBehaviorAfterAttack.Pursue:
|
case AIBehaviorAfterAttack.Pursue:
|
||||||
case AIBehaviorAfterAttack.PursueIfCanAttack:
|
case AIBehaviorAfterAttack.PursueIfCanAttack:
|
||||||
if (AttackingLimb.attack.SecondaryCoolDown <= 0)
|
if (currentAttackLimb.attack.SecondaryCoolDown <= 0)
|
||||||
{
|
{
|
||||||
// No (valid) secondary cooldown defined.
|
// No (valid) secondary cooldown defined.
|
||||||
if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
|
if (currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
|
||||||
{
|
{
|
||||||
canAttack = false;
|
canAttack = false;
|
||||||
pursue = true;
|
pursue = true;
|
||||||
@@ -1051,13 +1063,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (AttackingLimb.attack.SecondaryCoolDownTimer <= 0)
|
if (currentAttackLimb.attack.SecondaryCoolDownTimer <= 0)
|
||||||
{
|
{
|
||||||
// Don't allow attacking when the attack target has just changed.
|
// Don't allow attacking when the attack target has just changed.
|
||||||
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
||||||
{
|
{
|
||||||
canAttack = false;
|
canAttack = false;
|
||||||
if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack)
|
if (currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack)
|
||||||
{
|
{
|
||||||
// Fall back if cannot attack.
|
// Fall back if cannot attack.
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, true);
|
UpdateFallBack(attackWorldPos, deltaTime, true);
|
||||||
@@ -1068,7 +1080,7 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the secondary cooldown is defined and expired, check if we can switch the attack
|
// If the secondary cooldown is defined and expired, check if we can switch the attack
|
||||||
var newLimb = GetAttackLimb(attackWorldPos, AttackingLimb);
|
var newLimb = GetAttackLimb(attackWorldPos, currentAttackLimb);
|
||||||
if (newLimb != null)
|
if (newLimb != null)
|
||||||
{
|
{
|
||||||
// Attack with the new limb
|
// Attack with the new limb
|
||||||
@@ -1077,7 +1089,7 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No new limb was found.
|
// No new limb was found.
|
||||||
if (AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
|
if (currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
|
||||||
{
|
{
|
||||||
canAttack = false;
|
canAttack = false;
|
||||||
pursue = true;
|
pursue = true;
|
||||||
@@ -1099,26 +1111,26 @@ namespace Barotrauma
|
|||||||
break;
|
break;
|
||||||
case AIBehaviorAfterAttack.FallBackUntilCanAttack:
|
case AIBehaviorAfterAttack.FallBackUntilCanAttack:
|
||||||
case AIBehaviorAfterAttack.FollowThroughUntilCanAttack:
|
case AIBehaviorAfterAttack.FollowThroughUntilCanAttack:
|
||||||
if (AttackingLimb.attack.SecondaryCoolDown <= 0)
|
if (currentAttackLimb.attack.SecondaryCoolDown <= 0)
|
||||||
{
|
{
|
||||||
// No (valid) secondary cooldown defined.
|
// No (valid) secondary cooldown defined.
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (AttackingLimb.attack.SecondaryCoolDownTimer <= 0)
|
if (currentAttackLimb.attack.SecondaryCoolDownTimer <= 0)
|
||||||
{
|
{
|
||||||
// Don't allow attacking when the attack target has just changed.
|
// Don't allow attacking when the attack target has just changed.
|
||||||
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
||||||
{
|
{
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the secondary cooldown is defined and expired, check if we can switch the attack
|
// If the secondary cooldown is defined and expired, check if we can switch the attack
|
||||||
var newLimb = GetAttackLimb(attackWorldPos, AttackingLimb);
|
var newLimb = GetAttackLimb(attackWorldPos, currentAttackLimb);
|
||||||
if (newLimb != null)
|
if (newLimb != null)
|
||||||
{
|
{
|
||||||
// Attack with the new limb
|
// Attack with the new limb
|
||||||
@@ -1127,7 +1139,7 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No new limb was found.
|
// No new limb was found.
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1135,13 +1147,13 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Cooldown not yet expired -> steer away from the target
|
// Cooldown not yet expired -> steer away from the target
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, AttackingLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AIBehaviorAfterAttack.IdleUntilCanAttack:
|
case AIBehaviorAfterAttack.IdleUntilCanAttack:
|
||||||
if (AttackingLimb.attack.SecondaryCoolDown <= 0)
|
if (currentAttackLimb.attack.SecondaryCoolDown <= 0)
|
||||||
{
|
{
|
||||||
// No (valid) secondary cooldown defined.
|
// No (valid) secondary cooldown defined.
|
||||||
UpdateIdle(deltaTime, followLastTarget: false);
|
UpdateIdle(deltaTime, followLastTarget: false);
|
||||||
@@ -1149,7 +1161,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (AttackingLimb.attack.SecondaryCoolDownTimer <= 0)
|
if (currentAttackLimb.attack.SecondaryCoolDownTimer <= 0)
|
||||||
{
|
{
|
||||||
// Don't allow attacking when the attack target has just changed.
|
// Don't allow attacking when the attack target has just changed.
|
||||||
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
||||||
@@ -1160,7 +1172,7 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the secondary cooldown is defined and expired, check if we can switch the attack
|
// If the secondary cooldown is defined and expired, check if we can switch the attack
|
||||||
var newLimb = GetAttackLimb(attackWorldPos, AttackingLimb);
|
var newLimb = GetAttackLimb(attackWorldPos, currentAttackLimb);
|
||||||
if (newLimb != null)
|
if (newLimb != null)
|
||||||
{
|
{
|
||||||
// Attack with the new limb
|
// Attack with the new limb
|
||||||
@@ -1258,7 +1270,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
Vector2 attackLimbPos = Character.AnimController.SimplePhysicsEnabled ? Character.WorldPosition : AttackingLimb.WorldPosition;
|
Vector2 attackLimbPos = Character.AnimController.SimplePhysicsEnabled ? Character.WorldPosition : AttackingLimb.WorldPosition;
|
||||||
Vector2 toTarget = attackWorldPos - attackLimbPos;
|
Vector2 toTarget = attackWorldPos - attackLimbPos;
|
||||||
// Add a margin when the target is moving away, because otherwise it might be difficult to reach it (the attack takes some time to perform)
|
// Add a margin when the target is moving away, because otherwise it might be difficult to reach it if the attack takes some time to execute
|
||||||
if (wallTarget != null)
|
if (wallTarget != null)
|
||||||
{
|
{
|
||||||
if (wallTarget.Structure.Submarine != null)
|
if (wallTarget.Structure.Submarine != null)
|
||||||
@@ -1283,9 +1295,14 @@ namespace Barotrauma
|
|||||||
|
|
||||||
Vector2 CalculateMargin(Vector2 targetVelocity)
|
Vector2 CalculateMargin(Vector2 targetVelocity)
|
||||||
{
|
{
|
||||||
if (targetVelocity == Vector2.Zero) { return targetVelocity; }
|
if (targetVelocity == Vector2.Zero) { return Vector2.Zero; }
|
||||||
|
float diff = AttackingLimb.attack.Range - AttackingLimb.attack.DamageRange;
|
||||||
|
if (diff <= 0 || toTarget.LengthSquared() <= MathUtils.Pow2(AttackingLimb.attack.DamageRange)) { return Vector2.Zero; }
|
||||||
float dot = Vector2.Dot(Vector2.Normalize(targetVelocity), Vector2.Normalize(Character.AnimController.Collider.LinearVelocity));
|
float dot = Vector2.Dot(Vector2.Normalize(targetVelocity), Vector2.Normalize(Character.AnimController.Collider.LinearVelocity));
|
||||||
return ConvertUnits.ToDisplayUnits(targetVelocity) * AttackingLimb.attack.Duration * dot;
|
if (dot <= 0 || !MathUtils.IsValid(dot)) { return Vector2.Zero; }
|
||||||
|
float distanceOffset = diff * AttackingLimb.attack.Duration;
|
||||||
|
// Intentionally omit the unit conversion because we use distanceOffset as a multiplier.
|
||||||
|
return targetVelocity * distanceOffset * dot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we can reach the target
|
// Check that we can reach the target
|
||||||
@@ -1649,7 +1666,7 @@ namespace Barotrauma
|
|||||||
float GetTargetMaxSpeed() => Character.ApplyTemporarySpeedLimits(Character.AnimController.CurrentSwimParams.MovementSpeed * 0.3f);
|
float GetTargetMaxSpeed() => Character.ApplyTemporarySpeedLimits(Character.AnimController.CurrentSwimParams.MovementSpeed * 0.3f);
|
||||||
}
|
}
|
||||||
SteeringManager.SteeringSeek(steerPos, 10);
|
SteeringManager.SteeringSeek(steerPos, 10);
|
||||||
if (SelectedAiTarget?.Entity is Character || distance == 0 || distance > ConvertUnits.ToDisplayUnits(avoidLookAheadDistance * 2))
|
if (SelectedAiTarget?.Entity is Character c && c.Submarine == null || distance == 0 || distance > ConvertUnits.ToDisplayUnits(avoidLookAheadDistance * 2))
|
||||||
{
|
{
|
||||||
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 30);
|
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 30);
|
||||||
}
|
}
|
||||||
@@ -1813,9 +1830,8 @@ namespace Barotrauma
|
|||||||
ChangeTargetState(attacker, canAttack ? AIState.Attack : AIState.Escape, 100);
|
ChangeTargetState(attacker, canAttack ? AIState.Attack : AIState.Escape, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (!AIParams.HasTag("equal"))
|
||||||
{
|
{
|
||||||
// Equal strength
|
|
||||||
ChangeTargetState(attacker, canAttack ? AIState.Attack : AIState.Escape, 100);
|
ChangeTargetState(attacker, canAttack ? AIState.Attack : AIState.Escape, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2152,6 +2168,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
targetingTag = "weaker";
|
targetingTag = "weaker";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetingTag = "equal";
|
||||||
|
}
|
||||||
if (targetingTag == "stronger" && (State == AIState.Avoid || State == AIState.Escape || State == AIState.Flee))
|
if (targetingTag == "stronger" && (State == AIState.Avoid || State == AIState.Escape || State == AIState.Flee))
|
||||||
{
|
{
|
||||||
if (SelectedAiTarget == aiTarget)
|
if (SelectedAiTarget == aiTarget)
|
||||||
@@ -2619,91 +2639,163 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
private WallTarget wallTarget;
|
private WallTarget wallTarget;
|
||||||
|
private readonly List<(Body, int, Vector2)> wallHits = new List<(Body, int, Vector2)>(3);
|
||||||
private void UpdateWallTarget(int requiredHoleCount)
|
private void UpdateWallTarget(int requiredHoleCount)
|
||||||
{
|
{
|
||||||
wallTarget = null;
|
wallTarget = null;
|
||||||
if (State == AIState.Flee || State == AIState.Escape) { return; }
|
|
||||||
if (AIParams.CanOpenDoors && 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;
|
wallHits.Clear();
|
||||||
Vector2 rayEnd = SelectedAiTarget.SimPosition;
|
Structure wall = null;
|
||||||
if (SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null)
|
if (AIParams.WallTargetingMethod.HasFlag(WallTargetingMethod.Target))
|
||||||
{
|
{
|
||||||
rayStart -= SelectedAiTarget.Entity.Submarine.SimPosition;
|
Vector2 rayStart = SimPosition;
|
||||||
}
|
Vector2 rayEnd = SelectedAiTarget.SimPosition;
|
||||||
else if (SelectedAiTarget.Entity.Submarine == null && Character.Submarine != null)
|
if (SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null)
|
||||||
{
|
|
||||||
rayEnd -= Character.Submarine.SimPosition;
|
|
||||||
}
|
|
||||||
Body closestBody = Submarine.CheckVisibility(rayStart, rayEnd, ignoreSubs: true, ignoreSensors: CanEnterSubmarine, ignoreDisabledWalls: CanEnterSubmarine);
|
|
||||||
if (Submarine.LastPickedFraction != 1.0f && closestBody != null)
|
|
||||||
{
|
|
||||||
if (closestBody.UserData is Structure wall && wall.Submarine != null && (Character.IsBot || wall.Submarine.Info.IsPlayer || wall.Submarine.Info.IsOutpost && TargetOutposts))
|
|
||||||
{
|
{
|
||||||
int sectionIndex = wall.FindSectionIndex(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition));
|
rayStart -= SelectedAiTarget.Entity.Submarine.SimPosition;
|
||||||
float sectionDamage = wall.SectionDamage(sectionIndex);
|
}
|
||||||
for (int i = sectionIndex - 2; i <= sectionIndex + 2; i++)
|
else if (SelectedAiTarget.Entity.Submarine == null && Character.Submarine != null)
|
||||||
|
{
|
||||||
|
rayEnd -= Character.Submarine.SimPosition;
|
||||||
|
}
|
||||||
|
DoRayCast(rayStart, rayEnd);
|
||||||
|
}
|
||||||
|
if (AIParams.WallTargetingMethod.HasFlag(WallTargetingMethod.Heading))
|
||||||
|
{
|
||||||
|
Vector2 rayStart = SimPosition;
|
||||||
|
Vector2 rayEnd = rayStart + VectorExtensions.Forward(Character.AnimController.Collider.Rotation + MathHelper.PiOver2, avoidLookAheadDistance * 5);
|
||||||
|
if (SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null)
|
||||||
|
{
|
||||||
|
rayStart -= SelectedAiTarget.Entity.Submarine.SimPosition;
|
||||||
|
rayEnd -= SelectedAiTarget.Entity.Submarine.SimPosition;
|
||||||
|
}
|
||||||
|
else if (SelectedAiTarget.Entity.Submarine == null && Character.Submarine != null)
|
||||||
|
{
|
||||||
|
rayStart -= Character.Submarine.SimPosition;
|
||||||
|
rayEnd -= Character.Submarine.SimPosition;
|
||||||
|
}
|
||||||
|
DoRayCast(rayStart, rayEnd);
|
||||||
|
}
|
||||||
|
if (AIParams.WallTargetingMethod.HasFlag(WallTargetingMethod.Steering))
|
||||||
|
{
|
||||||
|
Vector2 rayStart = SimPosition;
|
||||||
|
Vector2 rayEnd = rayStart + Steering * 5;
|
||||||
|
if (SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null)
|
||||||
|
{
|
||||||
|
rayStart -= SelectedAiTarget.Entity.Submarine.SimPosition;
|
||||||
|
rayEnd -= SelectedAiTarget.Entity.Submarine.SimPosition;
|
||||||
|
}
|
||||||
|
else if (SelectedAiTarget.Entity.Submarine == null && Character.Submarine != null)
|
||||||
|
{
|
||||||
|
rayStart -= Character.Submarine.SimPosition;
|
||||||
|
rayEnd -= Character.Submarine.SimPosition;
|
||||||
|
}
|
||||||
|
DoRayCast(rayStart, rayEnd);
|
||||||
|
}
|
||||||
|
if (wallHits.Any())
|
||||||
|
{
|
||||||
|
Body closestBody = null;
|
||||||
|
float closestDistance = 0;
|
||||||
|
int sectionIndex = -1;
|
||||||
|
Vector2 sectionPos = Vector2.Zero;
|
||||||
|
foreach ((Body body, int index, Vector2 sectionPosition) in wallHits)
|
||||||
|
{
|
||||||
|
float distance = Vector2.DistanceSquared(SimPosition, sectionPosition);
|
||||||
|
if (closestBody == null || closestDistance == 0 || distance < closestDistance)
|
||||||
{
|
{
|
||||||
if (wall.SectionBodyDisabled(i))
|
closestBody = body;
|
||||||
{
|
closestDistance = distance;
|
||||||
if (Character.AnimController.CanEnterSubmarine && CanPassThroughHole(wall, i, requiredHoleCount))
|
wall = closestBody.UserData as Structure;
|
||||||
{
|
sectionPos = sectionPosition;
|
||||||
sectionIndex = i;
|
sectionIndex = index;
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Ignore and keep breaking other sections
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wall.SectionDamage(i) > sectionDamage)
|
|
||||||
{
|
|
||||||
sectionIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vector2 sectionPos = wall.SectionPosition(sectionIndex);
|
|
||||||
Vector2 attachTargetNormal;
|
|
||||||
if (wall.IsHorizontal)
|
|
||||||
{
|
|
||||||
attachTargetNormal = new Vector2(0.0f, Math.Sign(WorldPosition.Y - wall.WorldPosition.Y));
|
|
||||||
sectionPos.Y += (wall.BodyHeight <= 0.0f ? wall.Rect.Height : wall.BodyHeight) / 2 * attachTargetNormal.Y;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
attachTargetNormal = new Vector2(Math.Sign(WorldPosition.X - wall.WorldPosition.X), 0.0f);
|
|
||||||
sectionPos.X += (wall.BodyWidth <= 0.0f ? wall.Rect.Width : wall.BodyWidth) / 2 * attachTargetNormal.X;
|
|
||||||
}
|
|
||||||
LatchOntoAI?.SetAttachTarget(wall, ConvertUnits.ToSimUnits(sectionPos), attachTargetNormal);
|
|
||||||
if (Character.AnimController.CanEnterSubmarine || !wall.SectionBodyDisabled(sectionIndex) && !IsWallDisabled(wall))
|
|
||||||
{
|
|
||||||
if (AIParams.TargetOuterWalls || wall.prefab.Tags.Contains("inner") || wall.Submarine != null && wall.Submarine == Character.Submarine)
|
|
||||||
{
|
|
||||||
if (wall.NoAITarget && Character.AnimController.CanEnterSubmarine)
|
|
||||||
{
|
|
||||||
// Blocked by a wall that shouldn't be targeted. The main intention here is to prevents monsters from entering the the tail and the nose pieces.
|
|
||||||
IgnoreTarget(SelectedAiTarget);
|
|
||||||
ResetAITarget();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wallTarget = new WallTarget(sectionPos, wall, sectionIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Character.AnimController.CanEnterSubmarine && wallTarget == null && selectedTargetingParams?.AttackPattern == AttackPattern.Straight)
|
if (closestBody == null || sectionIndex == -1) { return; }
|
||||||
|
Vector2 attachTargetNormal;
|
||||||
|
if (wall.IsHorizontal)
|
||||||
{
|
{
|
||||||
if (closestBody.UserData is Structure w && w.Submarine != null && w.Submarine == SelectedAiTarget.Entity?.Submarine ||
|
attachTargetNormal = new Vector2(0.0f, Math.Sign(WorldPosition.Y - wall.WorldPosition.Y));
|
||||||
closestBody.UserData is Item i && i.Submarine != null && i.Submarine == SelectedAiTarget.Entity?.Submarine)
|
sectionPos.Y += (wall.BodyHeight <= 0.0f ? wall.Rect.Height : wall.BodyHeight) / 2 * attachTargetNormal.Y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
attachTargetNormal = new Vector2(Math.Sign(WorldPosition.X - wall.WorldPosition.X), 0.0f);
|
||||||
|
sectionPos.X += (wall.BodyWidth <= 0.0f ? wall.Rect.Width : wall.BodyWidth) / 2 * attachTargetNormal.X;
|
||||||
|
}
|
||||||
|
LatchOntoAI?.SetAttachTarget(wall, ConvertUnits.ToSimUnits(sectionPos), attachTargetNormal);
|
||||||
|
if (Character.AnimController.CanEnterSubmarine || !wall.SectionBodyDisabled(sectionIndex) && !IsWallDisabled(wall))
|
||||||
|
{
|
||||||
|
if (wall.NoAITarget && Character.AnimController.CanEnterSubmarine)
|
||||||
{
|
{
|
||||||
// Cannot reach the target, because it's blocked by a disabled wall or a door
|
// Blocked by a wall that shouldn't be targeted. The main intention here is to prevent monsters from entering the the tail and the nose pieces.
|
||||||
IgnoreTarget(SelectedAiTarget);
|
IgnoreTarget(SelectedAiTarget);
|
||||||
ResetAITarget();
|
ResetAITarget();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wallTarget = new WallTarget(sectionPos, wall, sectionIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Blocked by a disabled wall.
|
||||||
|
IgnoreTarget(SelectedAiTarget);
|
||||||
|
ResetAITarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoRayCast(Vector2 rayStart, Vector2 rayEnd)
|
||||||
|
{
|
||||||
|
Body hitTarget = Submarine.CheckVisibility(rayStart, rayEnd, ignoreSubs: true, ignoreSensors: CanEnterSubmarine, ignoreDisabledWalls: CanEnterSubmarine);
|
||||||
|
if (hitTarget != null && IsValid(hitTarget, out wall))
|
||||||
|
{
|
||||||
|
int sectionIndex = wall.FindSectionIndex(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition));
|
||||||
|
if (sectionIndex >= 0)
|
||||||
|
{
|
||||||
|
wallHits.Add((hitTarget, sectionIndex, GetSectionPosition(wall, sectionIndex)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 GetSectionPosition(Structure wall, int sectionIndex)
|
||||||
|
{
|
||||||
|
float sectionDamage = wall.SectionDamage(sectionIndex);
|
||||||
|
for (int i = sectionIndex - 2; i <= sectionIndex + 2; i++)
|
||||||
|
{
|
||||||
|
if (wall.SectionBodyDisabled(i))
|
||||||
|
{
|
||||||
|
if (Character.AnimController.CanEnterSubmarine && CanPassThroughHole(wall, i, requiredHoleCount))
|
||||||
|
{
|
||||||
|
sectionIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ignore and keep breaking other sections
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wall.SectionDamage(i) > sectionDamage)
|
||||||
|
{
|
||||||
|
sectionIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wall.SectionPosition(sectionIndex, world: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValid(Body hit, out Structure wall)
|
||||||
|
{
|
||||||
|
wall = null;
|
||||||
|
if (Submarine.LastPickedFraction == 1.0f) { return false; }
|
||||||
|
if (!(hit.UserData is Structure w)) { return false; }
|
||||||
|
if (w.Submarine == null) { return false; }
|
||||||
|
if (w.Submarine != SelectedAiTarget.Entity.Submarine) { return false; }
|
||||||
|
if (Character.Submarine == null && w.prefab.Tags.Contains("inner")) { return false; }
|
||||||
|
if (!AIParams.TargetOuterWalls && !w.prefab.Tags.Contains("inner")) { return false; }
|
||||||
|
wall = w;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2712,7 +2804,7 @@ namespace Barotrauma
|
|||||||
if (wallTarget != null && wallTarget.SectionIndex > -1 && CanPassThroughHole(wallTarget.Structure, wallTarget.SectionIndex, requiredHoleCount))
|
if (wallTarget != null && wallTarget.SectionIndex > -1 && CanPassThroughHole(wallTarget.Structure, wallTarget.SectionIndex, requiredHoleCount))
|
||||||
{
|
{
|
||||||
WallSection section = wallTarget.Structure.GetSection(wallTarget.SectionIndex);
|
WallSection section = wallTarget.Structure.GetSection(wallTarget.SectionIndex);
|
||||||
Vector2 targetPos = wallTarget.Structure.SectionPosition(wallTarget.SectionIndex, true);
|
Vector2 targetPos = wallTarget.Structure.SectionPosition(wallTarget.SectionIndex, world: true);
|
||||||
return section?.gap != null && SteerThroughGap(wallTarget.Structure, section, targetPos, deltaTime);
|
return section?.gap != null && SteerThroughGap(wallTarget.Structure, section, targetPos, deltaTime);
|
||||||
}
|
}
|
||||||
else if (SelectedAiTarget != null)
|
else if (SelectedAiTarget != null)
|
||||||
|
|||||||
@@ -136,8 +136,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsMentallyUnstable =>
|
public override bool IsMentallyUnstable =>
|
||||||
MentalStateManager?.CurrentMentalType != MentalStateManager.MentalType.Normal &&
|
MentalStateManager == null ? false :
|
||||||
MentalStateManager?.CurrentMentalType != MentalStateManager.MentalType.Confused;
|
MentalStateManager.CurrentMentalType != MentalStateManager.MentalType.Normal &&
|
||||||
|
MentalStateManager.CurrentMentalType != MentalStateManager.MentalType.Confused;
|
||||||
|
|
||||||
public ShipCommandManager ShipCommandManager { get; private set; }
|
public ShipCommandManager ShipCommandManager { get; private set; }
|
||||||
|
|
||||||
@@ -740,9 +741,10 @@ namespace Barotrauma
|
|||||||
suitableContainer = null;
|
suitableContainer = null;
|
||||||
if (character.FindItem(ref itemIndex, out Item targetContainer, ignoredItems: ignoredItems, positionalReference: containableItem, customPriorityFunction: i =>
|
if (character.FindItem(ref itemIndex, out Item targetContainer, ignoredItems: ignoredItems, positionalReference: containableItem, customPriorityFunction: i =>
|
||||||
{
|
{
|
||||||
if (i.IsThisOrAnyContainerIgnoredByAI()) { return 0; }
|
if (i.IsThisOrAnyContainerIgnoredByAI(character)) { return 0; }
|
||||||
var container = i.GetComponent<ItemContainer>();
|
var container = i.GetComponent<ItemContainer>();
|
||||||
if (container == null) { return 0; }
|
if (container == null) { return 0; }
|
||||||
|
if (!container.HasAccess(character)) { return 0; }
|
||||||
if (!container.Inventory.CanBePut(containableItem)) { return 0; }
|
if (!container.Inventory.CanBePut(containableItem)) { return 0; }
|
||||||
if (container.ShouldBeContained(containableItem, out bool isRestrictionsDefined))
|
if (container.ShouldBeContained(containableItem, out bool isRestrictionsDefined))
|
||||||
{
|
{
|
||||||
@@ -1032,11 +1034,11 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float cumulativeDamage = GetDamageDoneByAttacker(attacker);
|
float cumulativeDamage = GetDamageDoneByAttacker(attacker);
|
||||||
if (!Character.IsSecurity && attacker.IsBot && !IsMentallyUnstable && !attacker.AIController.IsMentallyUnstable && Character.CombatAction == null)
|
bool isAccidental = attacker.IsBot && !IsMentallyUnstable && !attacker.AIController.IsMentallyUnstable && Character.CombatAction == null;
|
||||||
|
if (isAccidental)
|
||||||
{
|
{
|
||||||
if (cumulativeDamage > 1)
|
if (!Character.IsSecurity && cumulativeDamage > 1)
|
||||||
{
|
{
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1109,7 +1111,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (Character otherCharacter in Character.CharacterList)
|
foreach (Character otherCharacter in Character.CharacterList)
|
||||||
{
|
{
|
||||||
if (otherCharacter == Character || otherCharacter.IsDead || otherCharacter.IsUnconscious || otherCharacter.Removed) { continue; }
|
if (otherCharacter == Character || otherCharacter.IsUnconscious || otherCharacter.Removed) { continue; }
|
||||||
if (otherCharacter.Submarine != Character.Submarine) { continue; }
|
if (otherCharacter.Submarine != Character.Submarine) { continue; }
|
||||||
if (otherCharacter.Submarine != attacker.Submarine) { continue; }
|
if (otherCharacter.Submarine != attacker.Submarine) { continue; }
|
||||||
if (otherCharacter.Info?.Job == null || otherCharacter.IsInstigator) { continue; }
|
if (otherCharacter.Info?.Job == null || otherCharacter.IsInstigator) { continue; }
|
||||||
@@ -1921,18 +1923,45 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private static bool FilterCrewMember(Character self, Character other) => other != null && !other.IsDead && !other.Removed && other.AIController is HumanAIController humanAi && humanAi.IsFriendly(self);
|
private static bool FilterCrewMember(Character self, Character other) => other != null && !other.IsDead && !other.Removed && other.AIController is HumanAIController humanAi && humanAi.IsFriendly(self);
|
||||||
|
|
||||||
public static bool IsItemOperatedByAnother(Character character, ItemComponent target, out Character operatingCharacter)
|
public static bool IsItemTargetedBySomeone(ItemComponent target, CharacterTeamType team, out Character operatingCharacter)
|
||||||
{
|
{
|
||||||
operatingCharacter = null;
|
operatingCharacter = null;
|
||||||
if (character == null) { return false; }
|
foreach (Character c in Character.CharacterList)
|
||||||
if (target?.Item == null) { return false; }
|
|
||||||
bool isOrder = IsOrderedToOperateThis(character.AIController);
|
|
||||||
foreach (var c in Character.CharacterList)
|
|
||||||
{
|
{
|
||||||
if (c == character) { continue; }
|
if (c.Removed) { continue; }
|
||||||
if (c.IsDead || c.IsIncapacitated) { continue; }
|
if (c.TeamID != team) { continue; }
|
||||||
if (!IsFriendly(character, c, onlySameTeam: true)) { continue; }
|
if (c.IsIncapacitated) { continue; }
|
||||||
|
bool isOperated = c.SelectedConstruction == target.Item;
|
||||||
|
if (!isOperated)
|
||||||
|
{
|
||||||
|
if (c.AIController is HumanAIController humanAI)
|
||||||
|
{
|
||||||
|
isOperated = humanAI.ObjectiveManager.Objectives.Any(o => o is AIObjectiveOperateItem operateObjective && operateObjective.Component.Item == target.Item);
|
||||||
|
}
|
||||||
|
}
|
||||||
operatingCharacter = c;
|
operatingCharacter = c;
|
||||||
|
if (isOperated)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's some duplicate logic in the two methods below, but making them use the same code would require some changes in the target classes so that we could use exactly the same checks.
|
||||||
|
// And even then there would be some differences that could end up being confusing (like the exception for steering).
|
||||||
|
public bool IsItemOperatedByAnother(ItemComponent target, out Character other)
|
||||||
|
{
|
||||||
|
other = null;
|
||||||
|
if (target?.Item == null) { return false; }
|
||||||
|
bool isOrder = IsOrderedToOperateThis(Character.AIController);
|
||||||
|
foreach (Character c in Character.CharacterList)
|
||||||
|
{
|
||||||
|
if (c == Character) { continue; }
|
||||||
|
if (c.Removed) { continue; }
|
||||||
|
if (c.TeamID != Character.TeamID) { continue; }
|
||||||
|
if (c.IsIncapacitated) { continue; }
|
||||||
|
other = c;
|
||||||
if (c.IsPlayer)
|
if (c.IsPlayer)
|
||||||
{
|
{
|
||||||
if (c.SelectedConstruction == target.Item)
|
if (c.SelectedConstruction == target.Item)
|
||||||
@@ -1963,7 +1992,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!isTargetOrdered && operatingAI.ObjectiveManager.CurrentOrder == operatingAI.ObjectiveManager.CurrentObjective)
|
if (!isTargetOrdered && operatingAI.ObjectiveManager.CurrentOrder != operatingAI.ObjectiveManager.CurrentObjective)
|
||||||
{
|
{
|
||||||
// The other bot is ordered to do something else
|
// The other bot is ordered to do something else
|
||||||
continue;
|
continue;
|
||||||
@@ -1971,12 +2000,12 @@ namespace Barotrauma
|
|||||||
if (target is Steering)
|
if (target is Steering)
|
||||||
{
|
{
|
||||||
// Steering is hard-coded -> cannot use the required skills collection defined in the xml
|
// Steering is hard-coded -> cannot use the required skills collection defined in the xml
|
||||||
if (character.GetSkillLevel("helm") <= c.GetSkillLevel("helm"))
|
if (Character.GetSkillLevel("helm") <= c.GetSkillLevel("helm"))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (target.DegreeOfSuccess(character) <= target.DegreeOfSuccess(c))
|
else if (target.DegreeOfSuccess(Character) <= target.DegreeOfSuccess(c))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1985,7 +2014,65 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
bool IsOrderedToOperateThis(AIController ai) => ai is HumanAIController humanAI && humanAI.ObjectiveManager.CurrentOrder is AIObjectiveOperateItem operateObjective && operateObjective.Component.Item == target.Item;
|
bool IsOrderedToOperateThis(AIController ai) => ai is HumanAIController humanAI && humanAI.ObjectiveManager.CurrentOrder is AIObjectiveOperateItem operateOrder && operateOrder.Component.Item == target.Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsItemRepairedByAnother(Item target, out Character other)
|
||||||
|
{
|
||||||
|
other = null;
|
||||||
|
if (Character == null) { return false; }
|
||||||
|
if (target == null) { return false; }
|
||||||
|
bool isOrder = IsOrderedToRepairThis(Character.AIController as HumanAIController);
|
||||||
|
foreach (var c in Character.CharacterList)
|
||||||
|
{
|
||||||
|
if (c == Character) { continue; }
|
||||||
|
if (c.TeamID != Character.TeamID) { continue; }
|
||||||
|
if (c.IsIncapacitated) { continue; }
|
||||||
|
other = c;
|
||||||
|
if (c.IsPlayer)
|
||||||
|
{
|
||||||
|
if (target.Repairables.Any(r => r.CurrentFixer == c))
|
||||||
|
{
|
||||||
|
// If the other character is player, don't try to repair
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c.AIController is HumanAIController operatingAI)
|
||||||
|
{
|
||||||
|
var repairItemsObjective = operatingAI.ObjectiveManager.GetObjective<AIObjectiveRepairItems>();
|
||||||
|
if (repairItemsObjective == null) { continue; }
|
||||||
|
if (repairItemsObjective.SubObjectives.None(o => o is AIObjectiveRepairItem repairObjective && repairObjective.Item == target))
|
||||||
|
{
|
||||||
|
// Not targeting the same item.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool isTargetOrdered = IsOrderedToRepairThis(operatingAI);
|
||||||
|
if (!isOrder && isTargetOrdered)
|
||||||
|
{
|
||||||
|
// If the other bot is ordered to repair the item, let him do it, unless we are ordered too
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isOrder && !isTargetOrdered)
|
||||||
|
{
|
||||||
|
// We are ordered and the target is not -> allow to repair
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!isTargetOrdered && operatingAI.ObjectiveManager.CurrentOrder != operatingAI.ObjectiveManager.CurrentObjective)
|
||||||
|
{
|
||||||
|
// The other bot is ordered to do something else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return target.Repairables.Max(r => r.DegreeOfSuccess(Character)) <= target.Repairables.Max(r => r.DegreeOfSuccess(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
bool IsOrderedToRepairThis(HumanAIController ai) => ai.ObjectiveManager.CurrentOrder is AIObjectiveRepairItems repairOrder && repairOrder.PrioritizedItem == target;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Wrappers
|
#region Wrappers
|
||||||
@@ -1994,7 +2081,6 @@ namespace Barotrauma
|
|||||||
public bool IsTrueForAnyCrewMember(Func<HumanAIController, bool> predicate) => IsTrueForAnyCrewMember(Character, predicate);
|
public bool IsTrueForAnyCrewMember(Func<HumanAIController, bool> predicate) => IsTrueForAnyCrewMember(Character, predicate);
|
||||||
public bool IsTrueForAllCrewMembers(Func<HumanAIController, bool> predicate) => IsTrueForAllCrewMembers(Character, predicate);
|
public bool IsTrueForAllCrewMembers(Func<HumanAIController, bool> predicate) => IsTrueForAllCrewMembers(Character, predicate);
|
||||||
public int CountCrew(Func<HumanAIController, bool> predicate = null, bool onlyActive = true, bool onlyBots = false) => CountCrew(Character, predicate, onlyActive, onlyBots);
|
public int CountCrew(Func<HumanAIController, bool> predicate = null, bool onlyActive = true, bool onlyBots = false) => CountCrew(Character, predicate, onlyActive, onlyBots);
|
||||||
public bool IsItemOperatedByAnother(ItemComponent target, out Character operatingCharacter) => IsItemOperatedByAnother(Character, target, out operatingCharacter);
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (battery == null) { return false; }
|
if (battery == null) { return false; }
|
||||||
var item = battery.Item;
|
var item = battery.Item;
|
||||||
if (item.IgnoreByAI) { return false; }
|
if (item.IgnoreByAI(character)) { return false; }
|
||||||
if (!item.IsInteractable(character)) { return false; }
|
if (!item.IsInteractable(character)) { return false; }
|
||||||
if (item.Submarine == null) { return false; }
|
if (item.Submarine == null) { return false; }
|
||||||
if (item.CurrentHull == null) { return false; }
|
if (item.CurrentHull == null) { return false; }
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected override void Act(float deltaTime)
|
protected override void Act(float deltaTime)
|
||||||
{
|
{
|
||||||
if (item.IgnoreByAI)
|
if (item.IgnoreByAI(character))
|
||||||
{
|
{
|
||||||
Abandon = true;
|
Abandon = true;
|
||||||
return;
|
return;
|
||||||
|
|||||||
+3
-2
@@ -82,16 +82,17 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static bool IsValidContainer(Item container, Character character, bool allowUnloading = true) =>
|
public static bool IsValidContainer(Item container, Character character, bool allowUnloading = true) =>
|
||||||
allowUnloading &&
|
allowUnloading &&
|
||||||
!container.IgnoreByAI &&
|
!container.IgnoreByAI(character) &&
|
||||||
container.IsInteractable(character) &&
|
container.IsInteractable(character) &&
|
||||||
container.HasTag("allowcleanup") &&
|
container.HasTag("allowcleanup") &&
|
||||||
container.ParentInventory == null && container.OwnInventory != null && container.OwnInventory.AllItems.Any() &&
|
container.ParentInventory == null && container.OwnInventory != null && container.OwnInventory.AllItems.Any() &&
|
||||||
|
container.GetComponent<ItemContainer>() is ItemContainer itemContainer && itemContainer.HasAccess(character) &&
|
||||||
IsItemInsideValidSubmarine(container, character);
|
IsItemInsideValidSubmarine(container, character);
|
||||||
|
|
||||||
public static bool IsValidTarget(Item item, Character character, bool checkInventory, bool allowUnloading = true)
|
public static bool IsValidTarget(Item item, Character character, bool checkInventory, bool allowUnloading = true)
|
||||||
{
|
{
|
||||||
if (item == null) { return false; }
|
if (item == null) { return false; }
|
||||||
if (item.IgnoreByAI) { return false; }
|
if (item.IgnoreByAI(character)) { return false; }
|
||||||
if (!item.IsInteractable(character)) { return false; }
|
if (!item.IsInteractable(character)) { return false; }
|
||||||
if (item.SpawnedInOutpost) { return false; }
|
if (item.SpawnedInOutpost) { return false; }
|
||||||
if (item.ParentInventory != null)
|
if (item.ParentInventory != null)
|
||||||
|
|||||||
+4
-4
@@ -64,7 +64,7 @@ namespace Barotrauma
|
|||||||
protected override bool CheckObjectiveSpecific()
|
protected override bool CheckObjectiveSpecific()
|
||||||
{
|
{
|
||||||
if (IsCompleted) { return true; }
|
if (IsCompleted) { return true; }
|
||||||
if (container == null || (container.Item != null && container.Item.IsThisOrAnyContainerIgnoredByAI()))
|
if (container == null || (container.Item != null && container.Item.IsThisOrAnyContainerIgnoredByAI(character)))
|
||||||
{
|
{
|
||||||
Abandon = true;
|
Abandon = true;
|
||||||
return false;
|
return false;
|
||||||
@@ -87,11 +87,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckItem(Item i) => itemIdentifiers.Any(id => i.Prefab.Identifier == id || i.HasTag(id)) && i.ConditionPercentage >= ConditionLevel && !i.IsThisOrAnyContainerIgnoredByAI();
|
private bool CheckItem(Item i) => itemIdentifiers.Any(id => i.Prefab.Identifier == id || i.HasTag(id)) && i.ConditionPercentage >= ConditionLevel && !i.IsThisOrAnyContainerIgnoredByAI(character);
|
||||||
|
|
||||||
protected override void Act(float deltaTime)
|
protected override void Act(float deltaTime)
|
||||||
{
|
{
|
||||||
if (container?.Item == null || container.Item.Removed || container.Item.IsThisOrAnyContainerIgnoredByAI())
|
if (container?.Item == null || container.Item.Removed || container.Item.IsThisOrAnyContainerIgnoredByAI(character))
|
||||||
{
|
{
|
||||||
Abandon = true;
|
Abandon = true;
|
||||||
return;
|
return;
|
||||||
@@ -147,7 +147,7 @@ namespace Barotrauma
|
|||||||
DialogueIdentifier = "dialogcannotreachtarget",
|
DialogueIdentifier = "dialogcannotreachtarget",
|
||||||
TargetName = container.Item.Name,
|
TargetName = container.Item.Name,
|
||||||
AbortCondition = obj =>
|
AbortCondition = obj =>
|
||||||
container?.Item == null || container.Item.Removed || container.Item.IsThisOrAnyContainerIgnoredByAI() ||
|
container?.Item == null || container.Item.Removed || container.Item.IsThisOrAnyContainerIgnoredByAI(character) ||
|
||||||
ItemToContain == null || ItemToContain.Removed ||
|
ItemToContain == null || ItemToContain.Removed ||
|
||||||
!ItemToContain.IsOwnedBy(character) || container.Item.GetRootInventoryOwner() is Character c && c != character,
|
!ItemToContain.IsOwnedBy(character) || container.Item.GetRootInventoryOwner() is Character c && c != character,
|
||||||
SpeakIfFails = !objectiveManager.IsCurrentOrder<AIObjectiveCleanupItems>()
|
SpeakIfFails = !objectiveManager.IsCurrentOrder<AIObjectiveCleanupItems>()
|
||||||
|
|||||||
+5
-2
@@ -63,13 +63,16 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected override void Act(float deltaTime)
|
protected override void Act(float deltaTime)
|
||||||
{
|
{
|
||||||
Item itemToDecontain = targetItem ?? sourceContainer.Inventory.FindItem(i => itemIdentifiers.Any(id => i.Prefab.Identifier == id || i.HasTag(id) && !i.IgnoreByAI), recursive: false);
|
Item itemToDecontain =
|
||||||
|
targetItem ??
|
||||||
|
sourceContainer.Inventory.FindItem(i => itemIdentifiers.Any(id => i.Prefab.Identifier == id || i.HasTag(id) && !i.IgnoreByAI(character)), recursive: false);
|
||||||
|
|
||||||
if (itemToDecontain == null)
|
if (itemToDecontain == null)
|
||||||
{
|
{
|
||||||
Abandon = true;
|
Abandon = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (itemToDecontain.IgnoreByAI)
|
if (itemToDecontain.IgnoreByAI(character))
|
||||||
{
|
{
|
||||||
Abandon = true;
|
Abandon = true;
|
||||||
return;
|
return;
|
||||||
|
|||||||
+5
-2
@@ -38,10 +38,13 @@ namespace Barotrauma
|
|||||||
Priority = 0;
|
Priority = 0;
|
||||||
Abandon = true;
|
Abandon = true;
|
||||||
}
|
}
|
||||||
else if (HumanAIController.IsTrueForAnyCrewMember(other => other != HumanAIController && other.Character.IsBot && other.ObjectiveManager.GetActiveObjective<AIObjectiveFixLeak>()?.Leak == Leak))
|
else if (HumanAIController.IsTrueForAnyCrewMember(
|
||||||
|
other => other != HumanAIController &&
|
||||||
|
other.Character.IsBot &&
|
||||||
|
other.ObjectiveManager.GetActiveObjective<AIObjectiveFixLeaks>() is AIObjectiveFixLeaks fixLeaks &&
|
||||||
|
fixLeaks.SubObjectives.Any(so => so is AIObjectiveFixLeak fixObjective && fixObjective.Leak == Leak)))
|
||||||
{
|
{
|
||||||
Priority = 0;
|
Priority = 0;
|
||||||
Abandon = true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -74,7 +74,7 @@ namespace Barotrauma
|
|||||||
// Don't fix a leak on a wall section set to be ignored
|
// Don't fix a leak on a wall section set to be ignored
|
||||||
if (gap.ConnectedWall != null)
|
if (gap.ConnectedWall != null)
|
||||||
{
|
{
|
||||||
if (gap.ConnectedWall.Sections.Any(s => s.gap == gap && s.IgnoreByAI)) { return false; }
|
if (gap.ConnectedWall.Sections.Any(s => s.gap == gap && s.IgnoreByAI(character))) { return false; }
|
||||||
if (gap.ConnectedWall.MaxHealth <= 0.0f) { return false; }
|
if (gap.ConnectedWall.MaxHealth <= 0.0f) { return false; }
|
||||||
}
|
}
|
||||||
if (gap.ConnectedWall == null || gap.ConnectedDoor != null || gap.Open <= 0 || gap.linkedTo.All(l => l == null)) { return false; }
|
if (gap.ConnectedWall == null || gap.ConnectedDoor != null || gap.Open <= 0 || gap.linkedTo.All(l => l == null)) { return false; }
|
||||||
|
|||||||
+2
-1
@@ -305,6 +305,7 @@ namespace Barotrauma
|
|||||||
if (rootInventoryOwner is Item ownerItem)
|
if (rootInventoryOwner is Item ownerItem)
|
||||||
{
|
{
|
||||||
if (!ownerItem.IsInteractable(character)) { continue; }
|
if (!ownerItem.IsInteractable(character)) { continue; }
|
||||||
|
if (!(ownerItem.GetComponent<ItemContainer>()?.HasRequiredItems(character, addMessage: false) ?? true)) { continue; }
|
||||||
}
|
}
|
||||||
Vector2 itemPos = (rootInventoryOwner ?? item).WorldPosition;
|
Vector2 itemPos = (rootInventoryOwner ?? item).WorldPosition;
|
||||||
float yDist = Math.Abs(character.WorldPosition.Y - itemPos.Y);
|
float yDist = Math.Abs(character.WorldPosition.Y - itemPos.Y);
|
||||||
@@ -403,7 +404,7 @@ namespace Barotrauma
|
|||||||
private bool CheckItem(Item item)
|
private bool CheckItem(Item item)
|
||||||
{
|
{
|
||||||
if (!item.IsInteractable(character)) { return false; }
|
if (!item.IsInteractable(character)) { return false; }
|
||||||
if (item.IsThisOrAnyContainerIgnoredByAI()) { return false; }
|
if (item.IsThisOrAnyContainerIgnoredByAI(character)) { return false; }
|
||||||
if (ignoredItems.Contains(item)) { return false; };
|
if (ignoredItems.Contains(item)) { return false; };
|
||||||
if (item.Condition < TargetCondition) { return false; }
|
if (item.Condition < TargetCondition) { return false; }
|
||||||
if (ItemFilter != null && !ItemFilter(item)) { return false; }
|
if (ItemFilter != null && !ItemFilter(item)) { return false; }
|
||||||
|
|||||||
+1
-1
@@ -118,7 +118,7 @@ namespace Barotrauma
|
|||||||
targetItem.CurrentHull.FireSources.Any() ||
|
targetItem.CurrentHull.FireSources.Any() ||
|
||||||
HumanAIController.IsItemOperatedByAnother(target, out _) ||
|
HumanAIController.IsItemOperatedByAnother(target, out _) ||
|
||||||
Character.CharacterList.Any(c => c.CurrentHull == targetItem.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c))
|
Character.CharacterList.Any(c => c.CurrentHull == targetItem.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c))
|
||||||
|| component.Item.IgnoreByAI || (useController && controller.Item.IgnoreByAI))
|
|| component.Item.IgnoreByAI(character) || useController && controller.Item.IgnoreByAI(character))
|
||||||
{
|
{
|
||||||
Priority = 0;
|
Priority = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ namespace Barotrauma
|
|||||||
protected override bool Filter(Pump pump)
|
protected override bool Filter(Pump pump)
|
||||||
{
|
{
|
||||||
if (pump == null) { return false; }
|
if (pump == null) { return false; }
|
||||||
if (pump.Item.IgnoreByAI) { return false; }
|
if (pump.Item.IgnoreByAI(character)) { return false; }
|
||||||
if (!pump.Item.IsInteractable(character)) { return false; }
|
if (!pump.Item.IsInteractable(character)) { return false; }
|
||||||
if (pump.Item.HasTag("ballast")) { return false; }
|
if (pump.Item.HasTag("ballast")) { return false; }
|
||||||
if (pump.Item.Submarine == null) { return false; }
|
if (pump.Item.Submarine == null) { return false; }
|
||||||
|
|||||||
+3
-3
@@ -34,7 +34,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected override float GetPriority()
|
protected override float GetPriority()
|
||||||
{
|
{
|
||||||
if (!IsAllowed || Item.IgnoreByAI)
|
if (!IsAllowed || Item.IgnoreByAI(character))
|
||||||
{
|
{
|
||||||
Priority = 0;
|
Priority = 0;
|
||||||
Abandon = true;
|
Abandon = true;
|
||||||
@@ -44,10 +44,10 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
return Priority;
|
return Priority;
|
||||||
}
|
}
|
||||||
// Ignore items that are being repaired by someone else.
|
if (HumanAIController.IsItemRepairedByAnother(Item, out _))
|
||||||
if (Item.Repairables.Any(r => r.CurrentFixer != null && r.CurrentFixer != character))
|
|
||||||
{
|
{
|
||||||
Priority = 0;
|
Priority = 0;
|
||||||
|
IsCompleted = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+5
-5
@@ -16,7 +16,7 @@ namespace Barotrauma
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string RelevantSkill;
|
public string RelevantSkill;
|
||||||
|
|
||||||
private readonly Item prioritizedItem;
|
public Item PrioritizedItem { get; private set; }
|
||||||
|
|
||||||
public override bool AllowMultipleInstances => true;
|
public override bool AllowMultipleInstances => true;
|
||||||
public override bool AllowInAnySub => true;
|
public override bool AllowInAnySub => true;
|
||||||
@@ -28,7 +28,7 @@ namespace Barotrauma
|
|||||||
public AIObjectiveRepairItems(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1, Item prioritizedItem = null)
|
public AIObjectiveRepairItems(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1, Item prioritizedItem = null)
|
||||||
: base(character, objectiveManager, priorityModifier)
|
: base(character, objectiveManager, priorityModifier)
|
||||||
{
|
{
|
||||||
this.prioritizedItem = prioritizedItem;
|
PrioritizedItem = prioritizedItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateObjectives()
|
protected override void CreateObjectives()
|
||||||
@@ -76,7 +76,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (item.Repairables.None(r => r.requiredSkills.Any(s => s.Identifier.Equals(RelevantSkill, StringComparison.OrdinalIgnoreCase)))) { return false; }
|
if (item.Repairables.None(r => r.requiredSkills.Any(s => s.Identifier.Equals(RelevantSkill, StringComparison.OrdinalIgnoreCase)))) { return false; }
|
||||||
}
|
}
|
||||||
return true;
|
return !HumanAIController.IsItemRepairedByAnother(item, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool ViableForRepair(Item item, Character character, HumanAIController humanAIController)
|
public static bool ViableForRepair(Item item, Character character, HumanAIController humanAIController)
|
||||||
@@ -139,7 +139,7 @@ namespace Barotrauma
|
|||||||
protected override IEnumerable<Item> GetList() => Item.ItemList;
|
protected override IEnumerable<Item> GetList() => Item.ItemList;
|
||||||
|
|
||||||
protected override AIObjective ObjectiveConstructor(Item item)
|
protected override AIObjective ObjectiveConstructor(Item item)
|
||||||
=> new AIObjectiveRepairItem(character, item, objectiveManager, priorityModifier: PriorityModifier, isPriority: item == prioritizedItem);
|
=> new AIObjectiveRepairItem(character, item, objectiveManager, priorityModifier: PriorityModifier, isPriority: item == PrioritizedItem);
|
||||||
|
|
||||||
protected override void OnObjectiveCompleted(AIObjective objective, Item target)
|
protected override void OnObjectiveCompleted(AIObjective objective, Item target)
|
||||||
=> HumanAIController.RemoveTargets<AIObjectiveRepairItems, Item>(character, target);
|
=> HumanAIController.RemoveTargets<AIObjectiveRepairItems, Item>(character, target);
|
||||||
@@ -147,7 +147,7 @@ namespace Barotrauma
|
|||||||
public static bool IsValidTarget(Item item, Character character)
|
public static bool IsValidTarget(Item item, Character character)
|
||||||
{
|
{
|
||||||
if (item == null) { return false; }
|
if (item == null) { return false; }
|
||||||
if (item.IgnoreByAI) { return false; }
|
if (item.IgnoreByAI(character)) { return false; }
|
||||||
if (!item.IsInteractable(character)) { return false; }
|
if (!item.IsInteractable(character)) { return false; }
|
||||||
if (item.IsFullCondition) { return false; }
|
if (item.IsFullCondition) { return false; }
|
||||||
if (item.CurrentHull == null) { return false; }
|
if (item.CurrentHull == null) { return false; }
|
||||||
|
|||||||
@@ -495,27 +495,19 @@ namespace Barotrauma
|
|||||||
if (submarine == null) { return matchingItems; }
|
if (submarine == null) { return matchingItems; }
|
||||||
if (ItemComponentType != null || TargetItems.Length > 0)
|
if (ItemComponentType != null || TargetItems.Length > 0)
|
||||||
{
|
{
|
||||||
matchingItems = TargetItems.Length > 0 ?
|
foreach (var item in Item.ItemList)
|
||||||
Item.ItemList.FindAll(it => TargetItems.Contains(it.Prefab.Identifier) || it.HasTag(TargetItems)) :
|
|
||||||
Item.ItemList.FindAll(it => TryGetTargetItemComponent(it, out _));
|
|
||||||
if (mustBelongToPlayerSub)
|
|
||||||
{
|
{
|
||||||
matchingItems.RemoveAll(it => it.Submarine?.Info != null && it.Submarine.Info.Type != SubmarineType.Player);
|
if (TargetItems.Length > 0 && !TargetItems.Contains(item.Prefab.Identifier) && !item.HasTag(TargetItems)) { continue; }
|
||||||
}
|
if (TargetItems.Length == 0 && !TryGetTargetItemComponent(item, out _)) { continue; }
|
||||||
matchingItems.RemoveAll(it => it.Submarine != submarine && !submarine.DockedTo.Contains(it.Submarine));
|
if (mustBelongToPlayerSub && item.Submarine?.Info != null && item.Submarine.Info.Type != SubmarineType.Player) { continue; }
|
||||||
if (requiredTeam.HasValue)
|
if (item.Submarine != submarine && !submarine.DockedTo.Contains(item.Submarine)) { continue; }
|
||||||
{
|
if (requiredTeam.HasValue && (item.Submarine == null || item.Submarine.TeamID != requiredTeam.Value)) { continue; }
|
||||||
matchingItems.RemoveAll(it => it.Submarine == null || it.Submarine.TeamID != requiredTeam.Value);
|
if (item.NonInteractable) { continue; }
|
||||||
}
|
if (ItemComponentType != null && item.Components.None(c => c.GetType() == ItemComponentType)) { continue; }
|
||||||
matchingItems.RemoveAll(it => it.NonInteractable);
|
Controller controller = null;
|
||||||
if (UseController)
|
if (UseController && !item.TryFindController(out controller)) { continue; }
|
||||||
{
|
if (interactableFor != null && (!item.IsInteractable(interactableFor) || (UseController && !controller.Item.IsInteractable(interactableFor)))) { continue; }
|
||||||
matchingItems.RemoveAll(i => i.Components.None(c => c.GetType() == ItemComponentType) && !i.TryFindController(out _));
|
matchingItems.Add(item);
|
||||||
}
|
|
||||||
if (interactableFor != null)
|
|
||||||
{
|
|
||||||
matchingItems.RemoveAll(it => !it.IsInteractable(interactableFor) ||
|
|
||||||
(UseController && it.FindController() is Controller c && !c.Item.IsInteractable(interactableFor)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return matchingItems;
|
return matchingItems;
|
||||||
|
|||||||
-2
@@ -24,8 +24,6 @@ namespace Barotrauma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TargetItem.IgnoreByAI) { return false; }
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-7
@@ -270,14 +270,16 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LimbJoint rightWrist = GetJointBetweenLimbs(LimbType.RightForearm, LimbType.RightHand);
|
LimbJoint rightWrist = GetJointBetweenLimbs(LimbType.RightForearm, LimbType.RightHand);
|
||||||
|
if (rightWrist != null)
|
||||||
|
{
|
||||||
|
forearmLength = Vector2.Distance(
|
||||||
|
rightElbow.LimbA.type == LimbType.RightForearm ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB,
|
||||||
|
rightWrist.LimbA.type == LimbType.RightForearm ? rightWrist.LocalAnchorA : rightWrist.LocalAnchorB);
|
||||||
|
|
||||||
forearmLength = Vector2.Distance(
|
forearmLength += Vector2.Distance(
|
||||||
rightElbow.LimbA.type == LimbType.RightForearm ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB,
|
rightHand.PullJointLocalAnchorA,
|
||||||
rightWrist.LimbA.type == LimbType.RightForearm ? rightWrist.LocalAnchorA : rightWrist.LocalAnchorB);
|
rightElbow.LimbA.type == LimbType.RightHand ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB);
|
||||||
|
}
|
||||||
forearmLength += Vector2.Distance(
|
|
||||||
rightHand.PullJointLocalAnchorA,
|
|
||||||
rightElbow.LimbA.type == LimbType.RightHand ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected Key[] keys;
|
protected Key[] keys;
|
||||||
|
|
||||||
|
public HumanPrefab Prefab;
|
||||||
|
|
||||||
private CharacterTeamType teamID;
|
private CharacterTeamType teamID;
|
||||||
public CharacterTeamType TeamID
|
public CharacterTeamType TeamID
|
||||||
{
|
{
|
||||||
@@ -1365,11 +1367,27 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private List<Item> wearableItems = new List<Item>();
|
||||||
|
|
||||||
public float GetSkillLevel(string skillIdentifier)
|
public float GetSkillLevel(string skillIdentifier)
|
||||||
{
|
{
|
||||||
if (Info?.Job == null) { return 0.0f; }
|
if (Info?.Job == null) { return 0.0f; }
|
||||||
float skillLevel = Info.Job.GetSkillLevel(skillIdentifier);
|
float skillLevel = Info.Job.GetSkillLevel(skillIdentifier);
|
||||||
|
|
||||||
|
if (skillIdentifier != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Inventory.Capacity; i++)
|
||||||
|
{
|
||||||
|
if (Inventory.SlotTypes[i] != InvSlotType.Any && Inventory.GetItemAt(i)?.GetComponent<Wearable>() is Wearable wearable)
|
||||||
|
{
|
||||||
|
if (wearable.SkillModifiers.TryGetValue(skillIdentifier, out float skillValue))
|
||||||
|
{
|
||||||
|
skillLevel += skillValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (Affliction affliction in CharacterHealth.GetAllAfflictions())
|
foreach (Affliction affliction in CharacterHealth.GetAllAfflictions())
|
||||||
{
|
{
|
||||||
skillLevel *= affliction.GetSkillMultiplier();
|
skillLevel *= affliction.GetSkillMultiplier();
|
||||||
|
|||||||
+2
-2
@@ -77,7 +77,7 @@ namespace Barotrauma
|
|||||||
else if (Strength < ActiveThreshold)
|
else if (Strength < ActiveThreshold)
|
||||||
{
|
{
|
||||||
DeactivateHusk();
|
DeactivateHusk();
|
||||||
if (Prefab is AfflictionPrefabHusk { CauseSpeechImpediment: false })
|
if (Prefab is AfflictionPrefabHusk { CauseSpeechImpediment: true })
|
||||||
{
|
{
|
||||||
character.SpeechImpediment = 100;
|
character.SpeechImpediment = 100;
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ namespace Barotrauma
|
|||||||
character.NeedsAir = false;
|
character.NeedsAir = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Prefab is AfflictionPrefabHusk { CauseSpeechImpediment: false })
|
if (Prefab is AfflictionPrefabHusk { CauseSpeechImpediment: true })
|
||||||
{
|
{
|
||||||
character.SpeechImpediment = 100;
|
character.SpeechImpediment = 100;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,20 @@ namespace Barotrauma
|
|||||||
private string rawAfflictionTypeString;
|
private string rawAfflictionTypeString;
|
||||||
private string[] parsedAfflictionIdentifiers;
|
private string[] parsedAfflictionIdentifiers;
|
||||||
private string[] parsedAfflictionTypes;
|
private string[] parsedAfflictionTypes;
|
||||||
|
public string[] ParsedAfflictionIdentifiers
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return parsedAfflictionIdentifiers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string[] ParsedAfflictionTypes
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return parsedAfflictionTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public DamageModifier(XElement element, string parentDebugName)
|
public DamageModifier(XElement element, string parentDebugName)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -167,9 +167,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CharacterInfo GetCharacterInfo()
|
public CharacterInfo GetCharacterInfo(Rand.RandSync randSync = Rand.RandSync.Unsynced)
|
||||||
{
|
{
|
||||||
var characterElement = ToolBox.SelectWeightedRandom(CustomNPCSets.Keys.ToList(), CustomNPCSets.Values.ToList(), Rand.RandSync.Unsynced);
|
var characterElement = ToolBox.SelectWeightedRandom(CustomNPCSets.Keys.ToList(), CustomNPCSets.Values.ToList(), randSync);
|
||||||
return characterElement != null ? new CharacterInfo(characterElement) : null;
|
return characterElement != null ? new CharacterInfo(characterElement) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -526,7 +526,7 @@ namespace Barotrauma
|
|||||||
[Serialize(false, true, description: "Does the character attack when provoked? When enabled, overrides the predefined targeting state with Attack and increases the priority of it."), Editable()]
|
[Serialize(false, true, description: "Does the character attack when provoked? When enabled, overrides the predefined targeting state with Attack and increases the priority of it."), Editable()]
|
||||||
public bool AttackWhenProvoked { get; private set; }
|
public bool AttackWhenProvoked { get; private set; }
|
||||||
|
|
||||||
[Serialize(true, true, description: "The character will flee for a brief moment when being shot at if not performing an attack."), Editable]
|
[Serialize(false, true, description: "The character will flee for a brief moment when being shot at if not performing an attack."), Editable]
|
||||||
public bool AvoidGunfire { get; private set; }
|
public bool AvoidGunfire { get; private set; }
|
||||||
|
|
||||||
[Serialize(3f, true, description: "How long the creature avoids gunfire. Also used when the creature is unlatched."), Editable(minValue: 0f, maxValue: 100f)]
|
[Serialize(3f, true, description: "How long the creature avoids gunfire. Also used when the creature is unlatched."), Editable(minValue: 0f, maxValue: 100f)]
|
||||||
@@ -565,6 +565,9 @@ namespace Barotrauma
|
|||||||
[Serialize(0f, true, description: ""), Editable]
|
[Serialize(0f, true, description: ""), Editable]
|
||||||
public float AggressionCumulation { get; private set; }
|
public float AggressionCumulation { get; private set; }
|
||||||
|
|
||||||
|
[Serialize(WallTargetingMethod.Target, true, description: ""), Editable]
|
||||||
|
public WallTargetingMethod WallTargetingMethod { get; private set; }
|
||||||
|
|
||||||
public IEnumerable<TargetParams> Targets => targets;
|
public IEnumerable<TargetParams> Targets => targets;
|
||||||
protected readonly List<TargetParams> targets = new List<TargetParams>();
|
protected readonly List<TargetParams> targets = new List<TargetParams>();
|
||||||
|
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ namespace Barotrauma
|
|||||||
UpdaterUtil.SaveFileList("filelist.xml");
|
UpdaterUtil.SaveFileList("filelist.xml");
|
||||||
}));
|
}));
|
||||||
|
|
||||||
commands.Add(new Command("spawn|spawncharacter", "spawn [creaturename/jobname] [near/inside/outside/cursor]: Spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine). You can also enter the name of a job (e.g. \"Mechanic\") to spawn a character with a specific job and the appropriate equipment.", null,
|
commands.Add(new Command("spawn|spawncharacter", "spawn [creaturename/jobname] [near/inside/outside/cursor] [team (0-3)]: Spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine). You can also enter the name of a job (e.g. \"Mechanic\") to spawn a character with a specific job and the appropriate equipment.", null,
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
List<string> characterFiles = GameMain.Instance.GetFilesOfType(ContentType.Character).Select(f => f.Path).ToList();
|
List<string> characterFiles = GameMain.Instance.GetFilesOfType(ContentType.Character).Select(f => f.Path).ToList();
|
||||||
@@ -1904,9 +1904,19 @@ namespace Barotrauma
|
|||||||
spawnPoint = WayPoint.GetRandom(human ? SpawnType.Human : SpawnType.Enemy);
|
spawnPoint = WayPoint.GetRandom(human ? SpawnType.Human : SpawnType.Enemy);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterTeamType teamType;
|
|
||||||
teamType = args.Length > 2 ? (CharacterTeamType)int.Parse(args[2]) : Character.Controlled != null ? Character.Controlled.TeamID : CharacterTeamType.Team1;
|
|
||||||
if (string.IsNullOrWhiteSpace(args[0])) { return; }
|
if (string.IsNullOrWhiteSpace(args[0])) { return; }
|
||||||
|
CharacterTeamType teamType = Character.Controlled != null ? Character.Controlled.TeamID : CharacterTeamType.Team1;
|
||||||
|
if (args.Length > 2)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
teamType = (CharacterTeamType)int.Parse(args[2]);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"\"{args[2]}\" is not a valid team id.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (spawnPoint != null) { spawnPosition = spawnPoint.WorldPosition; }
|
if (spawnPoint != null) { spawnPosition = spawnPoint.WorldPosition; }
|
||||||
|
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (speaker == null) { return; }
|
if (speaker == null) { return; }
|
||||||
speaker.CampaignInteractionType = CampaignMode.InteractionType.None;
|
speaker.CampaignInteractionType = CampaignMode.InteractionType.None;
|
||||||
speaker.ActiveConversation = this;
|
speaker.ActiveConversation = null;
|
||||||
speaker.SetCustomInteract(null, null);
|
speaker.SetCustomInteract(null, null);
|
||||||
#if SERVER
|
#if SERVER
|
||||||
GameMain.NetworkMember.CreateEntityEvent(speaker, new object[] { NetEntityEvent.Type.AssignCampaignInteraction });
|
GameMain.NetworkMember.CreateEntityEvent(speaker, new object[] { NetEntityEvent.Type.AssignCampaignInteraction });
|
||||||
|
|||||||
@@ -48,9 +48,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var goToObjective in humanAiController.ObjectiveManager.GetActiveObjectives<AIObjectiveGoTo>())
|
foreach (var objective in humanAiController.ObjectiveManager.Objectives)
|
||||||
{
|
{
|
||||||
if (goToObjective.Target == target)
|
if (objective is AIObjectiveGoTo goToObjective && goToObjective.Target == target)
|
||||||
{
|
{
|
||||||
goToObjective.Abandon = true;
|
goToObjective.Abandon = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace Barotrauma
|
|||||||
bool hasValidTargets = false;
|
bool hasValidTargets = false;
|
||||||
foreach (Entity target in targets)
|
foreach (Entity target in targets)
|
||||||
{
|
{
|
||||||
if (target is Character character && character.Inventory != null)
|
if (target is Character character && character.Inventory != null || target is Item)
|
||||||
{
|
{
|
||||||
hasValidTargets = true;
|
hasValidTargets = true;
|
||||||
break;
|
break;
|
||||||
@@ -55,20 +55,31 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (!hasValidTargets) { return; }
|
if (!hasValidTargets) { return; }
|
||||||
|
|
||||||
List<Item> usedItems = new List<Item>();
|
HashSet<Item> removedItems = new HashSet<Item>();
|
||||||
foreach (Entity target in targets)
|
foreach (Entity target in targets)
|
||||||
{
|
{
|
||||||
Inventory inventory = (target as Character)?.Inventory;
|
Inventory inventory = (target as Character)?.Inventory;
|
||||||
if (inventory == null) { continue; }
|
if (inventory != null)
|
||||||
while (usedItems.Count < Amount)
|
|
||||||
{
|
{
|
||||||
var item = inventory.FindItem(it =>
|
while (removedItems.Count < Amount)
|
||||||
it != null &&
|
{
|
||||||
!usedItems.Contains(it) &&
|
var item = inventory.FindItem(it =>
|
||||||
it.Prefab.Identifier.Equals(ItemIdentifier, StringComparison.InvariantCultureIgnoreCase), recursive: true);
|
it != null &&
|
||||||
if (item == null) { break; }
|
!removedItems.Contains(it) &&
|
||||||
Entity.Spawner.AddToRemoveQueue(item);
|
it.Prefab.Identifier.Equals(ItemIdentifier, StringComparison.InvariantCultureIgnoreCase), recursive: true);
|
||||||
usedItems.Add(item);
|
if (item == null) { break; }
|
||||||
|
Entity.Spawner.AddToRemoveQueue(item);
|
||||||
|
removedItems.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (target is Item item)
|
||||||
|
{
|
||||||
|
if (item.Prefab.Identifier.Equals(ItemIdentifier, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
Entity.Spawner.AddToRemoveQueue(item);
|
||||||
|
removedItems.Add(item);
|
||||||
|
if (removedItems.Count >= Amount) { break; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isFinished = true;
|
isFinished = true;
|
||||||
|
|||||||
@@ -107,27 +107,32 @@ namespace Barotrauma
|
|||||||
if (!string.IsNullOrEmpty(NPCSetIdentifier) && !string.IsNullOrEmpty(NPCIdentifier))
|
if (!string.IsNullOrEmpty(NPCSetIdentifier) && !string.IsNullOrEmpty(NPCIdentifier))
|
||||||
{
|
{
|
||||||
HumanPrefab humanPrefab = NPCSet.Get(NPCSetIdentifier, NPCIdentifier);
|
HumanPrefab humanPrefab = NPCSet.Get(NPCSetIdentifier, NPCIdentifier);
|
||||||
ISpatialEntity spawnPos = GetSpawnPos();
|
if (humanPrefab != null)
|
||||||
Entity.Spawner.AddToSpawnQueue(CharacterPrefab.HumanSpeciesName, OffsetSpawnPos(spawnPos?.WorldPosition ?? Vector2.Zero, 100.0f), humanPrefab.GetCharacterInfo(), onSpawn: newCharacter =>
|
|
||||||
{
|
{
|
||||||
newCharacter.TeamID = CharacterTeamType.FriendlyNPC;
|
ISpatialEntity spawnPos = GetSpawnPos();
|
||||||
newCharacter.EnableDespawn = false;
|
Entity.Spawner.AddToSpawnQueue(CharacterPrefab.HumanSpeciesName, OffsetSpawnPos(spawnPos?.WorldPosition ?? Vector2.Zero, 100.0f), humanPrefab.GetCharacterInfo(), onSpawn: newCharacter =>
|
||||||
humanPrefab.GiveItems(newCharacter, newCharacter.Submarine);
|
|
||||||
if (LootingIsStealing)
|
|
||||||
{
|
{
|
||||||
foreach (Item item in newCharacter.Inventory.AllItems)
|
if (newCharacter == null) { return; }
|
||||||
|
newCharacter.Prefab = humanPrefab;
|
||||||
|
newCharacter.TeamID = CharacterTeamType.FriendlyNPC;
|
||||||
|
newCharacter.EnableDespawn = false;
|
||||||
|
humanPrefab.GiveItems(newCharacter, newCharacter.Submarine);
|
||||||
|
if (LootingIsStealing)
|
||||||
{
|
{
|
||||||
item.SpawnedInOutpost = true;
|
foreach (Item item in newCharacter.Inventory.AllItems)
|
||||||
item.AllowStealing = false;
|
{
|
||||||
|
item.SpawnedInOutpost = true;
|
||||||
|
item.AllowStealing = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
humanPrefab.InitializeCharacter(newCharacter, spawnPos);
|
||||||
humanPrefab.InitializeCharacter(newCharacter, spawnPos);
|
if (!string.IsNullOrEmpty(TargetTag) && newCharacter != null)
|
||||||
if (!string.IsNullOrEmpty(TargetTag) && newCharacter != null)
|
{
|
||||||
{
|
ParentEvent.AddTarget(TargetTag, newCharacter);
|
||||||
ParentEvent.AddTarget(TargetTag, newCharacter);
|
}
|
||||||
}
|
spawnedEntity = newCharacter;
|
||||||
spawnedEntity = newCharacter;
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(SpeciesName))
|
else if (!string.IsNullOrEmpty(SpeciesName))
|
||||||
{
|
{
|
||||||
@@ -198,7 +203,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
spawned = true;
|
spawned = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector2 OffsetSpawnPos(Vector2 pos, float offsetAmount)
|
public static Vector2 OffsetSpawnPos(Vector2 pos, float offsetAmount)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
class TagAction : EventAction
|
class TagAction : EventAction
|
||||||
{
|
{
|
||||||
public enum SubType { Any= 0, Player = 1, Outpost = 2, Wreck = 4, BeaconStation = 8 }
|
public enum SubType { Any = 0, Player = 1, Outpost = 2, Wreck = 4, BeaconStation = 8 }
|
||||||
|
|
||||||
[Serialize("", true)]
|
[Serialize("", true)]
|
||||||
public string Criteria { get; set; }
|
public string Criteria { get; set; }
|
||||||
@@ -67,6 +67,16 @@ namespace Barotrauma
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TagHumansByIdentifier(string identifier)
|
||||||
|
{
|
||||||
|
foreach (Character c in Character.CharacterList)
|
||||||
|
{
|
||||||
|
if (c.Prefab?.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase) ?? false)
|
||||||
|
{
|
||||||
|
ParentEvent.AddTarget(Tag, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
private void TagStructuresByIdentifier(string identifier)
|
private void TagStructuresByIdentifier(string identifier)
|
||||||
{
|
{
|
||||||
ParentEvent.AddTargetPredicate(Tag, e => e is Structure s && SubmarineTypeMatches(s.Submarine) && s.Prefab.Identifier.Equals(identifier, StringComparison.InvariantCultureIgnoreCase));
|
ParentEvent.AddTargetPredicate(Tag, e => e is Structure s && SubmarineTypeMatches(s.Submarine) && s.Prefab.Identifier.Equals(identifier, StringComparison.InvariantCultureIgnoreCase));
|
||||||
@@ -122,6 +132,9 @@ namespace Barotrauma
|
|||||||
case "crew":
|
case "crew":
|
||||||
TagCrew();
|
TagCrew();
|
||||||
break;
|
break;
|
||||||
|
case "humanprefabidentifier":
|
||||||
|
if (kvp.Length > 1) { TagHumansByIdentifier(kvp[1].Trim()); }
|
||||||
|
break;
|
||||||
case "structureidentifier":
|
case "structureidentifier":
|
||||||
if (kvp.Length > 1) { TagStructuresByIdentifier(kvp[1].Trim()); }
|
if (kvp.Length > 1) { TagStructuresByIdentifier(kvp[1].Trim()); }
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
npcOrItem = npc;
|
npcOrItem = npc;
|
||||||
npc.CampaignInteractionType = CampaignMode.InteractionType.Examine;
|
npc.CampaignInteractionType = CampaignMode.InteractionType.Examine;
|
||||||
|
npc.RequireConsciousnessForCustomInteract = false;
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
npc.SetCustomInteract(
|
npc.SetCustomInteract(
|
||||||
(speaker, player) => { if (e1 == speaker) { Trigger(speaker, player); } else { Trigger(player, speaker); } },
|
(speaker, player) => { if (e1 == speaker) { Trigger(speaker, player); } else { Trigger(player, speaker); } },
|
||||||
@@ -132,7 +133,6 @@ namespace Barotrauma
|
|||||||
TextManager.Get("CampaignInteraction.Talk"));
|
TextManager.Get("CampaignInteraction.Talk"));
|
||||||
GameMain.NetworkMember.CreateEntityEvent(npc, new object[] { NetEntityEvent.Type.AssignCampaignInteraction });
|
GameMain.NetworkMember.CreateEntityEvent(npc, new object[] { NetEntityEvent.Type.AssignCampaignInteraction });
|
||||||
#endif
|
#endif
|
||||||
npc.RequireConsciousnessForCustomInteract = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -176,6 +176,9 @@ namespace Barotrauma
|
|||||||
npc.CampaignInteractionType = CampaignMode.InteractionType.None;
|
npc.CampaignInteractionType = CampaignMode.InteractionType.None;
|
||||||
npc.SetCustomInteract(null, null);
|
npc.SetCustomInteract(null, null);
|
||||||
npc.RequireConsciousnessForCustomInteract = true;
|
npc.RequireConsciousnessForCustomInteract = true;
|
||||||
|
#if SERVER
|
||||||
|
GameMain.NetworkMember.CreateEntityEvent(npc, new object[] { NetEntityEvent.Type.AssignCampaignInteraction });
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if (npcOrItem.TryGet(out Item item))
|
else if (npcOrItem.TryGet(out Item item))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ namespace Barotrauma
|
|||||||
if (eventSet == null) { return; }
|
if (eventSet == null) { return; }
|
||||||
if (eventSet.OncePerOutpost)
|
if (eventSet.OncePerOutpost)
|
||||||
{
|
{
|
||||||
foreach (EventPrefab ep in eventSet.EventPrefabs.Select(e => e.First))
|
foreach (EventPrefab ep in eventSet.EventPrefabs.Select(e => e.prefab))
|
||||||
{
|
{
|
||||||
if (!level.LevelData.NonRepeatableEvents.Contains(ep))
|
if (!level.LevelData.NonRepeatableEvents.Contains(ep))
|
||||||
{
|
{
|
||||||
@@ -374,11 +374,11 @@ namespace Barotrauma
|
|||||||
preloadedSprites.Clear();
|
preloadedSprites.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private float CalculateCommonness(Pair<EventPrefab, float> eventPrefab)
|
private float CalculateCommonness(EventPrefab eventPrefab, float baseCommonness)
|
||||||
{
|
{
|
||||||
if (level.LevelData.NonRepeatableEvents.Contains(eventPrefab.First)) { return 0.0f; }
|
if (level.LevelData.NonRepeatableEvents.Contains(eventPrefab)) { return 0.0f; }
|
||||||
float retVal = eventPrefab.Second;
|
float retVal = baseCommonness;
|
||||||
if (level.LevelData.EventHistory.Contains(eventPrefab.First)) { retVal *= 0.1f; }
|
if (level.LevelData.EventHistory.Contains(eventPrefab)) { retVal *= 0.1f; }
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,8 +420,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
var suitablePrefabs = eventSet.EventPrefabs.FindAll(e =>
|
var suitablePrefabs = eventSet.EventPrefabs.FindAll(e =>
|
||||||
string.IsNullOrEmpty(e.First.BiomeIdentifier) ||
|
string.IsNullOrEmpty(e.prefab.BiomeIdentifier) ||
|
||||||
e.First.BiomeIdentifier.Equals(level.LevelData?.Biome?.Identifier, StringComparison.OrdinalIgnoreCase));
|
e.prefab.BiomeIdentifier.Equals(level.LevelData?.Biome?.Identifier, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
for (int i = 0; i < applyCount; i++)
|
for (int i = 0; i < applyCount; i++)
|
||||||
{
|
{
|
||||||
@@ -429,14 +429,14 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (suitablePrefabs.Count > 0)
|
if (suitablePrefabs.Count > 0)
|
||||||
{
|
{
|
||||||
List<Pair<EventPrefab, float>> unusedEvents = new List<Pair<EventPrefab, float>>(suitablePrefabs);
|
var unusedEvents = new List<(EventPrefab prefab, float commonness, float probability)>(suitablePrefabs);
|
||||||
for (int j = 0; j < eventSet.EventCount; j++)
|
for (int j = 0; j < eventSet.EventCount; j++)
|
||||||
{
|
{
|
||||||
if (unusedEvents.All(e => CalculateCommonness(e) <= 0.0f)) { break; }
|
if (unusedEvents.All(e => CalculateCommonness(e.prefab, e.commonness) <= 0.0f)) { break; }
|
||||||
var eventPrefab = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => CalculateCommonness(e)).ToList(), rand);
|
(EventPrefab eventPrefab, float commonness, float probability) = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => CalculateCommonness(e.prefab, e.commonness)).ToList(), rand);
|
||||||
if (eventPrefab != null)
|
if (eventPrefab != null && rand.NextDouble() <= probability)
|
||||||
{
|
{
|
||||||
var newEvent = eventPrefab.First.CreateInstance();
|
var newEvent = eventPrefab.CreateInstance();
|
||||||
if (newEvent == null) { continue; }
|
if (newEvent == null) { continue; }
|
||||||
newEvent.Init(true);
|
newEvent.Init(true);
|
||||||
if (i < spawnPosFilter.Count) { newEvent.SpawnPosFilter = spawnPosFilter[i]; }
|
if (i < spawnPosFilter.Count) { newEvent.SpawnPosFilter = spawnPosFilter[i]; }
|
||||||
@@ -450,7 +450,7 @@ namespace Barotrauma
|
|||||||
selectedEvents.Add(eventSet, new List<Event>());
|
selectedEvents.Add(eventSet, new List<Event>());
|
||||||
}
|
}
|
||||||
selectedEvents[eventSet].Add(newEvent);
|
selectedEvents[eventSet].Add(newEvent);
|
||||||
unusedEvents.Remove(eventPrefab);
|
unusedEvents.Remove((eventPrefab, commonness, probability));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -465,9 +465,10 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (Pair<EventPrefab, float> eventPrefab in suitablePrefabs)
|
foreach ((EventPrefab eventPrefab, float commonness, float probability) in suitablePrefabs)
|
||||||
{
|
{
|
||||||
var newEvent = eventPrefab.First.CreateInstance();
|
if (rand.NextDouble() > probability) { continue; }
|
||||||
|
var newEvent = eventPrefab.CreateInstance();
|
||||||
if (newEvent == null) { continue; }
|
if (newEvent == null) { continue; }
|
||||||
newEvent.Init(true);
|
newEvent.Init(true);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
public readonly XElement ConfigElement;
|
public readonly XElement ConfigElement;
|
||||||
public readonly Type EventType;
|
public readonly Type EventType;
|
||||||
public readonly float SpawnProbability;
|
public readonly float Probability;
|
||||||
public readonly bool TriggerEventCooldown;
|
public readonly bool TriggerEventCooldown;
|
||||||
public float Commonness;
|
public float Commonness;
|
||||||
public string Identifier;
|
public string Identifier;
|
||||||
@@ -39,7 +39,7 @@ namespace Barotrauma
|
|||||||
Identifier = ConfigElement.GetAttributeString("identifier", string.Empty);
|
Identifier = ConfigElement.GetAttributeString("identifier", string.Empty);
|
||||||
BiomeIdentifier = ConfigElement.GetAttributeString("biome", string.Empty);
|
BiomeIdentifier = ConfigElement.GetAttributeString("biome", string.Empty);
|
||||||
Commonness = element.GetAttributeFloat("commonness", 1.0f);
|
Commonness = element.GetAttributeFloat("commonness", 1.0f);
|
||||||
SpawnProbability = Math.Clamp(element.GetAttributeFloat("spawnprobability", 1.0f), 0, 1);
|
Probability = Math.Clamp(element.GetAttributeFloat(1.0f, "probability", "spawnprobability"), 0, 1);
|
||||||
TriggerEventCooldown = element.GetAttributeBool("triggereventcooldown", true);
|
TriggerEventCooldown = element.GetAttributeBool("triggereventcooldown", true);
|
||||||
|
|
||||||
UnlockPathEvent = element.GetAttributeBool("unlockpathevent", false);
|
UnlockPathEvent = element.GetAttributeBool("unlockpathevent", false);
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ namespace Barotrauma
|
|||||||
List<EventPrefab> eventPrefabs = new List<EventPrefab>(PrefabList);
|
List<EventPrefab> eventPrefabs = new List<EventPrefab>(PrefabList);
|
||||||
foreach (var eventSet in List)
|
foreach (var eventSet in List)
|
||||||
{
|
{
|
||||||
eventPrefabs.AddRange(eventSet.EventPrefabs.Select(ep => ep.First));
|
eventPrefabs.AddRange(eventSet.EventPrefabs.Select(ep => ep.prefab));
|
||||||
foreach (var childSet in eventSet.ChildSets)
|
foreach (var childSet in eventSet.ChildSets)
|
||||||
{
|
{
|
||||||
eventPrefabs.AddRange(childSet.EventPrefabs.Select(ep => ep.First));
|
eventPrefabs.AddRange(childSet.EventPrefabs.Select(ep => ep.prefab));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return eventPrefabs;
|
return eventPrefabs;
|
||||||
@@ -96,8 +96,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public readonly Dictionary<string, float> Commonness;
|
public readonly Dictionary<string, float> Commonness;
|
||||||
|
|
||||||
//Pair.First: event prefab, Pair.Second: commonness
|
public readonly List<(EventPrefab prefab, float commonness, float probability)> EventPrefabs;
|
||||||
public readonly List<Pair<EventPrefab, float>> EventPrefabs;
|
|
||||||
|
|
||||||
public readonly List<EventSet> ChildSets;
|
public readonly List<EventSet> ChildSets;
|
||||||
|
|
||||||
@@ -111,7 +110,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
DebugIdentifier = element.GetAttributeString("identifier", null) ?? debugIdentifier;
|
DebugIdentifier = element.GetAttributeString("identifier", null) ?? debugIdentifier;
|
||||||
Commonness = new Dictionary<string, float>();
|
Commonness = new Dictionary<string, float>();
|
||||||
EventPrefabs = new List<Pair<EventPrefab, float>>();
|
EventPrefabs = new List<(EventPrefab prefab, float commonness, float probability)>();
|
||||||
ChildSets = new List<EventSet>();
|
ChildSets = new List<EventSet>();
|
||||||
|
|
||||||
BiomeIdentifier = element.GetAttributeString("biome", string.Empty);
|
BiomeIdentifier = element.GetAttributeString("biome", string.Empty);
|
||||||
@@ -184,13 +183,14 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
float commonness = subElement.GetAttributeFloat("commonness", prefab.Commonness);
|
float commonness = subElement.GetAttributeFloat("commonness", prefab.Commonness);
|
||||||
EventPrefabs.Add(new Pair<EventPrefab, float>( prefab, commonness));
|
float probability = subElement.GetAttributeFloat("probability", prefab.Probability);
|
||||||
|
EventPrefabs.Add((prefab, commonness, probability));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var prefab = new EventPrefab(subElement);
|
var prefab = new EventPrefab(subElement);
|
||||||
EventPrefabs.Add(new Pair<EventPrefab, float>(prefab, prefab.Commonness));
|
EventPrefabs.Add((prefab, prefab.Commonness, prefab.Probability));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -342,13 +342,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (thisSet.ChooseRandom)
|
if (thisSet.ChooseRandom)
|
||||||
{
|
{
|
||||||
List<Pair<EventPrefab, float>> unusedEvents = new List<Pair<EventPrefab, float>>(thisSet.EventPrefabs);
|
var unusedEvents = new List<(EventPrefab prefab, float commonness, float probability)>(thisSet.EventPrefabs);
|
||||||
for (int i = 0; i < thisSet.EventCount; i++)
|
for (int i = 0; i < thisSet.EventCount; i++)
|
||||||
{
|
{
|
||||||
var eventPrefab = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => e.Second).ToList(), Rand.RandSync.Unsynced);
|
var eventPrefab = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => e.commonness).ToList(), Rand.RandSync.Unsynced);
|
||||||
if (eventPrefab != null)
|
if (eventPrefab.prefab != null)
|
||||||
{
|
{
|
||||||
AddEvent(stats, eventPrefab.First);
|
AddEvent(stats, eventPrefab.prefab);
|
||||||
unusedEvents.Remove(eventPrefab);
|
unusedEvents.Remove(eventPrefab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -357,7 +357,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (var eventPrefab in thisSet.EventPrefabs)
|
foreach (var eventPrefab in thisSet.EventPrefabs)
|
||||||
{
|
{
|
||||||
AddEvent(stats, eventPrefab.First);
|
AddEvent(stats, eventPrefab.prefab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var childSet in thisSet.ChildSets)
|
foreach (var childSet in thisSet.ChildSets)
|
||||||
|
|||||||
@@ -24,6 +24,19 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private Submarine sub;
|
private Submarine sub;
|
||||||
|
|
||||||
|
public override string Description
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Submarine.MainSub != sub)
|
||||||
|
{
|
||||||
|
string rewardText = $"‖color:gui.orange‖{string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:N0}", GetReward(Submarine.MainSub))}‖end‖";
|
||||||
|
if (descriptionWithoutReward != null) { description = descriptionWithoutReward.Replace("[reward]", rewardText); }
|
||||||
|
}
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public CargoMission(MissionPrefab prefab, Location[] locations, Submarine sub)
|
public CargoMission(MissionPrefab prefab, Location[] locations, Submarine sub)
|
||||||
: base(prefab, locations, sub)
|
: base(prefab, locations, sub)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,12 +14,15 @@ namespace Barotrauma
|
|||||||
private readonly XElement itemConfig;
|
private readonly XElement itemConfig;
|
||||||
|
|
||||||
private readonly List<Character> characters = new List<Character>();
|
private readonly List<Character> characters = new List<Character>();
|
||||||
private readonly Dictionary<Character, List<Item>> characterDictionary = new Dictionary<Character, List<Item>>();
|
private readonly Dictionary<Character, List<Item>> characterItems = new Dictionary<Character, List<Item>>();
|
||||||
|
|
||||||
private readonly int baseEscortedCharacters;
|
private readonly int baseEscortedCharacters;
|
||||||
private readonly float scalingEscortedCharacters;
|
private readonly float scalingEscortedCharacters;
|
||||||
private readonly float terroristChance;
|
private readonly float terroristChance;
|
||||||
|
|
||||||
|
private int calculatedReward;
|
||||||
|
private Submarine missionSub;
|
||||||
|
|
||||||
private Character vipCharacter;
|
private Character vipCharacter;
|
||||||
|
|
||||||
private readonly List<Character> terroristCharacters = new List<Character>();
|
private readonly List<Character> terroristCharacters = new List<Character>();
|
||||||
@@ -30,24 +33,43 @@ namespace Barotrauma
|
|||||||
public EscortMission(MissionPrefab prefab, Location[] locations, Submarine sub)
|
public EscortMission(MissionPrefab prefab, Location[] locations, Submarine sub)
|
||||||
: base(prefab, locations, sub)
|
: base(prefab, locations, sub)
|
||||||
{
|
{
|
||||||
|
missionSub = sub;
|
||||||
characterConfig = prefab.ConfigElement.Element("Characters");
|
characterConfig = prefab.ConfigElement.Element("Characters");
|
||||||
// Should reflect different escortables, prisoners, VIPs, passengers (where does this comment refer to?)
|
|
||||||
|
|
||||||
baseEscortedCharacters = prefab.ConfigElement.GetAttributeInt("baseescortedcharacters", 1);
|
baseEscortedCharacters = prefab.ConfigElement.GetAttributeInt("baseescortedcharacters", 1);
|
||||||
scalingEscortedCharacters = prefab.ConfigElement.GetAttributeFloat("scalingescortedcharacters", 0);
|
scalingEscortedCharacters = prefab.ConfigElement.GetAttributeFloat("scalingescortedcharacters", 0);
|
||||||
terroristChance = prefab.ConfigElement.GetAttributeFloat("terroristchance", 0);
|
terroristChance = prefab.ConfigElement.GetAttributeFloat("terroristchance", 0);
|
||||||
itemConfig = prefab.ConfigElement.Element("TerroristItems");
|
itemConfig = prefab.ConfigElement.Element("TerroristItems");
|
||||||
|
CalculateReward();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateReward()
|
||||||
|
{
|
||||||
|
if (missionSub == null)
|
||||||
|
{
|
||||||
|
calculatedReward = Prefab.Reward;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int multiplier = CalculateScalingEscortedCharacterCount();
|
||||||
|
calculatedReward = Prefab.Reward * multiplier;
|
||||||
|
|
||||||
|
string rewardText = $"‖color:gui.orange‖{string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:N0}", GetReward(missionSub))}‖end‖";
|
||||||
|
if (descriptionWithoutReward != null) { description = descriptionWithoutReward.Replace("[reward]", rewardText); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetReward(Submarine sub)
|
public override int GetReward(Submarine sub)
|
||||||
{
|
{
|
||||||
int multiplier = CalculateScalingEscortedCharacterCount();
|
if (sub != missionSub)
|
||||||
return Prefab.Reward * multiplier;
|
{
|
||||||
|
missionSub = sub;
|
||||||
|
CalculateReward();
|
||||||
|
}
|
||||||
|
return calculatedReward;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CalculateScalingEscortedCharacterCount(bool inMission = false)
|
int CalculateScalingEscortedCharacterCount(bool inMission = false)
|
||||||
{
|
{
|
||||||
if (Submarine.MainSub == null || Submarine.MainSub.Info == null) // UI logic failing to get the correct value is not important, but the mission logic must succeed
|
if (missionSub == null || missionSub.Info == null) // UI logic failing to get the correct value is not important, but the mission logic must succeed
|
||||||
{
|
{
|
||||||
if (inMission)
|
if (inMission)
|
||||||
{
|
{
|
||||||
@@ -55,13 +77,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return (int)Math.Round(baseEscortedCharacters + scalingEscortedCharacters * (Submarine.MainSub.Info.RecommendedCrewSizeMin + Submarine.MainSub.Info.RecommendedCrewSizeMax) / 2);
|
return (int)Math.Round(baseEscortedCharacters + scalingEscortedCharacters * (missionSub.Info.RecommendedCrewSizeMin + missionSub.Info.RecommendedCrewSizeMax) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitEscort()
|
private void InitEscort()
|
||||||
{
|
{
|
||||||
characters.Clear();
|
characters.Clear();
|
||||||
characterDictionary.Clear();
|
characterItems.Clear();
|
||||||
// VIP transport mission characters stay in the same location; other characters roam at will
|
// VIP transport mission characters stay in the same location; other characters roam at will
|
||||||
// could be replaced with a designated waypoint for VIPs, such as cargo or crew
|
// could be replaced with a designated waypoint for VIPs, such as cargo or crew
|
||||||
WayPoint explicitStayInHullPos = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);
|
WayPoint explicitStayInHullPos = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub);
|
||||||
@@ -78,7 +100,7 @@ namespace Barotrauma
|
|||||||
int count = CalculateScalingEscortedCharacterCount(inMission: true);
|
int count = CalculateScalingEscortedCharacterCount(inMission: true);
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
Character spawnedCharacter = CreateHuman(CreateHumanPrefabFromElement(element), characters, characterDictionary, Submarine.MainSub, CharacterTeamType.FriendlyNPC, explicitStayInHullPos, humanPrefabRandSync: randSync);
|
Character spawnedCharacter = CreateHuman(CreateHumanPrefabFromElement(element), characters, characterItems, Submarine.MainSub, CharacterTeamType.FriendlyNPC, explicitStayInHullPos, humanPrefabRandSync: randSync);
|
||||||
if (spawnedCharacter.AIController is HumanAIController humanAI)
|
if (spawnedCharacter.AIController is HumanAIController humanAI)
|
||||||
{
|
{
|
||||||
humanAI.InitMentalStateManager();
|
humanAI.InitMentalStateManager();
|
||||||
@@ -156,6 +178,13 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// to ensure single missions run without issues, default to mainsub
|
||||||
|
if (missionSub == null)
|
||||||
|
{
|
||||||
|
missionSub = Submarine.MainSub;
|
||||||
|
CalculateReward();
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsClient)
|
if (!IsClient)
|
||||||
{
|
{
|
||||||
InitEscort();
|
InitEscort();
|
||||||
@@ -276,7 +305,7 @@ namespace Barotrauma
|
|||||||
// characters that survived will take their items with them, in case players tried to be crafty and steal them
|
// characters that survived will take their items with them, in case players tried to be crafty and steal them
|
||||||
// this needs to run here in case players abort the mission by going back home
|
// this needs to run here in case players abort the mission by going back home
|
||||||
// TODO: I think this might feel like a bug.
|
// TODO: I think this might feel like a bug.
|
||||||
foreach (var characterItem in characterDictionary)
|
foreach (var characterItem in characterItems)
|
||||||
{
|
{
|
||||||
if (Survived(characterItem.Key) || !completed)
|
if (Survived(characterItem.Key) || !completed)
|
||||||
{
|
{
|
||||||
@@ -291,7 +320,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
characters.Clear();
|
characters.Clear();
|
||||||
characterDictionary.Clear();
|
characterItems.Clear();
|
||||||
failed = !completed;
|
failed = !completed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -400,8 +400,6 @@ namespace Barotrauma
|
|||||||
// putting these here since both escort and pirate missions need them. could be tucked away into another class that they can inherit from (or use composition)
|
// putting these here since both escort and pirate missions need them. could be tucked away into another class that they can inherit from (or use composition)
|
||||||
protected HumanPrefab CreateHumanPrefabFromElement(XElement element)
|
protected HumanPrefab CreateHumanPrefabFromElement(XElement element)
|
||||||
{
|
{
|
||||||
HumanPrefab humanPrefab = null;
|
|
||||||
|
|
||||||
if (element.Attribute("name") != null)
|
if (element.Attribute("name") != null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Error in mission \"" + Name + "\" - use character identifiers instead of names to configure the characters.");
|
DebugConsole.ThrowError("Error in mission \"" + Name + "\" - use character identifiers instead of names to configure the characters.");
|
||||||
@@ -411,8 +409,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
string characterIdentifier = element.GetAttributeString("identifier", "");
|
string characterIdentifier = element.GetAttributeString("identifier", "");
|
||||||
string characterFrom = element.GetAttributeString("from", "");
|
string characterFrom = element.GetAttributeString("from", "");
|
||||||
humanPrefab = NPCSet.Get(characterFrom, characterIdentifier);
|
HumanPrefab humanPrefab = NPCSet.Get(characterFrom, characterIdentifier);
|
||||||
|
|
||||||
if (humanPrefab == null)
|
if (humanPrefab == null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Couldn't spawn character for mission: character prefab \"" + characterIdentifier + "\" not found");
|
DebugConsole.ThrowError("Couldn't spawn character for mission: character prefab \"" + characterIdentifier + "\" not found");
|
||||||
@@ -428,9 +425,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
positionToStayIn = WayPoint.GetRandom(SpawnType.Human, null, submarine);
|
positionToStayIn = WayPoint.GetRandom(SpawnType.Human, null, submarine);
|
||||||
}
|
}
|
||||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, npcIdentifier: humanPrefab.Identifier, jobPrefab: humanPrefab.GetJobPrefab(humanPrefabRandSync), randSync: humanPrefabRandSync);
|
|
||||||
|
var characterInfo = humanPrefab.GetCharacterInfo(Rand.RandSync.Server) ?? new CharacterInfo(CharacterPrefab.HumanSpeciesName, npcIdentifier: humanPrefab.Identifier, jobPrefab: humanPrefab.GetJobPrefab(humanPrefabRandSync), randSync: humanPrefabRandSync);
|
||||||
characterInfo.TeamID = teamType;
|
characterInfo.TeamID = teamType;
|
||||||
Character spawnedCharacter = Character.Create(characterInfo.SpeciesName, positionToStayIn.WorldPosition, ToolBox.RandomSeed(8), characterInfo, createNetworkEvent: false);
|
Character spawnedCharacter = Character.Create(characterInfo.SpeciesName, positionToStayIn.WorldPosition, ToolBox.RandomSeed(8), characterInfo, createNetworkEvent: false);
|
||||||
|
spawnedCharacter.Prefab = humanPrefab;
|
||||||
humanPrefab.InitializeCharacter(spawnedCharacter, positionToStayIn);
|
humanPrefab.InitializeCharacter(spawnedCharacter, positionToStayIn);
|
||||||
humanPrefab.GiveItems(spawnedCharacter, submarine, Rand.RandSync.Server, createNetworkEvents: false);
|
humanPrefab.GiveItems(spawnedCharacter, submarine, Rand.RandSync.Server, createNetworkEvents: false);
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private Submarine enemySub;
|
private Submarine enemySub;
|
||||||
private readonly List<Character> characters = new List<Character>();
|
private readonly List<Character> characters = new List<Character>();
|
||||||
private readonly Dictionary<Character, List<Item>> characterDictionary = new Dictionary<Character, List<Item>>();
|
private readonly Dictionary<Character, List<Item>> characterItems = new Dictionary<Character, List<Item>>();
|
||||||
|
|
||||||
// Update the last sighting periodically so that the players can find the pirate sub even if they have lost the track of it.
|
// Update the last sighting periodically so that the players can find the pirate sub even if they have lost the track of it.
|
||||||
private readonly float pirateSightingUpdateFrequency = 30;
|
private readonly float pirateSightingUpdateFrequency = 30;
|
||||||
@@ -103,17 +103,20 @@ namespace Barotrauma
|
|||||||
|
|
||||||
alternateReward = submarineConfig.GetAttributeInt("alternatereward", Reward);
|
alternateReward = submarineConfig.GetAttributeInt("alternatereward", Reward);
|
||||||
|
|
||||||
string submarineIdentifier = submarineConfig.GetAttributeString("identifier", string.Empty);
|
string rewardText = $"‖color:gui.orange‖{string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:N0}", alternateReward)}‖end‖";
|
||||||
if (submarineIdentifier == string.Empty)
|
if (descriptionWithoutReward != null) { description = descriptionWithoutReward.Replace("[reward]", rewardText); }
|
||||||
|
|
||||||
|
string submarinePath = submarineConfig.GetAttributeString("path", string.Empty);
|
||||||
|
if (submarinePath == string.Empty)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("No identifier used for submarine for pirate mission!");
|
DebugConsole.ThrowError($"No path used for submarine for the pirate mission \"{Prefab.Identifier}\"!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// maybe a little redundant
|
// maybe a little redundant
|
||||||
var contentFile = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.EnemySubmarine).FirstOrDefault(x => x.Path == submarineIdentifier);
|
var contentFile = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.EnemySubmarine).FirstOrDefault(x => x.Path == submarinePath);
|
||||||
if (contentFile == null)
|
if (contentFile == null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("No submarine file found with the identifier!");
|
DebugConsole.ThrowError($"No submarine file found from the path {submarinePath}!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,14 +190,13 @@ namespace Barotrauma
|
|||||||
reactor.PowerUpImmediately();
|
reactor.PowerUpImmediately();
|
||||||
}
|
}
|
||||||
enemySub.EnableMaintainPosition();
|
enemySub.EnableMaintainPosition();
|
||||||
enemySub.SetPosition(spawnPos);
|
|
||||||
enemySub.TeamID = CharacterTeamType.None;
|
enemySub.TeamID = CharacterTeamType.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitPirates()
|
private void InitPirates()
|
||||||
{
|
{
|
||||||
characters.Clear();
|
characters.Clear();
|
||||||
characterDictionary.Clear();
|
characterItems.Clear();
|
||||||
|
|
||||||
if (characterConfig == null)
|
if (characterConfig == null)
|
||||||
{
|
{
|
||||||
@@ -222,13 +224,13 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (characterType == null)
|
if (characterType == null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("No character types defined in CharacterTypes for a declared type identifier in mission file " + this);
|
DebugConsole.ThrowError($"No character types defined in CharacterTypes for a declared type identifier in mission \"{Prefab.Identifier}\".");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
XElement variantElement = GetRandomDifficultyModifiedElement(characterType, enemyCreationDifficulty, RandomnessModifier);
|
XElement variantElement = GetRandomDifficultyModifiedElement(characterType, enemyCreationDifficulty, RandomnessModifier);
|
||||||
|
|
||||||
Character spawnedCharacter = CreateHuman(CreateHumanPrefabFromElement(variantElement), characters, characterDictionary, enemySub, CharacterTeamType.None, null);
|
Character spawnedCharacter = CreateHuman(CreateHumanPrefabFromElement(variantElement), characters, characterItems, enemySub, CharacterTeamType.None, null);
|
||||||
if (!commanderAssigned)
|
if (!commanderAssigned)
|
||||||
{
|
{
|
||||||
bool isCommander = variantElement.GetAttributeBool("iscommander", false);
|
bool isCommander = variantElement.GetAttributeBool("iscommander", false);
|
||||||
@@ -242,6 +244,14 @@ namespace Barotrauma
|
|||||||
commanderAssigned = true;
|
commanderAssigned = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (Item item in spawnedCharacter.Inventory.AllItems)
|
||||||
|
{
|
||||||
|
if (item?.Prefab.Identifier == "idcard")
|
||||||
|
{
|
||||||
|
item.AddTag("id_pirate");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,9 +307,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
InitPirateShip(spawnPos);
|
InitPirateShip(spawnPos);
|
||||||
}
|
}
|
||||||
|
enemySub.SetPosition(spawnPos);
|
||||||
|
|
||||||
// flipping the sub on the frame it is moved into place must be done after it's been moved, or it breaks item connections to the submarine
|
// flipping the sub on the frame it is moved into place must be done after it's been moved, or it breaks item connections in the submarine
|
||||||
// creating the pirates have to be done after the sub has been flipped, or it seems to break the AI pathing
|
// creating the pirates has to be done after the sub has been flipped, or it seems to break the AI pathing
|
||||||
enemySub.FlipX();
|
enemySub.FlipX();
|
||||||
enemySub.ShowSonarMarker = false;
|
enemySub.ShowSonarMarker = false;
|
||||||
|
|
||||||
@@ -375,7 +386,7 @@ namespace Barotrauma
|
|||||||
completed = true;
|
completed = true;
|
||||||
}
|
}
|
||||||
characters.Clear();
|
characters.Clear();
|
||||||
characterDictionary.Clear();
|
characterItems.Clear();
|
||||||
failed = !completed;
|
failed = !completed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,13 +182,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (disallowed) { return; }
|
if (disallowed) { return; }
|
||||||
|
|
||||||
if (Rand.Value(Rand.RandSync.Server) > prefab.SpawnProbability)
|
|
||||||
{
|
|
||||||
spawnPos = null;
|
|
||||||
Finished();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
spawnPos = Vector2.Zero;
|
spawnPos = Vector2.Zero;
|
||||||
var availablePositions = GetAvailableSpawnPositions();
|
var availablePositions = GetAvailableSpawnPositions();
|
||||||
var chosenPosition = new Level.InterestingPosition(Point.Zero, Level.PositionType.MainPath, isValid: false);
|
var chosenPosition = new Level.InterestingPosition(Point.Zero, Level.PositionType.MainPath, isValid: false);
|
||||||
|
|||||||
@@ -207,7 +207,8 @@ namespace Barotrauma
|
|||||||
SpawnedInOutpost = validContainer.Key.Item.SpawnedInOutpost,
|
SpawnedInOutpost = validContainer.Key.Item.SpawnedInOutpost,
|
||||||
AllowStealing = validContainer.Key.Item.AllowStealing,
|
AllowStealing = validContainer.Key.Item.AllowStealing,
|
||||||
OriginalModuleIndex = validContainer.Key.Item.OriginalModuleIndex,
|
OriginalModuleIndex = validContainer.Key.Item.OriginalModuleIndex,
|
||||||
OriginalContainerID = validContainer.Key.Item.ID
|
OriginalContainerIndex =
|
||||||
|
Item.ItemList.Where(it => it.Submarine == validContainer.Key.Item.Submarine && it.OriginalModuleIndex == validContainer.Key.Item.OriginalModuleIndex).ToList().IndexOf(validContainer.Key.Item)
|
||||||
};
|
};
|
||||||
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
|
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -246,42 +246,21 @@ namespace Barotrauma
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
availableContainers.Add(itemContainer);
|
availableContainers.Add(itemContainer);
|
||||||
#if SERVER
|
#if SERVER
|
||||||
if (GameMain.Server != null)
|
if (GameMain.Server != null)
|
||||||
{
|
{
|
||||||
Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
|
Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemContainer == null)
|
var item = new Item(pi.ItemPrefab, position, wp.Submarine);
|
||||||
{
|
itemContainer?.Inventory.TryPutItem(item, null);
|
||||||
//no container, place at the waypoint
|
itemSpawned(item);
|
||||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
#if SERVER
|
||||||
{
|
Entity.Spawner?.CreateNetworkEvent(item, false);
|
||||||
Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, position, wp.Submarine, onSpawned: itemSpawned);
|
#endif
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var item = new Item(pi.ItemPrefab, position, wp.Submarine);
|
|
||||||
itemSpawned(item);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//place in the container
|
|
||||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
|
||||||
{
|
|
||||||
Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, itemContainer.Inventory, onSpawned: itemSpawned);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var item = new Item(pi.ItemPrefab, position, wp.Submarine);
|
|
||||||
itemContainer.Inventory.TryPutItem(item, null);
|
|
||||||
itemSpawned(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void itemSpawned(Item item)
|
static void itemSpawned(Item item)
|
||||||
{
|
{
|
||||||
Submarine sub = item.Submarine ?? item.GetRootContainer()?.Submarine;
|
Submarine sub = item.Submarine ?? item.GetRootContainer()?.Submarine;
|
||||||
|
|||||||
@@ -412,16 +412,16 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static Character GetCharacterForQuickAssignment(Order order, Character controlledCharacter, IEnumerable<Character> characters, bool includeSelf = false)
|
public static Character GetCharacterForQuickAssignment(Order order, Character controlledCharacter, IEnumerable<Character> characters, bool includeSelf = false)
|
||||||
{
|
{
|
||||||
var controllingCharacter = controlledCharacter != null;
|
bool isControlledCharacterNull = controlledCharacter == null;
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
if (!controllingCharacter) { return null; }
|
if (isControlledCharacterNull) { return null; }
|
||||||
#endif
|
#endif
|
||||||
if (order.Category == OrderCategory.Operate && HumanAIController.IsItemOperatedByAnother(null, order.TargetItemComponent, out Character operatingCharacter) &&
|
if (order.Category == OrderCategory.Operate && HumanAIController.IsItemTargetedBySomeone(order.TargetItemComponent, controlledCharacter != null ? controlledCharacter.TeamID : CharacterTeamType.Team1, out Character operatingCharacter) &&
|
||||||
(!controllingCharacter || operatingCharacter.CanHearCharacter(controlledCharacter)))
|
(isControlledCharacterNull || operatingCharacter.CanHearCharacter(controlledCharacter)))
|
||||||
{
|
{
|
||||||
return operatingCharacter;
|
return operatingCharacter;
|
||||||
}
|
}
|
||||||
return GetCharactersSortedForOrder(order, characters, controlledCharacter, includeSelf).FirstOrDefault(c => !controllingCharacter || c.CanHearCharacter(controlledCharacter)) ?? controlledCharacter;
|
return GetCharactersSortedForOrder(order, characters, controlledCharacter, includeSelf).FirstOrDefault(c => isControlledCharacterNull || c.CanHearCharacter(controlledCharacter)) ?? controlledCharacter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<Character> GetCharactersSortedForOrder(Order order, IEnumerable<Character> characters, Character controlledCharacter, bool includeSelf, IEnumerable<Character> extraCharacters = null)
|
public static IEnumerable<Character> GetCharactersSortedForOrder(Order order, IEnumerable<Character> characters, Character controlledCharacter, bool includeSelf, IEnumerable<Character> extraCharacters = null)
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ namespace Barotrauma
|
|||||||
if (Level.Loaded.StartOutpost.DockedTo.Any())
|
if (Level.Loaded.StartOutpost.DockedTo.Any())
|
||||||
{
|
{
|
||||||
var dockedSub = Level.Loaded.StartOutpost.DockedTo.FirstOrDefault();
|
var dockedSub = Level.Loaded.StartOutpost.DockedTo.FirstOrDefault();
|
||||||
if (dockedSub == GameMain.NetworkMember?.RespawnManager?.RespawnShuttle) { return null; }
|
if (dockedSub == GameMain.NetworkMember?.RespawnManager?.RespawnShuttle || dockedSub.TeamID != leavingPlayers.FirstOrDefault()?.TeamID) { return null; }
|
||||||
return dockedSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : dockedSub;
|
return dockedSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : dockedSub;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,7 +522,7 @@ namespace Barotrauma
|
|||||||
if (Level.Loaded.EndOutpost.DockedTo.Any())
|
if (Level.Loaded.EndOutpost.DockedTo.Any())
|
||||||
{
|
{
|
||||||
var dockedSub = Level.Loaded.EndOutpost.DockedTo.FirstOrDefault();
|
var dockedSub = Level.Loaded.EndOutpost.DockedTo.FirstOrDefault();
|
||||||
if (dockedSub == GameMain.NetworkMember?.RespawnManager?.RespawnShuttle) { return null; }
|
if (dockedSub == GameMain.NetworkMember?.RespawnManager?.RespawnShuttle || dockedSub.TeamID != leavingPlayers.FirstOrDefault()?.TeamID) { return null; }
|
||||||
return dockedSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : dockedSub;
|
return dockedSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : dockedSub;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -549,7 +549,10 @@ namespace Barotrauma
|
|||||||
if (port.IsHorizontal || port.Docked) { continue; }
|
if (port.IsHorizontal || port.Docked) { continue; }
|
||||||
if (port.Item.Submarine == level.StartOutpost)
|
if (port.Item.Submarine == level.StartOutpost)
|
||||||
{
|
{
|
||||||
outPostPort = port;
|
if (port.DockingTarget == null)
|
||||||
|
{
|
||||||
|
outPostPort = port;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (port.Item.Submarine != Submarine) { continue; }
|
if (port.Item.Submarine != Submarine) { continue; }
|
||||||
|
|||||||
@@ -323,7 +323,11 @@ namespace Barotrauma
|
|||||||
Campaign.Money -= price;
|
Campaign.Money -= price;
|
||||||
|
|
||||||
itemToRemove.AvailableSwaps.Add(itemToRemove.Prefab);
|
itemToRemove.AvailableSwaps.Add(itemToRemove.Prefab);
|
||||||
if (itemToInstall != null) { itemToRemove.AvailableSwaps.Add(itemToInstall); }
|
if (itemToInstall != null && !itemToRemove.AvailableSwaps.Contains(itemToInstall))
|
||||||
|
{
|
||||||
|
itemToRemove.PurchasedNewSwap = true;
|
||||||
|
itemToRemove.AvailableSwaps.Add(itemToInstall);
|
||||||
|
}
|
||||||
|
|
||||||
if (itemToRemove.Prefab != itemToInstall && itemToInstall != null)
|
if (itemToRemove.Prefab != itemToInstall && itemToInstall != null)
|
||||||
{
|
{
|
||||||
@@ -424,7 +428,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
List<PurchasedUpgrade> pendingUpgrades = PendingUpgrades;
|
List<PurchasedUpgrade> pendingUpgrades = PendingUpgrades;
|
||||||
|
|
||||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
|
if (Level.Loaded is { Type: LevelData.LevelType.Outpost })
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GameMain.NetworkMember is { IsClient: true })
|
||||||
{
|
{
|
||||||
if (loadedUpgrades != null)
|
if (loadedUpgrades != null)
|
||||||
{
|
{
|
||||||
@@ -438,7 +447,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
int newLevel = BuyUpgrade(prefab, category, Submarine.MainSub, level);
|
int newLevel = BuyUpgrade(prefab, category, Submarine.MainSub, level);
|
||||||
DebugConsole.Log($" - {category.Identifier}.{prefab.Identifier} lvl. {level}, new: ({newLevel})");
|
DebugConsole.Log($" - {category.Identifier}.{prefab.Identifier} lvl. {level}, new: ({newLevel})");
|
||||||
SetUpgradeLevel(prefab, category, Math.Clamp(level, 0, prefab.MaxLevel));
|
SetUpgradeLevel(prefab, category, Math.Clamp(GetRealUpgradeLevel(prefab, category) + level, 0, prefab.MaxLevel));
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingUpgrades.Clear();
|
PendingUpgrades.Clear();
|
||||||
@@ -703,7 +712,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void LoadPendingUpgrades(XElement? element, bool isSingleplayer = true)
|
private void LoadPendingUpgrades(XElement? element, bool isSingleplayer = true)
|
||||||
{
|
{
|
||||||
if (element == null || !element.HasElements) { return; }
|
if (!(element is { HasElements: true })) { return; }
|
||||||
|
|
||||||
List<PurchasedUpgrade> pendingUpgrades = new List<PurchasedUpgrade>();
|
List<PurchasedUpgrade> pendingUpgrades = new List<PurchasedUpgrade>();
|
||||||
|
|
||||||
|
|||||||
@@ -538,16 +538,18 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
if (hull.Submarine != subs[i]) continue;
|
if (hull.Submarine != subs[i]) { continue; }
|
||||||
if (hull.WorldRect.Y < hullRects[i].Y - hullRects[i].Height) continue;
|
if (hull.WorldRect.Y - 5 < hullRects[i].Y - hullRects[i].Height) { continue; }
|
||||||
if (hull.WorldRect.Y - hull.WorldRect.Height > hullRects[i].Y) continue;
|
if (hull.WorldRect.Y - hull.WorldRect.Height + 5 > hullRects[i].Y) { continue; }
|
||||||
|
|
||||||
if (i == 0) //left hull
|
if (i == 0) //left hull
|
||||||
{
|
{
|
||||||
|
if (hull.WorldPosition.X > hullRects[0].Center.X) { continue; }
|
||||||
leftSubRightSide = Math.Max(hull.WorldRect.Right, leftSubRightSide);
|
leftSubRightSide = Math.Max(hull.WorldRect.Right, leftSubRightSide);
|
||||||
}
|
}
|
||||||
else //upper hull
|
else //upper hull
|
||||||
{
|
{
|
||||||
|
if (hull.WorldPosition.X < hullRects[1].Center.X) { continue; }
|
||||||
rightSubLeftSide = Math.Min(hull.WorldRect.X, rightSubLeftSide);
|
rightSubLeftSide = Math.Min(hull.WorldRect.X, rightSubLeftSide);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -591,8 +593,11 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int expand = 5;
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
|
hullRects[i].X -= expand;
|
||||||
|
hullRects[i].Width += expand * 2;
|
||||||
hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
|
hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
|
||||||
hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]);
|
hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]);
|
||||||
hulls[i].AddToGrid(subs[i]);
|
hulls[i].AddToGrid(subs[i]);
|
||||||
@@ -636,16 +641,18 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
if (hull.Submarine != subs[i]) continue;
|
if (hull.Submarine != subs[i]) { continue; }
|
||||||
if (hull.WorldRect.Right < hullRects[i].X) continue;
|
if (hull.WorldRect.Right - 5 < hullRects[i].X) { continue; }
|
||||||
if (hull.WorldRect.X > hullRects[i].Right) continue;
|
if (hull.WorldRect.X + 5 > hullRects[i].Right) { continue; }
|
||||||
|
|
||||||
if (i == 0) //lower hull
|
if (i == 0) //lower hull
|
||||||
{
|
{
|
||||||
|
if (hull.WorldPosition.Y > hullRects[i].Y - hullRects[i].Height / 2) { continue; }
|
||||||
lowerSubTop = Math.Max(hull.WorldRect.Y, lowerSubTop);
|
lowerSubTop = Math.Max(hull.WorldRect.Y, lowerSubTop);
|
||||||
}
|
}
|
||||||
else //upper hull
|
else //upper hull
|
||||||
{
|
{
|
||||||
|
if (hull.WorldPosition.Y < hullRects[i].Y - hullRects[i].Height / 2) { continue; }
|
||||||
upperSubBottom = Math.Min(hull.WorldRect.Y - hull.WorldRect.Height, upperSubBottom);
|
upperSubBottom = Math.Min(hull.WorldRect.Y - hull.WorldRect.Height, upperSubBottom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -705,8 +712,11 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int expand = 5;
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
|
hullRects[i].Y += expand;
|
||||||
|
hullRects[i].Height += expand * 2;
|
||||||
hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
|
hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
|
||||||
hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]);
|
hulls[i] = new Hull(MapEntityPrefab.Find(null, "hull"), hullRects[i], subs[i]);
|
||||||
hulls[i].AddToGrid(subs[i]);
|
hulls[i].AddToGrid(subs[i]);
|
||||||
|
|||||||
@@ -663,7 +663,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Item.GetConnectedComponents<Controller>(true).Any(b => b.HasAccess(character));
|
return base.HasAccess(character) && Item.GetConnectedComponents<Controller>(true).Any(b => b.HasAccess(character));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ namespace Barotrauma.Items.Components
|
|||||||
item.IsShootable = true;
|
item.IsShootable = true;
|
||||||
// TODO: should define this in xml if we have ranged weapons that don't require aim to use
|
// TODO: should define this in xml if we have ranged weapons that don't require aim to use
|
||||||
item.RequireAimToUse = true;
|
item.RequireAimToUse = true;
|
||||||
|
characterUsable = true;
|
||||||
InitProjSpecific(element);
|
InitProjSpecific(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -660,7 +660,7 @@ namespace Barotrauma.Items.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool HasAccess(Character character)
|
public virtual bool HasAccess(Character character)
|
||||||
{
|
{
|
||||||
if (item.IgnoreByAI) { return false; }
|
if (character.IsBot && item.IgnoreByAI(character)) { return false; }
|
||||||
if (!item.IsInteractable(character)) { return false; }
|
if (!item.IsInteractable(character)) { return false; }
|
||||||
if (requiredItems.None()) { return true; }
|
if (requiredItems.None()) { return true; }
|
||||||
if (character.Inventory != null)
|
if (character.Inventory != null)
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool alwaysContainedItemsSpawned;
|
||||||
|
|
||||||
public ItemInventory Inventory;
|
public ItemInventory Inventory;
|
||||||
|
|
||||||
private readonly List<ActiveContainedItem> activeContainedItems = new List<ActiveContainedItem>();
|
private readonly List<ActiveContainedItem> activeContainedItems = new List<ActiveContainedItem>();
|
||||||
@@ -208,6 +210,11 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public override void Update(float deltaTime, Camera cam)
|
public override void Update(float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
|
if (!string.IsNullOrEmpty(SpawnWithId) && !alwaysContainedItemsSpawned)
|
||||||
|
{
|
||||||
|
SpawnAlwaysContainedItems();
|
||||||
|
}
|
||||||
|
|
||||||
if (item.ParentInventory is CharacterInventory)
|
if (item.ParentInventory is CharacterInventory)
|
||||||
{
|
{
|
||||||
item.SetContainedItemPositions();
|
item.SetContainedItemPositions();
|
||||||
@@ -419,10 +426,12 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
var spawnedItem = new Item(prefab, Vector2.Zero, null);
|
var spawnedItem = new Item(prefab, Vector2.Zero, null);
|
||||||
Inventory.TryPutItem(spawnedItem, null, spawnedItem.AllowedSlots, createNetworkEvent: false);
|
Inventory.TryPutItem(spawnedItem, null, spawnedItem.AllowedSlots, createNetworkEvent: false);
|
||||||
|
alwaysContainedItemsSpawned = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Entity.Spawner?.AddToSpawnQueue(prefab, Inventory, spawnIfInventoryFull: false);
|
IsActive = true;
|
||||||
|
Entity.Spawner?.AddToSpawnQueue(prefab, Inventory, spawnIfInventoryFull: false, onSpawned: (Item item) => { alwaysContainedItemsSpawned = true; });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -326,19 +326,24 @@ namespace Barotrauma.Items.Components
|
|||||||
tolerance = MathHelper.Lerp(5.0f, 20.0f, degreeOfSuccess);
|
tolerance = MathHelper.Lerp(5.0f, 20.0f, degreeOfSuccess);
|
||||||
allowedTurbineOutput = new Vector2(correctTurbineOutput - tolerance, correctTurbineOutput + tolerance);
|
allowedTurbineOutput = new Vector2(correctTurbineOutput - tolerance, correctTurbineOutput + tolerance);
|
||||||
|
|
||||||
|
DebugConsole.Log($"Degree of success: {degreeOfSuccess}");
|
||||||
|
DebugConsole.Log($"Current load: {currentLoad}");
|
||||||
|
DebugConsole.Log($"Max power output: {MaxPowerOutput}");
|
||||||
|
DebugConsole.Log($"Available fuel: {AvailableFuel}");
|
||||||
|
|
||||||
float desiredTurbineOutput = MathHelper.Clamp(correctTurbineOutput, 0.0f, 100.0f);
|
float desiredTurbineOutput = MathHelper.Clamp(correctTurbineOutput, 0.0f, 100.0f);
|
||||||
DebugConsole.Log($"Turbine output reset: {targetTurbineOutput}, {turbineOutput} -> {desiredTurbineOutput}");
|
DebugConsole.Log($"Turbine output reset: {targetTurbineOutput}, {turbineOutput} -> {desiredTurbineOutput}");
|
||||||
targetTurbineOutput = desiredTurbineOutput;
|
targetTurbineOutput = desiredTurbineOutput;
|
||||||
turbineOutput = desiredTurbineOutput;
|
turbineOutput = desiredTurbineOutput;
|
||||||
|
|
||||||
float desiredFissionRate = (optimalFissionRate.X + optimalFissionRate.Y) / 2.0f;
|
|
||||||
DebugConsole.Log($"Fission rate reset: {targetFissionRate}, {fissionRate} -> {desiredFissionRate}");
|
|
||||||
targetFissionRate = desiredFissionRate;
|
|
||||||
fissionRate = desiredFissionRate;
|
|
||||||
|
|
||||||
float desiredTemperature = (optimalTemperature.X + optimalTemperature.Y) / 2.0f;
|
float desiredTemperature = (optimalTemperature.X + optimalTemperature.Y) / 2.0f;
|
||||||
DebugConsole.Log($"Temperature reset: {temperature} -> {desiredTemperature}");
|
DebugConsole.Log($"Temperature reset: {temperature} -> {desiredTemperature}");
|
||||||
temperature = desiredTemperature;
|
temperature = desiredTemperature;
|
||||||
|
|
||||||
|
float desiredFissionRate = GetFissionRateForTargetTemperatureAndTurbineOutput(desiredTemperature, desiredTurbineOutput);
|
||||||
|
DebugConsole.Log($"Fission rate reset: {targetFissionRate}, {fissionRate} -> {desiredFissionRate}");
|
||||||
|
targetFissionRate = desiredFissionRate;
|
||||||
|
fissionRate = desiredFissionRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadQueue.Enqueue(currentLoad);
|
loadQueue.Enqueue(currentLoad);
|
||||||
@@ -420,6 +425,12 @@ namespace Barotrauma.Items.Components
|
|||||||
return fissionRate * (prevAvailableFuel / 100.0f) * 2.0f;
|
return fissionRate * (prevAvailableFuel / 100.0f) * 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float GetFissionRateForTargetTemperatureAndTurbineOutput(float temperature, float turbineOutput)
|
||||||
|
{
|
||||||
|
if (MathUtils.NearlyEqual(AvailableFuel, 0f)) { return 0f; }
|
||||||
|
return (temperature + turbineOutput) / (AvailableFuel / 100f) / 2f;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Do we need more fuel to generate enough power to match the current load.
|
/// Do we need more fuel to generate enough power to match the current load.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private readonly Queue<Impact> impactQueue = new Queue<Impact>();
|
private readonly Queue<Impact> impactQueue = new Queue<Impact>();
|
||||||
|
|
||||||
|
private bool removePending;
|
||||||
|
|
||||||
//continuous collision detection is used while the projectile is moving faster than this
|
//continuous collision detection is used while the projectile is moving faster than this
|
||||||
const float ContinuousCollisionThreshold = 5.0f;
|
const float ContinuousCollisionThreshold = 5.0f;
|
||||||
|
|
||||||
@@ -274,10 +276,9 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
if (character != null && !characterUsable) { return false; }
|
if (character != null && !characterUsable) { return false; }
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < HitScanCount; i++)
|
for (int i = 0; i < HitScanCount; i++)
|
||||||
{
|
{
|
||||||
float launchAngle = 0f;
|
float launchAngle;
|
||||||
|
|
||||||
if (StaticSpread)
|
if (StaticSpread)
|
||||||
{
|
{
|
||||||
@@ -305,6 +306,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
item.body.SetTransform(item.body.SimPosition, launchAngle);
|
||||||
float modifiedLaunchImpulse = LaunchImpulse * (1 + Rand.Range(-ImpulseSpread, ImpulseSpread));
|
float modifiedLaunchImpulse = LaunchImpulse * (1 + Rand.Range(-ImpulseSpread, ImpulseSpread));
|
||||||
DoLaunch(launchDir * modifiedLaunchImpulse * item.body.Mass);
|
DoLaunch(launchDir * modifiedLaunchImpulse * item.body.Mass);
|
||||||
}
|
}
|
||||||
@@ -562,14 +564,17 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public override void Update(float deltaTime, Camera cam)
|
public override void Update(float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
|
||||||
|
|
||||||
while (impactQueue.Count > 0)
|
while (impactQueue.Count > 0)
|
||||||
{
|
{
|
||||||
var impact = impactQueue.Dequeue();
|
var impact = impactQueue.Dequeue();
|
||||||
HandleProjectileCollision(impact.Fixture, impact.Normal, impact.LinearVelocity);
|
HandleProjectileCollision(impact.Fixture, impact.Normal, impact.LinearVelocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!removePending)
|
||||||
|
{
|
||||||
|
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||||
|
}
|
||||||
|
|
||||||
if (item.body != null && item.body.FarseerBody.IsBullet)
|
if (item.body != null && item.body.FarseerBody.IsBullet)
|
||||||
{
|
{
|
||||||
if (item.body.LinearVelocity.LengthSquared() < ContinuousCollisionThreshold * ContinuousCollisionThreshold)
|
if (item.body.LinearVelocity.LengthSquared() < ContinuousCollisionThreshold * ContinuousCollisionThreshold)
|
||||||
@@ -668,6 +673,10 @@ namespace Barotrauma.Items.Components
|
|||||||
hits.Add(target.Body);
|
hits.Add(target.Body);
|
||||||
impactQueue.Enqueue(new Impact(target, contact.Manifold.LocalNormal, item.body.LinearVelocity));
|
impactQueue.Enqueue(new Impact(target, contact.Manifold.LocalNormal, item.body.LinearVelocity));
|
||||||
IsActive = true;
|
IsActive = true;
|
||||||
|
if (RemoveOnHit)
|
||||||
|
{
|
||||||
|
item.body.FarseerBody.ResetDynamics();
|
||||||
|
}
|
||||||
if (hits.Count() >= MaxTargetsToHit || target.Body.UserData is VoronoiCell)
|
if (hits.Count() >= MaxTargetsToHit || target.Body.UserData is VoronoiCell)
|
||||||
{
|
{
|
||||||
Deactivate();
|
Deactivate();
|
||||||
@@ -867,15 +876,10 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (RemoveOnHit)
|
if (RemoveOnHit)
|
||||||
{
|
{
|
||||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
|
removePending = true;
|
||||||
{
|
item.HiddenInGame = true;
|
||||||
//clients aren't allowed to remove items by themselves, so lets hide the projectile until the server tells us to remove it
|
item.body.FarseerBody.Enabled = false;
|
||||||
item.HiddenInGame = Hitscan;
|
Entity.Spawner?.AddToRemoveQueue(item);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Entity.Spawner?.AddToRemoveQueue(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string[] labels;
|
private string[] labels;
|
||||||
[Serialize("", true, description: "The texts displayed on the buttons/tickboxes, separated by commas.")]
|
[Serialize("", true, description: "The texts displayed on the buttons/tickboxes, separated by commas.", alwaysUseInstanceValues: true)]
|
||||||
public string Labels
|
public string Labels
|
||||||
{
|
{
|
||||||
get { return string.Join(",", labels); }
|
get { return string.Join(",", labels); }
|
||||||
@@ -111,7 +111,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string[] signals;
|
private string[] signals;
|
||||||
[Serialize("", true, description: "The signals sent when the buttons are pressed or the tickboxes checked, separated by commas.")]
|
[Serialize("", true, description: "The signals sent when the buttons are pressed or the tickboxes checked, separated by commas.", alwaysUseInstanceValues: true)]
|
||||||
public string Signals
|
public string Signals
|
||||||
{
|
{
|
||||||
//use semicolon as a separator because comma may be needed in the signals (for color or vector values for example)
|
//use semicolon as a separator because comma may be needed in the signals (for color or vector values for example)
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ namespace Barotrauma.Items.Components
|
|||||||
private bool castShadows;
|
private bool castShadows;
|
||||||
private bool drawBehindSubs;
|
private bool drawBehindSubs;
|
||||||
|
|
||||||
|
|
||||||
private double lastToggleSignalTime;
|
private double lastToggleSignalTime;
|
||||||
|
|
||||||
|
private string prevColorSignal;
|
||||||
|
|
||||||
public PhysicsBody ParentBody;
|
public PhysicsBody ParentBody;
|
||||||
|
|
||||||
private Turret turret;
|
private Turret turret;
|
||||||
@@ -326,7 +327,11 @@ namespace Barotrauma.Items.Components
|
|||||||
IsOn = signal.value != "0";
|
IsOn = signal.value != "0";
|
||||||
break;
|
break;
|
||||||
case "set_color":
|
case "set_color":
|
||||||
LightColor = XMLExtensions.ParseColor(signal.value, false);
|
if (signal.value != prevColorSignal)
|
||||||
|
{
|
||||||
|
LightColor = XMLExtensions.ParseColor(signal.value, false);
|
||||||
|
prevColorSignal = signal.value;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ namespace Barotrauma.Items.Components
|
|||||||
if (Math.Abs(item.body.LinearVelocity.X) > MinimumVelocity || Math.Abs(item.body.LinearVelocity.Y) > MinimumVelocity)
|
if (Math.Abs(item.body.LinearVelocity.X) > MinimumVelocity || Math.Abs(item.body.LinearVelocity.Y) > MinimumVelocity)
|
||||||
{
|
{
|
||||||
MotionDetected = true;
|
MotionDetected = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,64 +174,90 @@ namespace Barotrauma.Items.Components
|
|||||||
float broadRangeY = Math.Max(rangeY * 2, 500);
|
float broadRangeY = Math.Max(rangeY * 2, 500);
|
||||||
|
|
||||||
if (item.CurrentHull == null && item.Submarine != null && Level.Loaded != null &&
|
if (item.CurrentHull == null && item.Submarine != null && Level.Loaded != null &&
|
||||||
(Target == TargetType.Wall || Target == TargetType.Any) &&
|
(Target == TargetType.Wall || Target == TargetType.Any))
|
||||||
(Math.Abs(item.Submarine.Velocity.X) > MinimumVelocity || Math.Abs(item.Submarine.Velocity.Y) > MinimumVelocity))
|
|
||||||
{
|
{
|
||||||
var cells = Level.Loaded.GetCells(item.WorldPosition, 1);
|
if (Math.Abs(item.Submarine.Velocity.X) > MinimumVelocity || Math.Abs(item.Submarine.Velocity.Y) > MinimumVelocity)
|
||||||
foreach (var cell in cells)
|
|
||||||
{
|
{
|
||||||
if (cell.IsPointInside(item.WorldPosition))
|
var cells = Level.Loaded.GetCells(item.WorldPosition, 1);
|
||||||
|
foreach (var cell in cells)
|
||||||
{
|
{
|
||||||
MotionDetected = true;
|
if (cell.IsPointInside(item.WorldPosition))
|
||||||
return;
|
|
||||||
}
|
|
||||||
foreach (var edge in cell.Edges)
|
|
||||||
{
|
|
||||||
var closestPoint = MathUtils.GetClosestPointOnLineSegment(edge.Point1 + cell.Translation, edge.Point2 + cell.Translation, item.WorldPosition);
|
|
||||||
if (Math.Abs(closestPoint.X - item.WorldPosition.X) < rangeX && Math.Abs(closestPoint.Y - item.WorldPosition.Y) < rangeY)
|
|
||||||
{
|
{
|
||||||
MotionDetected = true;
|
MotionDetected = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
foreach (var edge in cell.Edges)
|
||||||
|
{
|
||||||
|
Vector2 e1 = edge.Point1 + cell.Translation;
|
||||||
|
Vector2 e2 = edge.Point2 + cell.Translation;
|
||||||
|
if (MathUtils.LinesIntersect(e1, e2, new Vector2(detectRect.X, detectRect.Y), new Vector2(detectRect.Right, detectRect.Y)) ||
|
||||||
|
MathUtils.LinesIntersect(e1, e2, new Vector2(detectRect.X, detectRect.Bottom), new Vector2(detectRect.Right, detectRect.Bottom)) ||
|
||||||
|
MathUtils.LinesIntersect(e1, e2, new Vector2(detectRect.X, detectRect.Y), new Vector2(detectRect.X, detectRect.Bottom)) ||
|
||||||
|
MathUtils.LinesIntersect(e1, e2, new Vector2(detectRect.Right, detectRect.Y), new Vector2(detectRect.Right, detectRect.Bottom)))
|
||||||
|
{
|
||||||
|
MotionDetected = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (Submarine sub in Submarine.Loaded)
|
||||||
|
{
|
||||||
|
if (sub == item.Submarine) { continue; }
|
||||||
|
|
||||||
|
Vector2 relativeVelocity = item.Submarine.Velocity - sub.Velocity;
|
||||||
|
if (Math.Abs(relativeVelocity.X) < MinimumVelocity && Math.Abs(relativeVelocity.Y) < MinimumVelocity) { continue; }
|
||||||
|
|
||||||
|
Rectangle worldBorders = new Rectangle(
|
||||||
|
sub.Borders.X + (int)sub.WorldPosition.X,
|
||||||
|
sub.Borders.Y + (int)sub.WorldPosition.Y - sub.Borders.Height,
|
||||||
|
sub.Borders.Width,
|
||||||
|
sub.Borders.Height);
|
||||||
|
|
||||||
|
if (worldBorders.Intersects(detectRect))
|
||||||
|
{
|
||||||
|
MotionDetected = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Character c in Character.CharacterList)
|
if (Target != TargetType.Wall)
|
||||||
{
|
{
|
||||||
if (IgnoreDead && c.IsDead) { continue; }
|
foreach (Character c in Character.CharacterList)
|
||||||
|
|
||||||
//ignore characters that have spawned a second or less ago
|
|
||||||
//makes it possible to detect when a spawned character moves without triggering the detector immediately as the ragdoll spawns and drops to the ground
|
|
||||||
if (c.SpawnTime > Timing.TotalTime - 1.0) { continue; }
|
|
||||||
|
|
||||||
switch (Target)
|
|
||||||
{
|
{
|
||||||
case TargetType.Human:
|
if (IgnoreDead && c.IsDead) { continue; }
|
||||||
if (!c.IsHuman) { continue; }
|
|
||||||
break;
|
|
||||||
case TargetType.Monster:
|
|
||||||
if (c.IsHuman || c.IsPet) { continue; }
|
|
||||||
break;
|
|
||||||
case TargetType.Wall:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//do a rough check based on the position of the character's collider first
|
//ignore characters that have spawned a second or less ago
|
||||||
//before the more accurate limb-based check
|
//makes it possible to detect when a spawned character moves without triggering the detector immediately as the ragdoll spawns and drops to the ground
|
||||||
if (Math.Abs(c.WorldPosition.X - detectPos.X) > broadRangeX || Math.Abs(c.WorldPosition.Y - detectPos.Y) > broadRangeY)
|
if (c.SpawnTime > Timing.TotalTime - 1.0) { continue; }
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Limb limb in c.AnimController.Limbs)
|
switch (Target)
|
||||||
{
|
|
||||||
if (limb.IsSevered) { continue; }
|
|
||||||
if (limb.LinearVelocity.LengthSquared() <= MinimumVelocity * MinimumVelocity) { continue; }
|
|
||||||
if (MathUtils.CircleIntersectsRectangle(limb.WorldPosition, ConvertUnits.ToDisplayUnits(limb.body.GetMaxExtent()), detectRect))
|
|
||||||
{
|
{
|
||||||
MotionDetected = true;
|
case TargetType.Human:
|
||||||
return;
|
if (!c.IsHuman) { continue; }
|
||||||
|
break;
|
||||||
|
case TargetType.Monster:
|
||||||
|
if (c.IsHuman || c.IsPet) { continue; }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//do a rough check based on the position of the character's collider first
|
||||||
|
//before the more accurate limb-based check
|
||||||
|
if (Math.Abs(c.WorldPosition.X - detectPos.X) > broadRangeX || Math.Abs(c.WorldPosition.Y - detectPos.Y) > broadRangeY)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Limb limb in c.AnimController.Limbs)
|
||||||
|
{
|
||||||
|
if (limb.IsSevered) { continue; }
|
||||||
|
if (limb.LinearVelocity.LengthSquared() <= MinimumVelocity * MinimumVelocity) { continue; }
|
||||||
|
if (MathUtils.CircleIntersectsRectangle(limb.WorldPosition, ConvertUnits.ToDisplayUnits(limb.body.GetMaxExtent()), detectRect))
|
||||||
|
{
|
||||||
|
MotionDetected = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ namespace Barotrauma.Items.Components
|
|||||||
partial class Turret : Powered, IDrawableComponent, IServerSerializable
|
partial class Turret : Powered, IDrawableComponent, IServerSerializable
|
||||||
{
|
{
|
||||||
private Sprite barrelSprite, railSprite;
|
private Sprite barrelSprite, railSprite;
|
||||||
private List<Tuple<Sprite, Vector2>> chargeSprites = new List<Tuple<Sprite, Vector2>>();
|
private readonly List<(Sprite sprite, Vector2 position)> chargeSprites = new List<(Sprite sprite, Vector2 position)>();
|
||||||
private List<Sprite> spinningBarrelSprites = new List<Sprite>();
|
private readonly List<Sprite> spinningBarrelSprites = new List<Sprite>();
|
||||||
|
|
||||||
private Vector2 barrelPos;
|
private Vector2 barrelPos;
|
||||||
private Vector2 transformedBarrelPos;
|
private Vector2 transformedBarrelPos;
|
||||||
@@ -290,7 +290,7 @@ namespace Barotrauma.Items.Components
|
|||||||
railSprite = new Sprite(subElement);
|
railSprite = new Sprite(subElement);
|
||||||
break;
|
break;
|
||||||
case "chargesprite":
|
case "chargesprite":
|
||||||
chargeSprites.Add(new Tuple<Sprite, Vector2>(new Sprite(subElement), subElement.GetAttributeVector2("chargetarget", Vector2.Zero)));
|
chargeSprites.Add((new Sprite(subElement), subElement.GetAttributeVector2("chargetarget", Vector2.Zero)));
|
||||||
break;
|
break;
|
||||||
case "spinningbarrelsprite":
|
case "spinningbarrelsprite":
|
||||||
int spriteCount = subElement.GetAttributeInt("spriteamount", 1);
|
int spriteCount = subElement.GetAttributeInt("spriteamount", 1);
|
||||||
@@ -1283,7 +1283,6 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private Vector2 GetRelativeFiringPosition(bool useOffset = true)
|
private Vector2 GetRelativeFiringPosition(bool useOffset = true)
|
||||||
{
|
{
|
||||||
// i don't feel great about this method, should be evaluated again
|
|
||||||
Vector2 transformedFiringOffset = Vector2.Zero;
|
Vector2 transformedFiringOffset = Vector2.Zero;
|
||||||
if (useOffset)
|
if (useOffset)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
class Wearable : Pickable, IServerSerializable
|
partial class Wearable : Pickable, IServerSerializable
|
||||||
{
|
{
|
||||||
private readonly XElement[] wearableElements;
|
private readonly XElement[] wearableElements;
|
||||||
private readonly WearableSprite[] wearableSprites;
|
private readonly WearableSprite[] wearableSprites;
|
||||||
@@ -210,6 +210,7 @@ namespace Barotrauma.Items.Components
|
|||||||
private readonly Limb[] limb;
|
private readonly Limb[] limb;
|
||||||
|
|
||||||
private readonly List<DamageModifier> damageModifiers;
|
private readonly List<DamageModifier> damageModifiers;
|
||||||
|
public readonly Dictionary<string, float> SkillModifiers;
|
||||||
|
|
||||||
public IEnumerable<DamageModifier> DamageModifiers
|
public IEnumerable<DamageModifier> DamageModifiers
|
||||||
{
|
{
|
||||||
@@ -265,6 +266,7 @@ namespace Barotrauma.Items.Components
|
|||||||
this.item = item;
|
this.item = item;
|
||||||
|
|
||||||
damageModifiers = new List<DamageModifier>();
|
damageModifiers = new List<DamageModifier>();
|
||||||
|
SkillModifiers = new Dictionary<string, float>();
|
||||||
|
|
||||||
int spriteCount = element.Elements().Count(x => x.Name.ToString() == "sprite");
|
int spriteCount = element.Elements().Count(x => x.Name.ToString() == "sprite");
|
||||||
Variants = element.GetAttributeInt("variants", 0);
|
Variants = element.GetAttributeInt("variants", 0);
|
||||||
@@ -308,6 +310,18 @@ namespace Barotrauma.Items.Components
|
|||||||
case "damagemodifier":
|
case "damagemodifier":
|
||||||
damageModifiers.Add(new DamageModifier(subElement, item.Name + ", Wearable"));
|
damageModifiers.Add(new DamageModifier(subElement, item.Name + ", Wearable"));
|
||||||
break;
|
break;
|
||||||
|
case "skillmodifier":
|
||||||
|
string skillIdentifier = subElement.GetAttributeString("skillidentifier", string.Empty);
|
||||||
|
float skillValue = subElement.GetAttributeFloat("skillvalue", 0f);
|
||||||
|
if (SkillModifiers.ContainsKey(skillIdentifier))
|
||||||
|
{
|
||||||
|
SkillModifiers[skillIdentifier] += skillValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SkillModifiers.TryAdd(skillIdentifier, skillValue);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,7 +338,7 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
var wearableSprite = wearableSprites[i];
|
var wearableSprite = wearableSprites[i];
|
||||||
if (!wearableSprite.IsInitialized) { wearableSprite.Init(picker.Info?.Gender ?? Gender.None); }
|
if (!wearableSprite.IsInitialized) { wearableSprite.Init(picker.Info?.Gender ?? Gender.None); }
|
||||||
if (picker.Info?.Gender != Gender.None && (wearableSprite.Gender != Gender.None))
|
if (picker.Info != null && picker.Info?.Gender != Gender.None && (wearableSprite.Gender != Gender.None))
|
||||||
{
|
{
|
||||||
// If the item is gender specific (it has a different textures for male and female), we have to change the gender here so that the texture is updated.
|
// If the item is gender specific (it has a different textures for male and female), we have to change the gender here so that the texture is updated.
|
||||||
wearableSprite.Gender = picker.Info.Gender;
|
wearableSprite.Gender = picker.Info.Gender;
|
||||||
@@ -386,6 +400,7 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
if (character == null || character.Removed) { return; }
|
if (character == null || character.Removed) { return; }
|
||||||
if (picker == null) { return; }
|
if (picker == null) { return; }
|
||||||
|
|
||||||
for (int i = 0; i < wearableSprites.Length; i++)
|
for (int i = 0; i < wearableSprites.Length; i++)
|
||||||
{
|
{
|
||||||
Limb equipLimb = character.AnimController.GetLimb(limbType[i]);
|
Limb equipLimb = character.AnimController.GetLimb(limbType[i]);
|
||||||
|
|||||||
@@ -204,6 +204,13 @@ namespace Barotrauma
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serialize(false, true)]
|
||||||
|
public bool PurchasedNewSwap
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks both <see cref="NonInteractable"/> and <see cref="NonPlayerTeamInteractable"/>
|
/// Checks both <see cref="NonInteractable"/> and <see cref="NonPlayerTeamInteractable"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -705,7 +712,7 @@ namespace Barotrauma
|
|||||||
get { return allPropertyObjects; }
|
get { return allPropertyObjects; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IgnoreByAI => OrderedToBeIgnored || HasTag("ignorebyai");
|
public bool IgnoreByAI(Character character) => HasTag("ignorebyai") || OrderedToBeIgnored && character.IsOnPlayerTeam;
|
||||||
public bool OrderedToBeIgnored { get; set; }
|
public bool OrderedToBeIgnored { get; set; }
|
||||||
|
|
||||||
public Item(ItemPrefab itemPrefab, Vector2 position, Submarine submarine, ushort id = Entity.NullEntityID)
|
public Item(ItemPrefab itemPrefab, Vector2 position, Submarine submarine, ushort id = Entity.NullEntityID)
|
||||||
@@ -1280,16 +1287,16 @@ namespace Barotrauma
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Should this item or any of its containers be ignored by the AI?
|
/// Should this item or any of its containers be ignored by the AI?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsThisOrAnyContainerIgnoredByAI()
|
public bool IsThisOrAnyContainerIgnoredByAI(Character character)
|
||||||
{
|
{
|
||||||
if (IgnoreByAI) { return true; }
|
if (IgnoreByAI(character)) { return true; }
|
||||||
if (Container == null) { return false; }
|
if (Container == null) { return false; }
|
||||||
if (Container.IgnoreByAI) { return true; }
|
if (Container.IgnoreByAI(character)) { return true; }
|
||||||
var container = Container;
|
var container = Container;
|
||||||
while (container.Container != null)
|
while (container.Container != null)
|
||||||
{
|
{
|
||||||
container = container.Container;
|
container = container.Container;
|
||||||
if (container.IgnoreByAI) { return true; }
|
if (container.IgnoreByAI(character)) { return true; }
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2779,6 +2786,7 @@ namespace Barotrauma
|
|||||||
item.SpriteDepth = element.GetAttributeFloat("spritedepth", item.SpriteDepth);
|
item.SpriteDepth = element.GetAttributeFloat("spritedepth", item.SpriteDepth);
|
||||||
item.SpriteColor = element.GetAttributeColor("spritecolor", item.SpriteColor);
|
item.SpriteColor = element.GetAttributeColor("spritecolor", item.SpriteColor);
|
||||||
item.Rotation = element.GetAttributeFloat("rotation", item.Rotation);
|
item.Rotation = element.GetAttributeFloat("rotation", item.Rotation);
|
||||||
|
item.PurchasedNewSwap = element.GetAttributeBool("purchasednewswap", false);
|
||||||
|
|
||||||
float scaleRelativeToPrefab = element.GetAttributeFloat(item.scale, "scale", "Scale") / oldPrefab.Scale;
|
float scaleRelativeToPrefab = element.GetAttributeFloat(item.scale, "scale", "Scale") / oldPrefab.Scale;
|
||||||
item.Scale *= scaleRelativeToPrefab;
|
item.Scale *= scaleRelativeToPrefab;
|
||||||
@@ -2787,16 +2795,41 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Vector2 oldRelativeOrigin = (oldPrefab.SwappableItem.SwapOrigin - oldPrefab.Size / 2) * element.GetAttributeFloat(item.scale, "scale", "Scale");
|
Vector2 oldRelativeOrigin = (oldPrefab.SwappableItem.SwapOrigin - oldPrefab.Size / 2) * element.GetAttributeFloat(item.scale, "scale", "Scale");
|
||||||
oldRelativeOrigin.Y = -oldRelativeOrigin.Y;
|
oldRelativeOrigin.Y = -oldRelativeOrigin.Y;
|
||||||
oldRelativeOrigin = MathUtils.RotatePoint(oldRelativeOrigin, item.rotationRad);
|
oldRelativeOrigin = MathUtils.RotatePoint(oldRelativeOrigin, -item.rotationRad);
|
||||||
Vector2 oldOrigin = centerPos + oldRelativeOrigin;
|
Vector2 oldOrigin = centerPos + oldRelativeOrigin;
|
||||||
|
|
||||||
Vector2 relativeOrigin = (prefab.SwappableItem.SwapOrigin - prefab.Size / 2) * item.Scale;
|
Vector2 relativeOrigin = (prefab.SwappableItem.SwapOrigin - prefab.Size / 2) * item.Scale;
|
||||||
relativeOrigin.Y = -relativeOrigin.Y;
|
relativeOrigin.Y = -relativeOrigin.Y;
|
||||||
relativeOrigin = MathUtils.RotatePoint(relativeOrigin, item.rotationRad);
|
relativeOrigin = MathUtils.RotatePoint(relativeOrigin, -item.rotationRad);
|
||||||
Vector2 origin = new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2) + relativeOrigin;
|
Vector2 origin = new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2) + relativeOrigin;
|
||||||
|
|
||||||
item.rect.Location -= (origin - oldOrigin).ToPoint();
|
item.rect.Location -= (origin - oldOrigin).ToPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item.PurchasedNewSwap && !string.IsNullOrEmpty(appliedSwap.SwappableItem?.SpawnWithId))
|
||||||
|
{
|
||||||
|
var container = item.GetComponent<ItemContainer>();
|
||||||
|
if (container != null)
|
||||||
|
{
|
||||||
|
container.SpawnWithId = appliedSwap.SwappableItem.SpawnWithId;
|
||||||
|
}
|
||||||
|
/*string[] splitIdentifier = appliedSwap.SwappableItem.SpawnWithId.Split(',');
|
||||||
|
foreach (string id in splitIdentifier)
|
||||||
|
{
|
||||||
|
ItemPrefab itemToSpawn = ItemPrefab.Find(name: null, identifier: id.Trim());
|
||||||
|
if (itemToSpawn == null)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"Failed to spawn an item inside the purchased {item.Name} (could not find an item with the identifier \"{id}\").");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var spawnedItem = new Item(itemToSpawn, Vector2.Zero, null);
|
||||||
|
item.OwnInventory.TryPutItem(spawnedItem, null, spawnedItem.AllowedSlots, createNetworkEvent: false);
|
||||||
|
Spawner?.AddToSpawnQueue(itemToSpawn, item.OwnInventory, spawnIfInventoryFull: false);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
item.PurchasedNewSwap = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float condition = element.GetAttributeFloat("condition", item.MaxCondition);
|
float condition = element.GetAttributeFloat("condition", item.MaxCondition);
|
||||||
|
|||||||
@@ -210,6 +210,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public readonly string ReplacementOnUninstall;
|
public readonly string ReplacementOnUninstall;
|
||||||
|
|
||||||
|
public string SpawnWithId;
|
||||||
|
|
||||||
|
public string SwapIdentifier;
|
||||||
|
|
||||||
public readonly Vector2 SwapOrigin;
|
public readonly Vector2 SwapOrigin;
|
||||||
|
|
||||||
public List<(string requiredTag, string swapTo)> ConnectedItemsToSwap = new List<(string requiredTag, string swapTo)>();
|
public List<(string requiredTag, string swapTo)> ConnectedItemsToSwap = new List<(string requiredTag, string swapTo)>();
|
||||||
@@ -225,9 +229,11 @@ namespace Barotrauma
|
|||||||
public SwappableItem(XElement element)
|
public SwappableItem(XElement element)
|
||||||
{
|
{
|
||||||
BasePrice = Math.Max(element.GetAttributeInt("price", 0), 0);
|
BasePrice = Math.Max(element.GetAttributeInt("price", 0), 0);
|
||||||
|
SwapIdentifier = element.GetAttributeString("swapidentifier", string.Empty);
|
||||||
CanBeBought = element.GetAttributeBool("canbebought", BasePrice != 0);
|
CanBeBought = element.GetAttributeBool("canbebought", BasePrice != 0);
|
||||||
ReplacementOnUninstall = element.GetAttributeString("replacementonuninstall", "");
|
ReplacementOnUninstall = element.GetAttributeString("replacementonuninstall", "");
|
||||||
SwapOrigin = element.GetAttributeVector2("origin", Vector2.One);
|
SwapOrigin = element.GetAttributeVector2("origin", Vector2.One);
|
||||||
|
SpawnWithId = element.GetAttributeString("spawnwithid", string.Empty);
|
||||||
|
|
||||||
foreach (XElement subElement in element.Elements())
|
foreach (XElement subElement in element.Elements())
|
||||||
{
|
{
|
||||||
@@ -357,6 +363,14 @@ namespace Barotrauma
|
|||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if true then players can only highlight the item if its targeted for interaction by a campaign event
|
||||||
|
[Serialize(false, false)]
|
||||||
|
public bool RequireCampaignInteract
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
//should the camera focus on the item when selected
|
//should the camera focus on the item when selected
|
||||||
[Serialize(false, false)]
|
[Serialize(false, false)]
|
||||||
public bool FocusOnSelected
|
public bool FocusOnSelected
|
||||||
@@ -730,6 +744,9 @@ namespace Barotrauma
|
|||||||
//nameidentifier can be used to make multiple items use the same names and descriptions
|
//nameidentifier can be used to make multiple items use the same names and descriptions
|
||||||
string nameIdentifier = element.GetAttributeString("nameidentifier", "");
|
string nameIdentifier = element.GetAttributeString("nameidentifier", "");
|
||||||
|
|
||||||
|
//only used if the item doesn't have a name/description defined in the currently selected language
|
||||||
|
string fallbackNameIdentifier = element.GetAttributeString("fallbacknameidentifier", "");
|
||||||
|
|
||||||
//works the same as nameIdentifier, but just replaces the description
|
//works the same as nameIdentifier, but just replaces the description
|
||||||
string descriptionIdentifier = element.GetAttributeString("descriptionidentifier", "");
|
string descriptionIdentifier = element.GetAttributeString("descriptionidentifier", "");
|
||||||
|
|
||||||
@@ -737,11 +754,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(nameIdentifier))
|
if (string.IsNullOrEmpty(nameIdentifier))
|
||||||
{
|
{
|
||||||
name = TextManager.Get("EntityName." + identifier, true) ?? string.Empty;
|
name = TextManager.Get("EntityName." + identifier, true, "EntityName." + fallbackNameIdentifier) ?? string.Empty;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
name = TextManager.Get("EntityName." + nameIdentifier, true) ?? string.Empty;
|
name = TextManager.Get("EntityName." + nameIdentifier, true, "EntityName." + fallbackNameIdentifier) ?? string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Category.HasFlag(MapEntityCategory.Legacy))
|
else if (Category.HasFlag(MapEntityCategory.Legacy))
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
float displayRange = Attack.Range;
|
float displayRange = Attack.Range;
|
||||||
|
|
||||||
Vector2 cameraPos = Character.Controlled != null ? Character.Controlled.WorldPosition : GameMain.GameScreen.Cam.Position;
|
Vector2 cameraPos = GameMain.GameScreen.Cam.Position;
|
||||||
float cameraDist = Vector2.Distance(cameraPos, worldPosition) / 2.0f;
|
float cameraDist = Vector2.Distance(cameraPos, worldPosition) / 2.0f;
|
||||||
GameMain.GameScreen.Cam.Shake = cameraShake * Math.Max((cameraShakeRange - cameraDist) / cameraShakeRange, 0.0f);
|
GameMain.GameScreen.Cam.Shake = cameraShake * Math.Max((cameraShakeRange - cameraDist) / cameraShakeRange, 0.0f);
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
interface IIgnorable : ISpatialEntity
|
interface IIgnorable : ISpatialEntity
|
||||||
{
|
{
|
||||||
bool IgnoreByAI { get; }
|
bool IgnoreByAI(Character character);
|
||||||
bool OrderedToBeIgnored { get; set; }
|
bool OrderedToBeIgnored { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public Rectangle Bounds;
|
public Rectangle Bounds;
|
||||||
|
|
||||||
public ItemAssemblyPrefab(string filePath)
|
public ItemAssemblyPrefab(string filePath, bool allowOverwrite = false)
|
||||||
{
|
{
|
||||||
FilePath = filePath;
|
FilePath = filePath;
|
||||||
XDocument doc = XMLExtensions.TryLoadXml(filePath);
|
XDocument doc = XMLExtensions.TryLoadXml(filePath);
|
||||||
@@ -113,6 +113,10 @@ namespace Barotrauma
|
|||||||
new Rectangle(0, 0, 1, 1) :
|
new Rectangle(0, 0, 1, 1) :
|
||||||
new Rectangle(minX, minY, maxX - minX, maxY - minY);
|
new Rectangle(minX, minY, maxX - minX, maxY - minY);
|
||||||
|
|
||||||
|
if (allowOverwrite && Prefabs.ContainsKey(identifier))
|
||||||
|
{
|
||||||
|
Prefabs.Remove(Prefabs[identifier]);
|
||||||
|
}
|
||||||
Prefabs.Add(this, doc.Root.IsOverride());
|
Prefabs.Add(this, doc.Root.IsOverride());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user