From 8ef6ec90caa487de9bbe52bd0d4f3f4c43161db7 Mon Sep 17 00:00:00 2001 From: Evil Factory <36804725+evilfactory@users.noreply.github.com> Date: Wed, 27 Oct 2021 13:59:08 -0300 Subject: [PATCH] Revert "what the fuck" This reverts commit 16e90bea61530688324cb742ccb69abb14073da0. Revert "fix merge conflicts, warning: still broken" This reverts commit 1f0f411d4f3ca78476f2004e27608b983319e666. --- .../ServerSource/Characters/Character.cs | 23 +- .../ServerSource/Networking/GameServer.cs | 137 +++--- .../Data/ContentPackages/Vanilla 0.9.xml | 53 +-- .../Characters/Health/CharacterHealth.cs | 284 ++++-------- .../Items/Components/Signal/WifiComponent.cs | 1 - .../SharedSource/Items/Item.cs | 414 +++++++----------- 6 files changed, 341 insertions(+), 571 deletions(-) diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/Character.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/Character.cs index 0ae36eb12..f605e430a 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/Character.cs @@ -27,16 +27,7 @@ namespace Barotrauma GameServer.Log(GameServer.CharacterLogName(this) + " has died (Cause of death: " + causeOfDeath + ")", ServerLog.MessageType.Attack); } } - - if (HasAbilityFlag(AbilityFlags.RetainExperienceForNewCharacter)) - { - var ownerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == this); - if (ownerClient != null) - { - (GameMain.GameSession?.GameMode as MultiPlayerCampaign)?.SaveExperiencePoints(ownerClient); - } - } - GameMain.Lua.hook.Call("characterDeath", new object[] { this, causeOfDeathAffliction }); + GameMain.Lua.hook.Call("characterDeath", new object[] { this,causeOfDeathAffliction }); healthUpdateTimer = 0.0f; if (CauseOfDeath.Killer != null && CauseOfDeath.Killer.IsTraitor && CauseOfDeath.Killer != this) @@ -44,7 +35,10 @@ namespace Barotrauma var owner = GameMain.Server.ConnectedClients.Find(c => c.Character == this); if (owner != null) { - GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("KilledByTraitorNotification"), owner, ChatMessageType.ServerMessageBoxInGame); + if (!GameMain.Lua.game.overrideTraitors) + { + GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("KilledByTraitorNotification"), owner, ChatMessageType.ServerMessageBoxInGame); + } } } foreach (Client client in GameMain.Server.ConnectedClients) @@ -55,10 +49,5 @@ namespace Barotrauma } } } - - partial void OnMoneyChanged(int prevAmount, int newAmount) - { - GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateMoney }); - } } -} \ No newline at end of file +} diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index 1cef0cdb4..51f6a23ac 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -11,6 +11,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; using System.Xml.Linq; +using MoonSharp.Interpreter; namespace Barotrauma.Networking { @@ -196,13 +197,15 @@ namespace Barotrauma.Networking #endif } + GameMain.Lua.Initialize(); + TickRate = serverSettings.TickRate; Log("Server started", ServerLog.MessageType.ServerMessage); GameMain.NetLobbyScreen.Select(); GameMain.NetLobbyScreen.RandomizeSettings(); - if (!string.IsNullOrEmpty(serverSettings.SelectedSubmarine)) + if (!string.IsNullOrEmpty(serverSettings.SelectedSubmarine)) { SubmarineInfo sub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == serverSettings.SelectedSubmarine); if (sub != null) { GameMain.NetLobbyScreen.SelectedSub = sub; } @@ -309,7 +312,10 @@ namespace Barotrauma.Networking SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient); } - SendChatMessage($"ServerMessage.JoinedServer~[client]={ClientLogName(newClient)}", ChatMessageType.Server, null, changeType: PlayerConnectionChangeType.Joined); + GameMain.Lua.hook.Call("clientConnected", new object[] { newClient }); + + + SendChatMessage($"ServerMessage.JoinedServer~[client]={clName}", ChatMessageType.Server, null, changeType: PlayerConnectionChangeType.Joined); serverSettings.ServerDetailsChanged = true; if (previousPlayer != null && previousPlayer.Name != newClient.Name) @@ -536,7 +542,7 @@ namespace Barotrauma.Networking initiatedStartGame = false; } } - else if (Screen.Selected == GameMain.NetLobbyScreen && !gameStarted && !initiatedStartGame && + else if (Screen.Selected == GameMain.NetLobbyScreen && !gameStarted && !initiatedStartGame && (GameMain.NetLobbyScreen.SelectedMode != GameModePreset.MultiPlayerCampaign || GameMain.GameSession?.GameMode is MultiPlayerCampaign)) { if (serverSettings.AutoRestart) @@ -687,7 +693,7 @@ namespace Barotrauma.Networking if (Timing.TotalTime > lastPingTime + 1.0) { lastPingData ??= new byte[64]; - for (int i = 0; i < lastPingData.Length; i++) + for (int i=0;i x.Connection == inc.Sender); @@ -1322,11 +1327,11 @@ namespace Barotrauma.Networking Log("Client \"" + GameServer.ClientLogName(sender) + "\" ended the round.", ServerLog.MessageType.ServerMessage); if (mpCampaign != null && Level.IsLoadedOutpost) { - mpCampaign.SavePlayers(); + mpCampaign.SaveInventories(); GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine); SaveUtil.SaveGame(GameMain.GameSession.SavePath); } - EndGame(); + EndGame(); } } else @@ -1457,7 +1462,7 @@ namespace Barotrauma.Networking } break; case ClientPermissions.ManageCampaign: - (GameMain.GameSession.GameMode as MultiPlayerCampaign)?.ServerRead(inc, sender); + (GameMain.GameSession.GameMode as MultiPlayerCampaign)?.ServerRead(inc, sender); break; case ClientPermissions.ConsoleCommands: { @@ -1813,7 +1818,7 @@ namespace Barotrauma.Networking outmsg.Write(client.InGame); outmsg.Write(client.Permissions != ClientPermissions.None); outmsg.Write(client.Connection == OwnerConnection); - outmsg.Write(client.Connection != OwnerConnection && + outmsg.Write(client.Connection != OwnerConnection && !client.HasPermission(ClientPermissions.Ban) && !client.HasPermission(ClientPermissions.Kick) && !client.HasPermission(ClientPermissions.Unban)); //is kicking the player allowed @@ -1821,7 +1826,7 @@ namespace Barotrauma.Networking } } - private void ClientWriteLobby(Client c) + public void ClientWriteLobby(Client c) { bool isInitialUpdate = false; @@ -2193,8 +2198,8 @@ namespace Barotrauma.Networking bool isOutpost = campaign != null && campaign.NextLevel?.Type == LevelData.LevelType.Outpost; if (serverSettings.AllowRespawn && missionAllowRespawn) - { - respawnManager = new RespawnManager(this, serverSettings.UseRespawnShuttle && !isOutpost ? selectedShuttle : null); + { + respawnManager = new RespawnManager(this, serverSettings.UseRespawnShuttle && !isOutpost ? selectedShuttle : null); } if (campaign != null) { @@ -2286,7 +2291,7 @@ namespace Barotrauma.Networking } AssignBotJobs(bots, teamID); - if (campaign != null) + if (campaign != null) { foreach (CharacterInfo bot in bots) { @@ -2303,7 +2308,7 @@ namespace Barotrauma.Networking List spawnWaypoints = null; List mainSubWaypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSubs[n]).ToList(); - if (Level.Loaded?.StartOutpost != null && + if (Level.Loaded?.StartOutpost != null && Level.Loaded.Type == LevelData.LevelType.Outpost && (Level.Loaded.StartOutpost.Info.OutpostGenerationParams?.SpawnCrewInsideOutpost ?? false) && Level.Loaded.StartOutpost.GetConnectedSubs().Any(s => s.Info.Type == SubmarineType.Player)) @@ -2358,16 +2363,8 @@ namespace Barotrauma.Networking characterData.ApplyHealthData(spawnedCharacter); characterData.ApplyOrderData(spawnedCharacter); spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]); - spawnedCharacter.LoadTalents(); - characterData.HasSpawned = true; } - if (GameMain.GameSession?.GameMode is MultiPlayerCampaign mpCampaign && spawnedCharacter.Info != null) - { - spawnedCharacter.Info.SetExperience(Math.Max(spawnedCharacter.Info.ExperiencePoints, mpCampaign.GetSavedExperiencePoints(teamClients[i]))); - mpCampaign.ClearSavedExperiencePoints(teamClients[i]); - } - spawnedCharacter.OwnerClientEndPoint = teamClients[i].Connection.EndPointString; spawnedCharacter.OwnerClientName = teamClients[i].Name; } @@ -2378,8 +2375,6 @@ namespace Barotrauma.Networking spawnedCharacter.TeamID = teamID; spawnedCharacter.GiveJobItems(mainSubWaypoints[i]); spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]); - // talents are only avilable for players in online sessions, but modders or someone else might want to have them loaded anyway - spawnedCharacter.LoadTalents(); } } @@ -2419,8 +2414,11 @@ namespace Barotrauma.Networking { if (!(GameMain.GameSession?.GameMode is CampaignMode)) { - TraitorManager = new TraitorManager(); - TraitorManager.Start(this); + if (!GameMain.Lua.game.overrideTraitors) + { + TraitorManager = new TraitorManager(); + TraitorManager.Start(this); + } } } @@ -2437,6 +2435,7 @@ namespace Barotrauma.Networking Log("Round started.", ServerLog.MessageType.ServerMessage); + gameStarted = true; initiatedStartGame = false; GameMain.ResetFrameTime(); @@ -2445,7 +2444,9 @@ namespace Barotrauma.Networking roundStartTime = DateTime.Now; - startGameCoroutine = null; + GameMain.Lua.hook.Call("roundStart", new object[] { }); + + yield return CoroutineStatus.Success; } @@ -2470,7 +2471,6 @@ namespace Barotrauma.Networking msg.Write(serverSettings.AllowRespawn && missionAllowRespawn); msg.Write(serverSettings.AllowDisguises); msg.Write(serverSettings.AllowRewiring); - msg.Write(serverSettings.AllowFriendlyFire); msg.Write(serverSettings.LockAllDefaultWires); msg.Write(serverSettings.AllowRagdollButton); msg.Write(serverSettings.UseRespawnShuttle); @@ -2566,6 +2566,9 @@ namespace Barotrauma.Networking Log("Ending the round...", ServerLog.MessageType.ServerMessage); } + GameMain.Lua.hook.Call("roundEnd", new object[] { }); + + string endMessage = TextManager.FormatServerMessage("RoundSummaryRoundHasEnded"); var traitorResults = TraitorManager?.GetEndResults() ?? new List(); @@ -2635,8 +2638,8 @@ namespace Barotrauma.Networking } } - entityEventManager.Clear(); Submarine.Unload(); + entityEventManager.Clear(); GameMain.NetLobbyScreen.Select(); Log("Round ended.", ServerLog.MessageType.ServerMessage); @@ -2805,7 +2808,7 @@ namespace Barotrauma.Networking //reset karma to a neutral value, so if/when the ban is revoked the client wont get immediately punished by low karma again previousPlayer.Karma = Math.Max(previousPlayer.Karma, 50.0f); - + if (!string.IsNullOrEmpty(previousPlayer.EndPoint) && (previousPlayer.SteamID == 0 || range)) { string ip = previousPlayer.EndPoint; @@ -2859,6 +2862,8 @@ namespace Barotrauma.Networking { if (client == null) return; + GameMain.Lua.hook.Call("clientDisconnected", new object[] { client }); + if (gameStarted && client.Character != null) { client.Character.ClientDisconnected = true; @@ -3098,13 +3103,21 @@ namespace Barotrauma.Networking senderName = null; senderCharacter = null; } - else if (type == ChatMessageType.Radio) + else if (type == ChatMessageType.Radio && !GameMain.Lua.game.overrideSignalRadio) { //send to chat-linked wifi components Signal s = new Signal(message, sender: senderCharacter, source: senderRadio.Item); senderRadio.TransmitSignal(s, sentFromChat: true); } + var hookChatMsg = ChatMessage.Create(senderName, message, (ChatMessageType)type, senderCharacter, senderClient, changeType); + + var should = new LuaResult(GameMain.Lua.hook.Call("modifyChatMessage", new object[] { hookChatMsg, senderRadio })); + + if (should.Bool()) + return; + + //check which clients can receive the message and apply distance effects foreach (Client client in ConnectedClients) { @@ -3137,14 +3150,15 @@ namespace Barotrauma.Networking break; } + var chatMsg = ChatMessage.Create( senderName, modifiedMessage, (ChatMessageType)type, senderCharacter, - senderClient, + senderClient, changeType); - + SendDirectChatMessage(chatMsg, client); } @@ -3161,19 +3175,28 @@ namespace Barotrauma.Networking public void SendOrderChatMessage(OrderChatMessage message) { if (message.Sender == null || message.Sender.SpeechImpediment >= 100.0f) { return; } + //ChatMessageType messageType = ChatMessage.CanUseRadio(message.Sender) ? ChatMessageType.Radio : ChatMessageType.Default; + //check which clients can receive the message and apply distance effects foreach (Client client in ConnectedClients) { - if (message.Sender != null && client.Character != null && !client.Character.IsDead) + string modifiedMessage = message.Text; + + if (message.Sender != null && + client.Character != null && !client.Character.IsDead) { //too far to hear the msg -> don't send if (!client.Character.CanHearCharacter(message.Sender)) { continue; } } + SendDirectChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.TargetEntity, message.TargetCharacter, message.Sender), client); } - if (!string.IsNullOrWhiteSpace(message.Text)) + + string myReceivedMessage = message.Text; + + if (!string.IsNullOrWhiteSpace(myReceivedMessage)) { - AddChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, message.Text, message.TargetEntity, message.TargetCharacter, message.Sender)); + AddChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.OrderPriority, myReceivedMessage, message.TargetEntity, message.TargetCharacter, message.Sender)); } } @@ -3435,7 +3458,7 @@ namespace Barotrauma.Networking { newCharacter.LastNetworkUpdateID = client.Character.LastNetworkUpdateID; } - + if (newCharacter.Info != null && newCharacter.Info.Character == null) { newCharacter.Info.Character = newCharacter; @@ -3469,15 +3492,15 @@ namespace Barotrauma.Networking } catch (Exception e) { + //gender = Gender.Male; + //race = Race.White; + //headSpriteId = 0; DebugConsole.Log("Received invalid characterinfo from \"" + sender.Name + "\"! { " + e.Message + " }"); } int hairIndex = message.ReadByte(); int beardIndex = message.ReadByte(); int moustacheIndex = message.ReadByte(); int faceAttachmentIndex = message.ReadByte(); - Color skinColor = message.ReadColorR8G8B8(); - Color hairColor = message.ReadColorR8G8B8(); - Color facialHairColor = message.ReadColorR8G8B8(); List> jobPreferences = new List>(); int count = message.ReadByte(); @@ -3494,9 +3517,6 @@ namespace Barotrauma.Networking sender.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, sender.Name); sender.CharacterInfo.RecreateHead(headSpriteId, race, gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex); - sender.CharacterInfo.SkinColor = skinColor; - sender.CharacterInfo.HairColor = hairColor; - sender.CharacterInfo.FacialHairColor = facialHairColor; if (jobPreferences.Count > 0) { @@ -3689,7 +3709,7 @@ namespace Barotrauma.Networking { c.AssignedJob = preferredJob; assignedClientCount[preferredJob.First]++; - break; + break; } } else //none of the client's preferred jobs available, choose a random job @@ -3746,10 +3766,10 @@ namespace Barotrauma.Networking unassignedBots[0].Job = new Job(jobPrefab, variant); assignedPlayerCount[jobPrefab]++; unassignedBots.Remove(unassignedBots[0]); - canAssign = true; + canAssign = true; } } while (unassignedBots.Count > 0 && canAssign); - + //find a suitable job for the rest of the bots foreach (CharacterInfo c in unassignedBots) { @@ -3796,15 +3816,15 @@ namespace Barotrauma.Networking return preferredClient; } - public void UpdateMissionState(Mission mission) + public void UpdateMissionState(Mission mission, int state) { foreach (var client in connectedClients) { IWriteMessage msg = new WriteOnlyMessage(); msg.Write((byte)ServerPacketHeader.MISSION); int missionIndex = GameMain.GameSession.GetMissionIndex(mission); - msg.Write((byte)(missionIndex == -1 ? 255 : missionIndex)); - mission?.ServerWrite(msg); + msg.Write((byte)(missionIndex == -1 ? 255: missionIndex)); + msg.Write((ushort)state); serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable); } } @@ -3820,6 +3840,9 @@ namespace Barotrauma.Networking { if (GameMain.Server == null || !GameMain.Server.ServerSettings.SaveServerLogs) { return; } + if(GameMain.Lua.hook != null) + GameMain.Lua.hook.Call("serverLog", new object[] { line, messageType }); + GameMain.Server.ServerSettings.ServerLog.WriteLine(line, messageType); foreach (Client client in GameMain.Server.ConnectedClients) @@ -3857,7 +3880,7 @@ namespace Barotrauma.Networking string submarinesString = string.Empty; for (int i = 0; i < GameMain.NetLobbyScreen.CampaignSubmarines.Count; i++) { - submarinesString += GameMain.NetLobbyScreen.CampaignSubmarines[i].Name + ServerSettings.SubmarineSeparatorChar; + submarinesString += GameMain.NetLobbyScreen.CampaignSubmarines[i].Name + ServerSettings.SubmarineSeparatorChar; } submarinesString.Trim(ServerSettings.SubmarineSeparatorChar); serverSettings.CampaignSubmarines = submarinesString; diff --git a/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml b/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml index f41bd4276..27133e747 100644 --- a/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml +++ b/Barotrauma/BarotraumaShared/Data/ContentPackages/Vanilla 0.9.xml @@ -23,7 +23,6 @@ - @@ -64,12 +63,6 @@ - - - - - - @@ -80,7 +73,6 @@ - @@ -88,8 +80,6 @@ - - @@ -157,13 +147,6 @@ - - - - - - - @@ -172,33 +155,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -305,11 +261,4 @@ - - - - - - - - \ No newline at end of file + diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs index 424a6f78c..bfa7d0906 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs @@ -6,13 +6,13 @@ using System.Xml.Linq; using Barotrauma.Networking; using Barotrauma.Extensions; using System.Globalization; -using Barotrauma.Abilities; +using MoonSharp.Interpreter; namespace Barotrauma { partial class CharacterHealth { - class LimbHealth + public class LimbHealth { public Sprite IndicatorSprite; public Sprite HighlightSprite; @@ -20,7 +20,7 @@ namespace Barotrauma public Rectangle HighlightArea; public readonly string Name; - + public readonly List Afflictions = new List(); public readonly Dictionary VitalityMultipliers = new Dictionary(); @@ -76,7 +76,7 @@ namespace Barotrauma } } } - + public List GetActiveAfflictions(AfflictionPrefab prefab) { return Afflictions.FindAll(a => a.Prefab == prefab); @@ -85,7 +85,7 @@ namespace Barotrauma { return Afflictions.FindAll(a => a.Prefab.AfflictionType == afflictionType); } - } + } public const float InsufficientOxygenThreshold = 30.0f; public const float LowOxygenThreshold = 50.0f; @@ -117,15 +117,15 @@ namespace Barotrauma private set => Character.Params.Health.CrushDepth = value; } - private readonly List limbHealths = new List(); + private List limbHealths = new List(); //non-limb-specific afflictions - private readonly List afflictions = new List(); + private List afflictions = new List(); /// /// Note: returns only the non-limb-secific afflictions. Use GetAllAfflictions or some other method for getting also the limb-specific afflictions. /// public IEnumerable Afflictions => afflictions; - private readonly HashSet irremovableAfflictions = new HashSet(); + private HashSet irremovableAfflictions = new HashSet(); private Affliction bloodlossAffliction; private Affliction oxygenLowAffliction; private Affliction pressureAffliction; @@ -133,7 +133,7 @@ namespace Barotrauma public bool IsUnconscious { - get { return (Vitality <= 0.0f || Character.IsDead) && !Character.HasAbilityFlag(AbilityFlags.AlwaysStayConscious); } + get { return Vitality <= 0.0f || Character.IsDead; } } public float PressureKillDelay { get; private set; } = 5.0f; @@ -152,7 +152,6 @@ namespace Barotrauma max += Character.Info.Job.Prefab.VitalityModifier; } max *= Character.StaticHealthMultiplier; - max *= 1f + Character.GetStatValue(StatTypes.MaximumHealthMultiplier); return max * Character.HealthMultiplier; } } @@ -169,20 +168,6 @@ namespace Barotrauma } } - public Color DefaultFaceTint = Color.TransparentBlack; - - public Color FaceTint - { - get; - private set; - } - - public Color BodyTint - { - get; - private set; - } - public float OxygenAmount { get @@ -206,11 +191,7 @@ namespace Barotrauma public float Stun { get { return stunAffliction.Strength; } - set - { - if (Character.GodMode) { return; } - stunAffliction.Strength = MathHelper.Clamp(value, 0.0f, stunAffliction.Prefab.MaxStrength); - } + set { stunAffliction.Strength = MathHelper.Clamp(value, 0.0f, stunAffliction.Prefab.MaxStrength); } } public float StunTimer { get; private set; } @@ -242,7 +223,7 @@ namespace Barotrauma this.Character = character; InitIrremovableAfflictions(); - Vitality = maxVitality; + Vitality = maxVitality; minVitality = character.IsHuman ? -100.0f : 0.0f; @@ -285,12 +266,6 @@ namespace Barotrauma private LimbHealth GetMatchingLimbHealth(Limb limb) => limb == null ? null : limbHealths[limb.HealthIndex]; private LimbHealth GetMatchingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb, excludeSevered: false)); - /// - /// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb. - /// - private IEnumerable GetMatchingAfflictions(LimbHealth limb) - => limb.Afflictions.Union(afflictions.Where(a => GetMatchingLimbHealth(a) == limb)); - /// /// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb. /// @@ -323,7 +298,7 @@ namespace Barotrauma public Affliction GetAffliction(string identifier, bool allowLimbAfflictions = true) => GetAffliction(a => a.Prefab.Identifier == identifier, allowLimbAfflictions); - public Affliction GetAfflictionOfType(string afflictionType, bool allowLimbAfflictions = true) + public Affliction GetAfflictionOfType(string afflictionType, bool allowLimbAfflictions = true) => GetAffliction(a => a.Prefab.AfflictionType == afflictionType, allowLimbAfflictions); private Affliction GetAffliction(Func predicate, bool allowLimbAfflictions = true) @@ -427,61 +402,62 @@ namespace Barotrauma return strength; } - public void ApplyAffliction(Limb targetLimb, Affliction affliction, bool allowStacking = true) + public void ApplyAffliction(Limb targetLimb, Affliction affliction) { if (!affliction.Prefab.IsBuff && Unkillable || Character.GodMode) { return; } if (affliction.Prefab.LimbSpecific) { if (targetLimb == null) { + var should = new LuaResult(GameMain.Lua.hook.Call("afflictionApplied", new object[] { this, affliction })); + + if (should.Bool()) + return; + + //if a limb-specific affliction is applied to no specific limb, apply to all limbs foreach (LimbHealth limbHealth in limbHealths) { - AddLimbAffliction(limbHealth, affliction, allowStacking: allowStacking); + AddLimbAffliction(limbHealth, affliction); } + } else { - AddLimbAffliction(targetLimb, affliction, allowStacking: allowStacking); + var should = new LuaResult(GameMain.Lua.hook.Call("afflictionApplied", new object[] { this, affliction, targetLimb })); + + if (should.Bool()) + return; + + AddLimbAffliction(targetLimb, affliction); } } else { - AddAffliction(affliction, allowStacking: allowStacking); + var should = new LuaResult(GameMain.Lua.hook.Call("afflictionApplied", new object[] { this, affliction })); + + if (should.Bool()) + return; + + AddAffliction(affliction); } } - public float GetResistance(AfflictionPrefab affliction) + public float GetResistance(string resistanceId) { float resistance = 0.0f; for (int i = 0; i < afflictions.Count; i++) { - resistance += afflictions[i].GetResistance(affliction); + if (!afflictions[i].Prefab.IsBuff) continue; + float temp = afflictions[i].GetResistance(resistanceId); + if (temp > resistance) resistance = temp; } - return 1 - ((1 - resistance) * Character.GetAbilityResistance(affliction)); - } - public float GetStatValue(StatTypes statType) - { - float value = 0f; - for (int i = 0; i < afflictions.Count; i++) - { - value += afflictions[i].GetStatValue(statType); - } - return value; - } - - public bool HasFlag(AbilityFlags flagType) - { - for (int i = 0; i < afflictions.Count; i++) - { - if (afflictions[i].HasFlag(flagType)) { return true; } - } - return false; + return resistance; } private readonly List matchingAfflictions = new List(); - public void ReduceAffliction(Limb targetLimb, string affliction, float amount, ActionType? treatmentAction = null) + public void ReduceAffliction(Limb targetLimb, string affliction, float amount) { matchingAfflictions.Clear(); matchingAfflictions.AddRange(afflictions); @@ -510,14 +486,6 @@ namespace Barotrauma for (int i = matchingAfflictions.Count - 1; i >= 0; i--) { var matchingAffliction = matchingAfflictions[i]; - - // this logic runs very often, so culling unnecessary object creation and talent checking with this method - if (Character.HasTalents()) - { - var afflictionReduction = new AbilityValueAffliction(reduceAmount, matchingAffliction); - Character.CheckTalents(AbilityEffectType.OnReduceAffliction, afflictionReduction); - } - if (matchingAffliction.Strength < reduceAmount) { float surplus = reduceAmount - matchingAffliction.Strength; @@ -532,17 +500,6 @@ namespace Barotrauma { matchingAffliction.Strength -= reduceAmount; amount -= reduceAmount; - if (treatmentAction != null) - { - if (treatmentAction.Value == ActionType.OnUse) - { - matchingAffliction.AppliedAsSuccessfulTreatmentTime = Timing.TotalTime; - } - else if (treatmentAction.Value == ActionType.OnFailure) - { - matchingAffliction.AppliedAsFailedTreatmentTime = Timing.TotalTime; - } - } } } CalculateVitality(); @@ -558,6 +515,11 @@ namespace Barotrauma return; } + var should = new LuaResult(GameMain.Lua.hook.Call("afflictionApplied", new object[] { this, attackResult, hitLimb })); + + if (should.Bool()) + return; + foreach (Affliction newAffliction in attackResult.Afflictions) { if (newAffliction.Prefab.LimbSpecific) @@ -568,15 +530,15 @@ namespace Barotrauma { AddAffliction(newAffliction, allowStacking); } - } + } } - + public void SetAllDamage(float damageAmount, float bleedingDamageAmount, float burnDamageAmount) { if (Unkillable || Character.GodMode) { return; } foreach (LimbHealth limbHealth in limbHealths) { - limbHealth.Afflictions.RemoveAll(a => + limbHealth.Afflictions.RemoveAll(a => a.Prefab.AfflictionType == AfflictionPrefab.InternalDamage.AfflictionType || a.Prefab.AfflictionType == AfflictionPrefab.Burn.AfflictionType || a.Prefab.AfflictionType == AfflictionPrefab.Bleeding.AfflictionType); @@ -600,9 +562,9 @@ namespace Barotrauma else { // Instead of using the limbhealth count here, I think it's best to define the max vitality per limb roughly with a constant value. - // Therefore with e.g. 80 health, the max damage per limb would be 40. - // Having at least 40 damage on both legs would cause maximum limping. - float max = MaxVitality / 2; + // Therefore with e.g. 80 health, the max damage per limb would be 20. + // Having at least 20 damage on both legs would cause maximum limping. + float max = MaxVitality / 4; if (string.IsNullOrEmpty(afflictionType)) { float damage = GetAfflictionStrength("damage", limb, true); @@ -633,22 +595,6 @@ namespace Barotrauma CalculateVitality(); } - public void RemoveNegativeAfflictions() - { - // also don't remove genetic effects, even if they're negative - foreach (LimbHealth limbHealth in limbHealths) - { - limbHealth.Afflictions.RemoveAll(a => !a.Prefab.IsBuff && a.Prefab.AfflictionType != "geneticmaterialbuff" && a.Prefab.AfflictionType != "geneticmaterialdebuff"); - } - - afflictions.RemoveAll(a => !irremovableAfflictions.Contains(a) && !a.Prefab.IsBuff && a.Prefab.AfflictionType != "geneticmaterialbuff" && a.Prefab.AfflictionType != "geneticmaterialdebuff"); - foreach (Affliction affliction in irremovableAfflictions) - { - affliction.Strength = 0.0f; - } - CalculateVitality(); - } - private void AddLimbAffliction(Limb limb, Affliction newAffliction, bool allowStacking = true) { if (!newAffliction.Prefab.LimbSpecific || limb == null) { return; } @@ -670,7 +616,7 @@ namespace Barotrauma { if (newAffliction.Prefab == affliction.Prefab) { - float newStrength = newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(affliction.Prefab)); + float newStrength = newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(affliction.Prefab.Identifier)); if (allowStacking) { // Add the existing strength @@ -692,10 +638,10 @@ namespace Barotrauma //create a new instance of the affliction to make sure we don't use the same instance for multiple characters //or modify the affliction instance of an Attack or a StatusEffect var copyAffliction = newAffliction.Prefab.Instantiate( - Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab))), + Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab.Identifier))), newAffliction.Source); limbHealth.Afflictions.Add(copyAffliction); - + Character.HealthUpdateInterval = 0.0f; CalculateVitality(); @@ -714,7 +660,6 @@ namespace Barotrauma private void AddAffliction(Affliction newAffliction, bool allowStacking = true) { if (!DoesBleed && newAffliction is AfflictionBleeding) { return; } - if (Character.Params.Health.StunImmunity && newAffliction.Prefab.AfflictionType == "stun") { return; } if (!Character.NeedsOxygen && newAffliction.Prefab == AfflictionPrefab.OxygenLow) { return; } if (newAffliction.Prefab is AfflictionPrefabHusk huskPrefab) { @@ -727,7 +672,7 @@ namespace Barotrauma { if (newAffliction.Prefab == affliction.Prefab) { - float newStrength = newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(affliction.Prefab)); + float newStrength = newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(affliction.Prefab.Identifier)); if (allowStacking) { // Add the existing strength @@ -749,7 +694,7 @@ namespace Barotrauma //create a new instance of the affliction to make sure we don't use the same instance for multiple characters //or modify the affliction instance of an Attack or a StatusEffect afflictions.Add(newAffliction.Prefab.Instantiate( - Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab))), + Math.Min(newAffliction.Prefab.MaxStrength, newAffliction.Strength * (100.0f / MaxVitality) * (1f - GetResistance(newAffliction.Prefab.Identifier))), source: newAffliction.Source)); Character.HealthUpdateInterval = 0.0f; @@ -761,6 +706,8 @@ namespace Barotrauma } } + partial void UpdateProjSpecific(float deltaTime); + partial void UpdateLimbAfflictionOverlays(); public void Update(float deltaTime) @@ -769,8 +716,6 @@ namespace Barotrauma StunTimer = Stun > 0 ? StunTimer + deltaTime : 0; - if (Character.GodMode) { return; } - for (int i = 0; i < limbHealths.Count; i++) { for (int j = limbHealths[i].Afflictions.Count - 1; j >= 0; j--) @@ -798,11 +743,11 @@ namespace Barotrauma Character.StackSpeedMultiplier(affliction.GetSpeedMultiplier()); } } - + for (int i = afflictions.Count - 1; i >= 0; i--) { var affliction = afflictions[i]; - if (irremovableAfflictions.Contains(affliction)) { continue; } + if (irremovableAfflictions.Contains(affliction)) continue; if (affliction.Strength <= 0.0f) { SteamAchievementManager.OnAfflictionRemoved(affliction, Character); @@ -816,21 +761,9 @@ namespace Barotrauma affliction.DamagePerSecondTimer += deltaTime; Character.StackSpeedMultiplier(affliction.GetSpeedMultiplier()); } - - Character.StackSpeedMultiplier(1f + Character.GetStatValue(StatTypes.MovementSpeed)); - - // maybe a bit of a hacky way to do this. should inquire if there is a better way. M61T - if (Character.InWater) - { - Character.StackSpeedMultiplier(1f + Character.GetStatValue(StatTypes.SwimmingSpeed)); - } - else - { - Character.StackSpeedMultiplier(1f + Character.GetStatValue(StatTypes.WalkingSpeed)); - } - + UpdateLimbAfflictionOverlays(); - UpdateSkinTint(); + CalculateVitality(); if (Vitality <= MinVitality) @@ -839,32 +772,6 @@ namespace Barotrauma } } - private void UpdateSkinTint() - { - FaceTint = DefaultFaceTint; - BodyTint = Color.TransparentBlack; - - for (int i = 0; i < limbHealths.Count; i++) - { - for (int j = limbHealths[i].Afflictions.Count - 1; j >= 0; j--) - { - var affliction = limbHealths[i].Afflictions[j]; - Color faceTint = affliction.GetFaceTint(); - if (faceTint.A > FaceTint.A) { FaceTint = faceTint; } - Color bodyTint = affliction.GetBodyTint(); - if (bodyTint.A > BodyTint.A) { BodyTint = bodyTint; } - } - } - for (int i = 0; i < afflictions.Count; i++) - { - var affliction = afflictions[i]; - Color faceTint = affliction.GetFaceTint(); - if (faceTint.A > FaceTint.A) { FaceTint = faceTint; } - Color bodyTint = affliction.GetBodyTint(); - if (bodyTint.A > BodyTint.A) { BodyTint = bodyTint; } - } - } - private void UpdateOxygen(float deltaTime) { if (!Character.NeedsOxygen) { return; } @@ -873,21 +780,16 @@ namespace Barotrauma if (IsUnconscious) { //the character dies of oxygen deprivation in 100 seconds after losing consciousness - OxygenAmount = MathHelper.Clamp(OxygenAmount - 1.0f * deltaTime, -100.0f, 100.0f); + OxygenAmount = MathHelper.Clamp(OxygenAmount - 1.0f * deltaTime, -100.0f, 100.0f); } else { - float decreaseSpeed = -5.0f; - float increaseSpeed = 10.0f; - float oxygenlowResistance = GetResistance(oxygenLowAffliction.Prefab); - decreaseSpeed *= (1f - oxygenlowResistance); - increaseSpeed *= (1f + oxygenlowResistance); - OxygenAmount = MathHelper.Clamp(OxygenAmount + deltaTime * (Character.OxygenAvailable < InsufficientOxygenThreshold ? decreaseSpeed : increaseSpeed), -100.0f, 100.0f); + OxygenAmount = MathHelper.Clamp(OxygenAmount + deltaTime * (Character.OxygenAvailable < InsufficientOxygenThreshold ? -5.0f : 10.0f), -100.0f, 100.0f); } UpdateOxygenProjSpecific(prevOxygen, deltaTime); } - + partial void UpdateOxygenProjSpecific(float prevOxygen, float deltaTime); partial void UpdateBleedingProjSpecific(AfflictionBleeding affliction, Limb targetLimb, float deltaTime); @@ -903,6 +805,8 @@ namespace Barotrauma Vitality = MaxVitality; if (Unkillable || Character.GodMode) { return; } + float damageResistanceMultiplier = 1f - GetResistance("damage"); + foreach (LimbHealth limbHealth in limbHealths) { foreach (Affliction affliction in limbHealth.Afflictions) @@ -918,6 +822,7 @@ namespace Barotrauma { vitalityDecrease *= limbHealth.VitalityTypeMultipliers[type]; } + vitalityDecrease *= damageResistanceMultiplier; Vitality -= vitalityDecrease; affliction.CalculateDamagePerSecond(vitalityDecrease); } @@ -926,6 +831,7 @@ namespace Barotrauma foreach (Affliction affliction in afflictions) { float vitalityDecrease = affliction.GetVitalityDecrease(this); + vitalityDecrease *= damageResistanceMultiplier; Vitality -= vitalityDecrease; affliction.CalculateDamagePerSecond(vitalityDecrease); } @@ -941,10 +847,9 @@ namespace Barotrauma private void Kill() { if (Unkillable || Character.GodMode) { return; } - - var (type, affliction) = GetCauseOfDeath(); - UpdateSkinTint(); - Character.Kill(type, affliction); + + var causeOfDeath = GetCauseOfDeath(); + Character.Kill(causeOfDeath.First, causeOfDeath.Second); #if CLIENT DisplayVitalityDelay = 0.0f; DisplayedVitality = Vitality; @@ -977,7 +882,7 @@ namespace Barotrauma } } - public (CauseOfDeathType type, Affliction affliction) GetCauseOfDeath() + public Pair GetCauseOfDeath() { List currentAfflictions = GetAllAfflictions(true); @@ -998,7 +903,7 @@ namespace Barotrauma causeOfDeath = Character.AnimController.InWater ? CauseOfDeathType.Drowning : CauseOfDeathType.Suffocation; } - return (causeOfDeath, strongestAffliction); + return new Pair(causeOfDeath, strongestAffliction); } // TODO: this method is called a lot (every half second) -> optimize, don't create new class instances and lists every time! @@ -1044,16 +949,15 @@ namespace Barotrauma /// A dictionary where the key is the identifier of the item and the value the suitability /// If true, the suitability values are normalized between 0 and 1. If not, they're arbitrary values defined in the medical item XML, where negative values are unsuitable, and positive ones suitable. /// Amount of randomization to apply to the values (0 = the values are accurate, 1 = the values are completely random) - public void GetSuitableTreatments(Dictionary treatmentSuitability, bool normalize, Limb limb = null, bool ignoreHiddenAfflictions = false, float randomization = 0.0f) + public void GetSuitableTreatments(Dictionary treatmentSuitability, bool normalize, float randomization = 0.0f) { //key = item identifier //float = suitability treatmentSuitability.Clear(); float minSuitability = -10, maxSuitability = 10; - foreach (Affliction affliction in getAfflictions(limb)) + foreach (Affliction affliction in GetAllAfflictions()) { - if (affliction.Strength <= affliction.Prefab.TreatmentThreshold) { continue; } - if (ignoreHiddenAfflictions && affliction.Strength < affliction.Prefab.ShowIconThreshold) { continue; } + if (affliction.Strength < affliction.Prefab.TreatmentThreshold) { continue; } foreach (KeyValuePair treatment in affliction.Prefab.TreatmentSuitability) { if (!treatmentSuitability.ContainsKey(treatment.Key)) @@ -1084,22 +988,10 @@ namespace Barotrauma treatmentSuitability[treatment] += Rand.Range(-100.0f, 100.0f) * randomization; } } - - IEnumerable getAfflictions(Limb limb) - { - if (limb == null) - { - return GetAllAfflictions(); - } - else - { - return GetMatchingAfflictions(GetMatchingLimbHealth(limb)); - } - } } private readonly List activeAfflictions = new List(); - private readonly List<(LimbHealth limbHealth, Affliction affliction)> limbAfflictions = new List<(LimbHealth limbHealth, Affliction affliction)>(); + private readonly List> limbAfflictions = new List>(); public void ServerWrite(IWriteMessage msg) { activeAfflictions.Clear(); @@ -1115,7 +1007,7 @@ namespace Barotrauma { msg.Write(affliction.Prefab.UIntIdentifier); msg.WriteRangedSingle( - MathHelper.Clamp(affliction.Strength, 0.0f, affliction.Prefab.MaxStrength), + MathHelper.Clamp(affliction.Strength, 0.0f, affliction.Prefab.MaxStrength), 0.0f, affliction.Prefab.MaxStrength, 8); msg.Write((byte)affliction.Prefab.PeriodicEffects.Count()); foreach (AfflictionPrefab.PeriodicEffect periodicEffect in affliction.Prefab.PeriodicEffects) @@ -1130,22 +1022,22 @@ namespace Barotrauma foreach (Affliction limbAffliction in limbHealth.Afflictions) { if (limbAffliction.Strength <= 0.0f || limbAffliction.Strength < limbAffliction.Prefab.ActivationThreshold) continue; - limbAfflictions.Add((limbHealth, limbAffliction)); + limbAfflictions.Add(new Pair(limbHealth, limbAffliction)); } } msg.Write((byte)limbAfflictions.Count); - foreach (var (limbHealth, affliction) in limbAfflictions) + foreach (var limbAffliction in limbAfflictions) { - msg.WriteRangedInteger(limbHealths.IndexOf(limbHealth), 0, limbHealths.Count - 1); - msg.Write(affliction.Prefab.UIntIdentifier); + msg.WriteRangedInteger(limbHealths.IndexOf(limbAffliction.First), 0, limbHealths.Count - 1); + msg.Write(limbAffliction.Second.Prefab.UIntIdentifier); msg.WriteRangedSingle( - MathHelper.Clamp(affliction.Strength, 0.0f, affliction.Prefab.MaxStrength), - 0.0f, affliction.Prefab.MaxStrength, 8); - msg.Write((byte)affliction.Prefab.PeriodicEffects.Count()); - foreach (AfflictionPrefab.PeriodicEffect periodicEffect in affliction.Prefab.PeriodicEffects) + MathHelper.Clamp(limbAffliction.Second.Strength, 0.0f, limbAffliction.Second.Prefab.MaxStrength), + 0.0f, limbAffliction.Second.Prefab.MaxStrength, 8); + msg.Write((byte)limbAffliction.Second.Prefab.PeriodicEffects.Count()); + foreach (AfflictionPrefab.PeriodicEffect periodicEffect in limbAffliction.Second.Prefab.PeriodicEffects) { - msg.WriteRangedSingle(affliction.PeriodicEffectTimers[periodicEffect], periodicEffect.MinInterval, periodicEffect.MaxInterval, 8); + msg.WriteRangedSingle(limbAffliction.Second.PeriodicEffectTimers[periodicEffect], periodicEffect.MinInterval, periodicEffect.MaxInterval, 8); } } } @@ -1161,7 +1053,7 @@ namespace Barotrauma /// Automatically filters out buffs. /// public static IEnumerable SortAfflictionsBySeverity(IEnumerable afflictions, bool excludeBuffs = true) => - afflictions.Where(a => !excludeBuffs || !a.Prefab.IsBuff).OrderByDescending(a => a.DamagePerSecond).ThenByDescending(a => a.Strength / a.Prefab.MaxStrength); + afflictions.Where(a => !excludeBuffs || !a.Prefab.IsBuff).OrderByDescending(a => a.DamagePerSecond).ThenByDescending(a => a.Strength); public void Save(XElement healthElement) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/WifiComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/WifiComponent.cs index 83008b492..ad06fd954 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/WifiComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/WifiComponent.cs @@ -60,7 +60,6 @@ namespace Barotrauma.Items.Components set; } - private bool linkToChat = false; [ConditionallyEditable(ConditionallyEditable.ConditionType.AllowLinkingWifiToChat)] diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index 7518e162d..2d6a462eb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -11,7 +11,7 @@ using System.Linq; using System.Xml.Linq; using Barotrauma.Extensions; using Barotrauma.MapCreatures.Behavior; -using Barotrauma.Abilities; +using MoonSharp.Interpreter; #if CLIENT using Microsoft.Xna.Framework.Graphics; @@ -25,7 +25,7 @@ namespace Barotrauma public ItemPrefab Prefab => prefab as ItemPrefab; public static bool ShowLinks = true; - + private HashSet tags; private bool isWire, isLogic; @@ -37,6 +37,7 @@ namespace Barotrauma set { currentHull = value; + ParentRuin = currentHull?.ParentRuin; } } @@ -97,16 +98,14 @@ namespace Barotrauma private Dictionary connections; - private readonly List repairables; + private List repairables; - private Quality qualityComponent; - - private readonly Queue impactQueue = new Queue(); + private Queue impactQueue = new Queue(); //a dictionary containing lists of the status effects in all the components of the item - private readonly bool[] hasStatusEffectsOfType; - private readonly Dictionary> statusEffectLists; - + private bool[] hasStatusEffectsOfType; + private Dictionary> statusEffectLists; + public Dictionary SerializableProperties { get; protected set; } private bool? hasInGameEditableProperties; @@ -171,7 +170,7 @@ namespace Barotrauma } } } - + public override string Name { get { return prefab.Name; } @@ -233,6 +232,7 @@ namespace Barotrauma { if (character != null && character.IsOnPlayerTeam) { + return IsPlayerTeamInteractable; } else @@ -254,12 +254,6 @@ namespace Barotrauma { if (!Prefab.AllowRotatingInEditor) { return; } rotationRad = MathHelper.ToRadians(value); -#if CLIENT - if (Screen.Selected == GameMain.SubEditorScreen) - { - SetContainedItemPositions(); - } -#endif } } @@ -267,7 +261,7 @@ namespace Barotrauma { get { return Prefab.ImpactTolerance; } } - + public float InteractDistance { get { return Prefab.InteractDistance; } @@ -350,7 +344,7 @@ namespace Barotrauma get; protected set; } - + [Editable, Serialize("1.0,1.0,1.0,1.0", true, description: "Changes the color of the item this item is contained inside. Only has an effect if either of the UseContainedSpriteColor or UseContainedInventoryIconColor property of the container is set to true.")] public Color ContainerColor { @@ -366,9 +360,9 @@ namespace Barotrauma { get { - return - Container?.prefab.Identifier ?? - ParentInventory?.Owner?.ToString() ?? + return + Container?.prefab.Identifier ?? + ParentInventory?.Owner?.ToString() ?? ""; } set { /*do nothing*/ } @@ -455,48 +449,42 @@ namespace Barotrauma } public bool IsFullCondition => MathUtils.NearlyEqual(Condition, MaxCondition); - public float MaxCondition => Prefab.Health * healthMultiplier * maxRepairConditionMultiplier * (1.0f + GetQualityModifier(Items.Components.Quality.StatType.Condition)); + public float MaxCondition => Prefab.Health * healthMultiplier; public float ConditionPercentage => MathUtils.Percentage(Condition, MaxCondition); private float offsetOnSelectedMultiplier = 1.0f; - + [Serialize(1.0f, false)] public float OffsetOnSelectedMultiplier { get => offsetOnSelectedMultiplier; set => offsetOnSelectedMultiplier = value; } - + private float healthMultiplier = 1.0f; [Serialize(1.0f, true, "Multiply the maximum condition by this value")] public float HealthMultiplier { get => healthMultiplier; - set { healthMultiplier = MathHelper.Clamp(value, 0.0f, float.PositiveInfinity); } + set + { + healthMultiplier = value; + } } - - private float maxRepairConditionMultiplier = 1.0f; - - [Serialize(1.0f, true)] - public float MaxRepairConditionMultiplier - { - get => maxRepairConditionMultiplier; - set { maxRepairConditionMultiplier = MathHelper.Clamp(value, 0.0f, float.PositiveInfinity); } - } - + //the default value should be Prefab.Health, but because we can't use it in the attribute, //we'll just use NaN (which does nothing) and set the default value in the constructor/load [Serialize(float.NaN, false), Editable] public float Condition { get { return condition; } - set + set { if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; } if (!MathUtils.IsValid(value)) { return; } if (Indestructible) { return; } - if (InvulnerableToDamage && value <= condition) { return; } + if (InvulnerableToDamage && value <= condition) { return;} float prev = condition; bool wasInFullCondition = IsFullCondition; @@ -513,7 +501,7 @@ namespace Barotrauma #endif ApplyStatusEffects(ActionType.OnBroken, 1.0f, null); } - + SetActiveSprite(); if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer) @@ -553,12 +541,6 @@ namespace Barotrauma set => indestructible = value; } - public bool AllowDeconstruct - { - get; - set; - } - [Editable, Serialize(false, isSaveable: true, "When enabled will prevent the item from taking damage from all sources")] public bool InvulnerableToDamage { get; set; } @@ -632,24 +614,9 @@ namespace Barotrauma get { return Prefab.UseInHealthInterface; } } - public int Quality - { - get - { - return qualityComponent?.QualityLevel ?? 0; - } - set - { - if (qualityComponent != null) - { - qualityComponent.QualityLevel = value; - } - } - } - public bool InWater { - get + get { //if the item has an active physics body, inWater is updated in the Update method if (body != null && body.Enabled) { return inWater; } @@ -766,16 +733,16 @@ namespace Barotrauma { get { return allPropertyObjects; } } - + public bool IgnoreByAI(Character character) => HasTag("ignorebyai") || OrderedToBeIgnored && character.IsOnPlayerTeam; public bool OrderedToBeIgnored { get; set; } public Item(ItemPrefab itemPrefab, Vector2 position, Submarine submarine, ushort id = Entity.NullEntityID) : this(new Rectangle( - (int)(position.X - itemPrefab.sprite.size.X / 2 * itemPrefab.Scale), - (int)(position.Y + itemPrefab.sprite.size.Y / 2 * itemPrefab.Scale), - (int)(itemPrefab.sprite.size.X * itemPrefab.Scale), - (int)(itemPrefab.sprite.size.Y * itemPrefab.Scale)), + (int)(position.X - itemPrefab.sprite.size.X / 2 * itemPrefab.Scale), + (int)(position.Y + itemPrefab.sprite.size.Y / 2 * itemPrefab.Scale), + (int)(itemPrefab.sprite.size.X * itemPrefab.Scale), + (int)(itemPrefab.sprite.size.Y * itemPrefab.Scale)), itemPrefab, submarine, id: id) { @@ -790,10 +757,10 @@ namespace Barotrauma { spriteColor = prefab.SpriteColor; - components = new List(); - drawableComponents = new List(); hasComponentsToDraw = false; - tags = new HashSet(); - repairables = new List(); + components = new List(); + drawableComponents = new List(); hasComponentsToDraw = false; + tags = new HashSet(); + repairables = new List(); defaultRect = newRect; rect = newRect; @@ -801,8 +768,6 @@ namespace Barotrauma condition = MaxCondition; lastSentCondition = condition; - AllowDeconstruct = itemPrefab.AllowDeconstruct; - allPropertyObjects.Add(this); XElement element = itemPrefab.ConfigElement; @@ -831,10 +796,10 @@ namespace Barotrauma body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionPlatform | Physics.CollisionProjectile; } if (collisionCategory != null) - { + { if (!Physics.TryParseCollisionCategory(collisionCategory, out Category cat)) { - DebugConsole.ThrowError("Invalid collision category in item \"" + Name + "\" (" + collisionCategory + ")"); + DebugConsole.ThrowError("Invalid collision category in item \"" + Name+"\" (" + collisionCategory + ")"); } else { @@ -962,8 +927,6 @@ namespace Barotrauma ownInventory = itemContainer.Inventory; } - qualityComponent = GetComponent(); - InitProjSpecific(); if (callOnItemLoaded) @@ -981,9 +944,6 @@ namespace Barotrauma if (Components.Any(ic => ic is Wire) && Components.All(ic => ic is Wire || ic is Holdable)) { isWire = true; } if (HasTag("logic")) { isLogic = true; } - - ApplyStatusEffects(ActionType.OnSpawn, 1.0f); - Components.ForEach(c => c.ApplyStatusEffects(ActionType.OnSpawn, 1.0f)); } partial void InitProjSpecific(); @@ -1030,7 +990,7 @@ namespace Barotrauma continue; } - clone.components[i].requiredItems[kvp.Key][j].JoinedIdentifiers = + clone.components[i].requiredItems[kvp.Key][j].JoinedIdentifiers = kvp.Value[j].JoinedIdentifiers; } } @@ -1038,7 +998,7 @@ namespace Barotrauma if (FlippedX) clone.FlipX(false); if (FlippedY) clone.FlipY(false); - + foreach (ItemComponent component in clone.components) { component.OnItemLoaded(); @@ -1049,7 +1009,7 @@ namespace Barotrauma var containedClone = containedItem.Clone(); clone.ownInventory.TryPutItem(containedClone as Item, null); } - + return clone; } @@ -1063,7 +1023,7 @@ namespace Barotrauma updateableComponents.Add(component); } - component.OnActiveStateChanged += (bool isActive) => + component.OnActiveStateChanged += (bool isActive) => { bool hasSounds = false; #if CLIENT @@ -1071,7 +1031,7 @@ namespace Barotrauma #endif //component doesn't need to be updated if it isn't active, doesn't have a parent that could activate it, //nor status effects, sounds or conditionals that would need to run - if (!isActive && + if (!isActive && !hasSounds && component.Parent == null && (component.IsActiveConditionals == null || !component.IsActiveConditionals.Any()) && @@ -1081,8 +1041,8 @@ namespace Barotrauma } else { - if (!updateableComponents.Contains(component)) - { + if (!updateableComponents.Contains(component)) + { updateableComponents.Add(component); this.isActive = true; } @@ -1143,7 +1103,7 @@ namespace Barotrauma if (typeof(T) == typeof(ItemComponent)) { return (T)components.FirstOrDefault(); - } + } return default; } @@ -1156,17 +1116,12 @@ namespace Barotrauma if (!componentsByType.ContainsKey(typeof(T))) { return Enumerable.Empty(); } return components.Where(c => c is T).Cast(); } - - public float GetQualityModifier(Quality.StatType statType) - { - return GetComponent()?.GetValue(statType) ?? 0.0f; - } - + public void RemoveContained(Item contained) { ownInventory?.RemoveItem(contained); - contained.Container = null; + contained.Container = null; } public void SetTransform(Vector2 simPosition, float rotation, bool findNewHull = true, bool setPrevTransform = true) @@ -1308,7 +1263,7 @@ namespace Barotrauma { foreach (Item item in ItemList) item.FindHull(); } - + public Hull FindHull() { if (parentInventory != null && parentInventory.Owner != null) @@ -1323,7 +1278,7 @@ namespace Barotrauma } Submarine = parentInventory.Owner.Submarine; - if (body != null) { body.Submarine = Submarine; } + if (body != null) body.Submarine = Submarine; return CurrentHull; } @@ -1350,7 +1305,7 @@ namespace Barotrauma return rootContainer; } - + /// /// Should this item or any of its containers be ignored by the AI? /// @@ -1402,7 +1357,7 @@ namespace Barotrauma (component as ItemContainer)?.SetContainedItemPositions(); } } - + public void AddTag(string tag) { if (tags.Contains(tag)) { return; } @@ -1463,7 +1418,7 @@ namespace Barotrauma ApplyStatusEffect(effect, type, deltaTime, character, limb, useTarget, isNetworkEvent, false, worldPosition); } } - + readonly List targets = new List(); public void ApplyStatusEffect(StatusEffect effect, ActionType type, float deltaTime, Character character = null, Limb limb = null, Entity useTarget = null, bool isNetworkEvent = false, bool checkCondition = true, Vector2? worldPosition = null) @@ -1473,11 +1428,11 @@ namespace Barotrauma if (condition == 0.0f && !effect.AllowWhenBroken && effect.type != ActionType.OnBroken) { return; } } if (effect.type != type) { return; } - + bool hasTargets = effect.TargetIdentifiers == null; targets.Clear(); - + if (effect.HasTargetType(StatusEffect.TargetType.Contained)) { foreach (Item containedItem in ContainedItems) @@ -1489,11 +1444,6 @@ namespace Barotrauma continue; } - if (effect.TargetSlot > -1) - { - if (OwnInventory.FindIndex(containedItem) != effect.TargetSlot) { continue; } - } - hasTargets = true; targets.Add(containedItem); } @@ -1551,10 +1501,10 @@ namespace Barotrauma { targets.Add(limb); } - - if (Container != null && effect.HasTargetType(StatusEffect.TargetType.Parent)) { targets.Add(Container); } - - effect.Apply(type, deltaTime, this, targets, worldPosition); + + if (Container != null && effect.HasTargetType(StatusEffect.TargetType.Parent)) targets.Add(Container); + + effect.Apply(type, deltaTime, this, targets, worldPosition); } @@ -1576,7 +1526,7 @@ namespace Barotrauma private bool IsInWater() { if (CurrentHull == null) { return true; } - + float surfaceY = CurrentHull.Surface; return CurrentHull.WaterVolume > 0.0f && Position.Y < surfaceY; } @@ -1612,10 +1562,9 @@ namespace Barotrauma } } - if (aiTarget != null) - { - aiTarget.Update(deltaTime); - } + aiTarget?.Update(deltaTime); + + GameMain.Lua.hook.Call("itemThink." + prefab.Identifier, new object[] { this, deltaTime }); if (!isActive) { return; } @@ -1631,7 +1580,7 @@ namespace Barotrauma bool shouldBeActive = true; foreach (var conditional in ic.IsActiveConditionals) { - if (!ConditionalMatches(conditional)) + if (!ConditionalMatches(conditional)) { shouldBeActive = false; break; @@ -1729,22 +1678,14 @@ namespace Barotrauma } } - + public void UpdateTransform() { if (body == null) { return; } + Submarine prevSub = Submarine; - var projectile = GetComponent(); - if (projectile?.StickTarget?.UserData is Limb limb) - { - Submarine = body.Submarine = limb.character?.Submarine; - currentHull = limb.character?.CurrentHull; - } - else - { - FindHull(); - } + FindHull(); if (Submarine == null && prevSub != null) { @@ -1772,7 +1713,7 @@ namespace Barotrauma rect.X = (int)(displayPos.X - rect.Width / 2.0f); rect.Y = (int)(displayPos.Y + rect.Height / 2.0f); - if (Math.Abs(body.LinearVelocity.X) > NetConfig.MaxPhysicsBodyVelocity || + if (Math.Abs(body.LinearVelocity.X) > NetConfig.MaxPhysicsBodyVelocity || Math.Abs(body.LinearVelocity.Y) > NetConfig.MaxPhysicsBodyVelocity) { body.LinearVelocity = new Vector2( @@ -1811,23 +1752,17 @@ namespace Barotrauma Vector2 drag = body.LinearVelocity * volume; - body.ApplyForce((uplift - drag) * 10.0f); + body.ApplyForce((uplift - drag) * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity); //apply simple angular drag body.ApplyTorque(body.AngularVelocity * volume * -0.05f); - } + } private bool OnCollision(Fixture f1, Fixture f2, Contact contact) { if (transformDirty) { return false; } - var projectile = GetComponent(); - if (projectile?.IgnoredBodies != null) - { - if (projectile.IgnoredBodies.Contains(f2.Body)) { return false; } - } - contact.GetWorldManifold(out Vector2 normal, out _); if (contact.FixtureA.Body == f1.Body) { normal = -normal; } float impact = Vector2.Dot(f1.Body.LinearVelocity, -normal); @@ -1856,7 +1791,7 @@ namespace Barotrauma foreach (Item contained in ContainedItems) { if (contained.body != null) { contained.HandleCollision(impact); } - } + } } } @@ -1867,10 +1802,10 @@ namespace Barotrauma //call the base method even if the item can't flip, to handle repositioning when flipping the whole sub base.FlipX(relativeToSub); - if (!Prefab.CanFlipX) + if (!Prefab.CanFlipX) { flippedX = false; - return; + return; } if (Prefab.AllowRotatingInEditor) @@ -1887,8 +1822,7 @@ namespace Barotrauma foreach (ItemComponent component in components) { component.FlipX(relativeToSub); - } - SetContainedItemPositions(); + } } public override void FlipY(bool relativeToSub) @@ -1913,7 +1847,6 @@ namespace Barotrauma { component.FlipY(relativeToSub); } - SetContainedItemPositions(); } /// @@ -1942,7 +1875,7 @@ namespace Barotrauma if (component != null && !connectedComponents.Contains(component)) { connectedComponents.Add(component); - } + } } } @@ -1973,28 +1906,28 @@ namespace Barotrauma return connectedComponents; } - - public static readonly (string input, string output)[] connectionPairs = new (string input, string output)[] + + public static readonly Pair[] connectionPairs = new Pair[] { - ("power_in", "power_out"), - ("signal_in1", "signal_out1"), - ("signal_in2", "signal_out2"), - ("signal_in3", "signal_out3"), - ("signal_in4", "signal_out4"), - ("signal_in", "signal_out"), - ("signal_in1", "signal_out"), - ("signal_in2", "signal_out") + new Pair("power_in", "power_out"), + new Pair("signal_in1", "signal_out1"), + new Pair("signal_in2", "signal_out2"), + new Pair("signal_in3", "signal_out3"), + new Pair("signal_in4", "signal_out4"), + new Pair("signal_in", "signal_out"), + new Pair("signal_in1", "signal_out"), + new Pair("signal_in2", "signal_out") }; private void GetConnectedComponentsRecursive(Connection c, HashSet alreadySearched, List connectedComponents) where T : ItemComponent { alreadySearched.Add(c); - + var recipients = c.Recipients; foreach (Connection recipient in recipients) { if (alreadySearched.Contains(recipient)) { continue; } - var component = recipient.Item.GetComponent(); + var component = recipient.Item.GetComponent(); if (component != null && !connectedComponents.Contains(component)) { connectedComponents.Add(component); @@ -2016,23 +1949,23 @@ namespace Barotrauma } } - recipient.Item.GetConnectedComponentsRecursive(recipient, alreadySearched, connectedComponents); + recipient.Item.GetConnectedComponentsRecursive(recipient, alreadySearched, connectedComponents); } - foreach ((string input, string output) in connectionPairs) + foreach (Pair connectionPair in connectionPairs) { - if (input == c.Name) + if (connectionPair.First == c.Name) { - var pairedConnection = c.Item.Connections.FirstOrDefault(c2 => c2.Name == output); + var pairedConnection = c.Item.Connections.FirstOrDefault(c2 => c2.Name == connectionPair.Second); if (pairedConnection != null) { if (alreadySearched.Contains(pairedConnection)) { continue; } GetConnectedComponentsRecursive(pairedConnection, alreadySearched, connectedComponents); } } - else if (output == c.Name) + else if (connectionPair.Second == c.Name) { - var pairedConnection = c.Item.Connections.FirstOrDefault(c2 => c2.Name == input); + var pairedConnection = c.Item.Connections.FirstOrDefault(c2 => c2.Name == connectionPair.First); if (pairedConnection != null) { if (alreadySearched.Contains(pairedConnection)) { continue; } @@ -2042,27 +1975,18 @@ namespace Barotrauma } } - public Controller FindController(string[] tags = null) + public Controller FindController() { //try finding the controller with the simpler non-recursive method first var controllers = GetConnectedComponents(); - bool needsTag = tags != null && tags.Length > 0; - if (controllers.None() || (needsTag && controllers.None(c => c.Item.HasTag(tags)))) - { - controllers = GetConnectedComponents(recursive: true); - } - if (needsTag) - { - controllers.RemoveAll(c => !c.Item.HasTag(tags)); - } - return controllers.Count < 2 ? - controllers.FirstOrDefault() : - controllers.FirstOrDefault(c => c.GetFocusTarget() == this) ?? controllers.FirstOrDefault(); + if (controllers.None()) { controllers = GetConnectedComponents(recursive: true); } + return controllers.Count < 2 ? controllers.FirstOrDefault() : + (controllers.FirstOrDefault(c => c.GetFocusTarget() == this) ?? controllers.FirstOrDefault()); } - public bool TryFindController(out Controller controller, string[] tags = null) + public bool TryFindController(out Controller controller) { - controller = FindController(tags: tags); + controller = FindController(); return controller != null; } @@ -2134,6 +2058,8 @@ namespace Barotrauma } while (CoroutineManager.DeltaTime <= 0.0f); delayedSignals.Remove((signal, connection)); + + signal.source = this; connection.SendSignal(signal); yield return CoroutineStatus.Success; @@ -2163,6 +2089,11 @@ namespace Barotrauma public bool TryInteract(Character picker, bool ignoreRequiredItems = false, bool forceSelectKey = false, bool forceActionKey = false) { + var should = new LuaResult(GameMain.Lua.hook.Call("itemInteract", new object[] { this, picker, ignoreRequiredItems, forceSelectKey, forceActionKey })); + + if (!should.IsNull()) + return should.Bool(); + if (CampaignInteractionType != CampaignMode.InteractionType.None) { return false; } bool picked = false, selected = false; @@ -2220,7 +2151,7 @@ namespace Barotrauma } #endif if (!pickHit && !selectHit) { continue; } - + bool showUiMsg = false; #if CLIENT if (!ic.HasRequiredSkills(picker, out Skill tempRequiredSkill)) { hasRequiredSkills = false; skillMultiplier = ic.GetSkillMultiplier(); } @@ -2270,7 +2201,7 @@ namespace Barotrauma if (Container != null) Container.RemoveContained(this); - return true; + return true; } public float GetContainedItemConditionPercentage() @@ -2287,7 +2218,7 @@ namespace Barotrauma if (maxCondition > 0.0f) { return condition / maxCondition; - } + } return -1; } @@ -2301,6 +2232,11 @@ namespace Barotrauma if (condition == 0.0f) { return; } + var should = new LuaResult(GameMain.Lua.hook.Call("itemUse", new object[] { this, character, targetLimb })); + + if (should.Bool()) + return; + bool remove = false; foreach (ItemComponent ic in components) @@ -2317,7 +2253,7 @@ namespace Barotrauma #if CLIENT ic.PlaySound(ActionType.OnUse, character); #endif - + ic.ApplyStatusEffects(ActionType.OnUse, deltaTime, character, targetLimb); if (ic.DeleteOnUse) { remove = true; } @@ -2334,6 +2270,12 @@ namespace Barotrauma { if (condition == 0.0f) { return; } + var should = new LuaResult(GameMain.Lua.hook.Call("itemSecondaryUse", new object[] { this, character})); + + if (should.Bool()) + return; + + bool remove = false; foreach (ItemComponent ic in components) @@ -2365,9 +2307,14 @@ namespace Barotrauma public void ApplyTreatment(Character user, Character character, Limb targetLimb) { + var should = new LuaResult(GameMain.Lua.hook.Call("itemApplyTreatment", new object[] { this, user, character, targetLimb })); + + if (should.Bool()) + return; + //can't apply treatment to dead characters - if (character.IsDead) { return; } - if (!UseInHealthInterface) { return; } + if (character.IsDead) return; + if (!UseInHealthInterface) return; #if CLIENT if (GameMain.Client != null) @@ -2377,12 +2324,10 @@ namespace Barotrauma } #endif - float applyOnSelfFraction = user?.GetStatValue(StatTypes.ApplyTreatmentsOnSelfFraction) ?? 0.0f; - bool remove = false; foreach (ItemComponent ic in components) { - if (!ic.HasRequiredContainedItems(user, addMessage: user == Character.Controlled)) { continue; } + if (!ic.HasRequiredContainedItems(user, addMessage: user == Character.Controlled)) continue; bool success = Rand.Range(0.0f, 0.5f) < ic.DegreeOfSuccess(user); ActionType actionType = success ? ActionType.OnUse : ActionType.OnFailure; @@ -2391,19 +2336,7 @@ namespace Barotrauma ic.PlaySound(actionType, user); #endif ic.WasUsed = true; - ic.ApplyStatusEffects(actionType, 1.0f, character, targetLimb, user: user, applyOnUserFraction: applyOnSelfFraction); - - if (applyOnSelfFraction > 0.0f) - { - //hacky af - ic.statusEffectLists.TryGetValue(actionType, out var effectList); - if (effectList != null) - { - effectList.ForEach(e => e.AfflictionMultiplier = applyOnSelfFraction); - ic.ApplyStatusEffects(actionType, 1.0f, user, targetLimb == null ? null : user.AnimController.GetLimb(targetLimb.type), user: user); - effectList.ForEach(e => e.AfflictionMultiplier = 1.0f); - } - } + ic.ApplyStatusEffects(actionType, 1.0f, character, targetLimb, user: user); if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer) { @@ -2413,23 +2346,19 @@ namespace Barotrauma }); } - if (ic.DeleteOnUse) { remove = true; } + if (ic.DeleteOnUse) remove = true; } - if (user != null) - { - var abilityItem = new AbilityApplyTreatment(user, character, this); - user.CheckTalents(AbilityEffectType.OnApplyTreatment, abilityItem); - - } - - - if (remove) { Spawner?.AddToRemoveQueue(this); } } public bool Combine(Item item, Character user) { + var should = new LuaResult(GameMain.Lua.hook.Call("itemCombine", new object[] { this, item, user })); + + if (!should.IsNull()) + return should.Bool(); + if (item == this) { return false; } bool isCombined = false; foreach (ItemComponent ic in components) @@ -2444,6 +2373,11 @@ namespace Barotrauma public void Drop(Character dropper, bool createNetworkEvent = true) { + var should = new LuaResult(GameMain.Lua.hook.Call("itemDrop", new object[] { this, dropper})); + + if (should.Bool()) + return; + if (createNetworkEvent) { if (parentInventory != null && !parentInventory.Owner.Removed && !Removed && @@ -2477,25 +2411,28 @@ namespace Barotrauma } foreach (ItemComponent ic in components) { ic.Drop(dropper); } - + if (Container != null) { SetTransform(Container.SimPosition, 0.0f); Container.RemoveContained(this); Container = null; } - + if (parentInventory != null) { parentInventory.RemoveItem(this); parentInventory = null; } - - SetContainedItemPositions(); } public void Equip(Character character) { + var should = new LuaResult(GameMain.Lua.hook.Call("itemEquip", new object[] { this, character})); + + if (should.Bool()) + return; + if (Removed) { DebugConsole.ThrowError($"Tried to equip a removed item ({Name}).\n{Environment.StackTrace.CleanupStackTrace()}"); @@ -2507,6 +2444,11 @@ namespace Barotrauma public void Unequip(Character character) { + var should = new LuaResult(GameMain.Lua.hook.Call("itemUnequip", new object[] { this, character })); + + if (should.Bool()) + return; + foreach (ItemComponent ic in components) { ic.Unequip(character); } } @@ -2518,7 +2460,7 @@ namespace Barotrauma foreach (var itemProperty in itemProperties) { allProperties.Add(new Pair(this, itemProperty)); - } + } foreach (ItemComponent ic in components) { List componentProperties = SerializableProperty.GetProperties(ic); @@ -2600,14 +2542,6 @@ namespace Barotrauma { msg.Write((int)value); } - else if (value is string[] a) - { - msg.Write(a.Length); - for (int i = 0; i < a.Length; i++) - { - msg.Write(a[i] ?? ""); - } - } else { throw new NotImplementedException("Serializing item properties of the type \"" + value.GetType() + "\" not supported"); @@ -2656,8 +2590,8 @@ namespace Barotrauma { string val = msg.ReadString(); logValue = val; - if (allowEditing) - { + if (allowEditing) + { property.TrySetValue(parentObject, val); } } @@ -2715,26 +2649,13 @@ namespace Barotrauma logValue = XMLExtensions.RectToString(val); if (allowEditing) { property.TrySetValue(parentObject, val); } } - else if (type == typeof(string[])) - { - int arrayLength = msg.ReadInt32(); - string[] val = new string[arrayLength]; - for (int i = 0; i < arrayLength; i++) - { - val[i] = msg.ReadString(); - } - if (allowEditing) - { - property.TrySetValue(parentObject, val); - } - } else if (typeof(Enum).IsAssignableFrom(type)) { int intVal = msg.ReadInt32(); try { - if (allowEditing) - { + if (allowEditing) + { property.TrySetValue(parentObject, Enum.ToObject(type, intVal)); logValue = property.GetValue(parentObject).ToString(); } @@ -2763,9 +2684,10 @@ namespace Barotrauma { CoroutineManager.StopCoroutines(logPropertyChangeCoroutine); } - logPropertyChangeCoroutine = CoroutineManager.Invoke(() => + logPropertyChangeCoroutine = CoroutineManager.InvokeAfter(() => { - GameServer.Log($"{sender.Character.Name} set the value \"{property.Name}\" of the item \"{Name}\" to \"{logValue}\".", ServerLog.MessageType.ItemInteraction); + if(sender.Character != null) + GameServer.Log($"{sender.Character.Name} set the value \"{property.Name}\" of the item \"{Name}\" to \"{logValue}\".", ServerLog.MessageType.ItemInteraction); }, delay: 1.0f); } #endif @@ -3003,7 +2925,7 @@ namespace Barotrauma { component.OnItemLoaded(); } - + return item; } @@ -3053,7 +2975,7 @@ namespace Barotrauma (int)(rect.X - subPosition.X) + "," + (int)(rect.Y - subPosition.Y) + "," + width + "," + height)); - + if (linkedTo != null && linkedTo.Count > 0) { bool isOutpost = Submarine != null && Submarine.Info.IsOutpost; @@ -3103,7 +3025,7 @@ namespace Barotrauma ic.OnMapLoaded(); } } - + /// /// Remove the item so that it doesn't appear to exist in the game world (stop sounds, remove bodies etc) /// but don't reset anything that's required for cloning the item @@ -3111,7 +3033,7 @@ namespace Barotrauma public override void ShallowRemove() { base.ShallowRemove(); - + foreach (ItemComponent ic in components) { ic.ShallowRemove(); @@ -3133,7 +3055,7 @@ namespace Barotrauma return; } DebugConsole.Log("Removing item " + Name + " (ID: " + ID + ")"); - + base.Remove(); foreach (Character character in Character.CharacterList) @@ -3152,8 +3074,6 @@ namespace Barotrauma } } - connections?.Clear(); - if (parentInventory != null) { if (parentInventory is CharacterInventory characterInventory) @@ -3179,8 +3099,6 @@ namespace Barotrauma body = null; } - CurrentHull = null; - if (StaticFixtures != null) { foreach (Fixture fixture in StaticFixtures)