Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fixed npc health #420

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions EXILED/Exiled.API/Features/Npc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ namespace Exiled.API.Features
using CommandSystem.Commands.RemoteAdmin.Dummies;
using Exiled.API.Enums;
using Exiled.API.Features.Components;
using Exiled.API.Features.CustomStats;
using Exiled.API.Features.Roles;
using Footprinting;
using GameCore;
using MEC;
using Mirror;
using PlayerRoles;
using PlayerStatsSystem;
using UnityEngine;

using Object = UnityEngine.Object;
Expand All @@ -33,6 +35,11 @@ namespace Exiled.API.Features
/// </summary>
public class Npc : Player
{
/// <summary>
/// The time it takes for the NPC to receive its <see cref="CustomHealthStat"/>, <see cref="CustomHumeShieldStat"/> and <see cref="Role"/>.
/// </summary>
public const float SpawnSetRoleDelay = 0.5f;

/// <inheritdoc cref="Player" />
public Npc(ReferenceHub referenceHub)
: base(referenceHub)
Expand Down Expand Up @@ -252,10 +259,13 @@ public static Npc Spawn(string name, RoleTypeId role, Vector3 position)
{
Npc npc = new(DummyUtils.SpawnDummy(name));

Timing.CallDelayed(0.5f, () =>
Timing.CallDelayed(SpawnSetRoleDelay, () =>
{
npc.Role.Set(role);
npc.Role.Set(role, SpawnReason.ForceClass);
npc.Position = position;
npc.ReferenceHub.playerStats._dictionarizedTypes[typeof(HealthStat)] = npc.ReferenceHub.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HealthStat))] = npc.CustomHealthStat = new CustomHealthStat { Hub = npc.ReferenceHub };
Bonjemus marked this conversation as resolved.
Show resolved Hide resolved
npc.Health = npc.MaxHealth; // otherwise the npc will spawn with 0 health
npc.ReferenceHub.playerStats._dictionarizedTypes[typeof(HumeShieldStat)] = npc.ReferenceHub.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HumeShieldStat))] = npc.CustomHumeShieldStat = new CustomHumeShieldStat { Hub = npc.ReferenceHub };
});

Dictionary.Add(npc.GameObject, npc);
Expand All @@ -274,9 +284,12 @@ public static Npc Spawn(string name, RoleTypeId role = RoleTypeId.None, bool ign
{
Npc npc = new(DummyUtils.SpawnDummy(name));

Timing.CallDelayed(0.5f, () =>
Timing.CallDelayed(SpawnSetRoleDelay, () =>
{
npc.Role.Set(role, SpawnReason.ForceClass, position is null ? RoleSpawnFlags.All : RoleSpawnFlags.AssignInventory);
npc.ReferenceHub.playerStats._dictionarizedTypes[typeof(HealthStat)] = npc.ReferenceHub.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HealthStat))] = npc.CustomHealthStat = new CustomHealthStat { Hub = npc.ReferenceHub };
npc.Health = npc.MaxHealth; // otherwise the npc will spawn with 0 health
npc.ReferenceHub.playerStats._dictionarizedTypes[typeof(HumeShieldStat)] = npc.ReferenceHub.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HumeShieldStat))] = npc.CustomHumeShieldStat = new CustomHumeShieldStat { Hub = npc.ReferenceHub };

if (position is not null)
npc.Position = position.Value;
Expand Down
41 changes: 24 additions & 17 deletions EXILED/Exiled.API/Features/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ namespace Exiled.API.Features
using PluginAPI.Core;
using RelativePositioning;
using RemoteAdmin;
using Respawning.NamingRules;
using RoundRestarting;
using UnityEngine;
using Utils;
Expand Down Expand Up @@ -96,8 +95,6 @@ public class Player : TypeCastObject<Player>, IEntity, IWorldSpace
private readonly HashSet<EActor> componentsInChildren = new();

private ReferenceHub referenceHub;
private CustomHealthStat healthStat;
private CustomHumeShieldStat humeShieldStat;
private Role role;

/// <summary>
Expand Down Expand Up @@ -145,6 +142,16 @@ public Player(GameObject gameObject)
/// </summary>
public static Dictionary<string, Player> UserIdsCache { get; } = new(20);

/// <summary>
/// Gets or sets a <see cref="CustomHealthStat"/>.
/// </summary>
public CustomHealthStat CustomHealthStat { get; protected set; }

/// <summary>
/// Gets or sets a <see cref="CustomHumeShieldStat"/>.
/// </summary>
public CustomHumeShieldStat CustomHumeShieldStat { get; protected set; }

/// <inheritdoc/>
public IReadOnlyCollection<EActor> ComponentsInChildren => componentsInChildren;

Expand Down Expand Up @@ -178,8 +185,8 @@ private set
Inventory = value.inventory;
CameraTransform = value.PlayerCameraReference;

value.playerStats._dictionarizedTypes[typeof(HealthStat)] = value.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HealthStat))] = healthStat = new CustomHealthStat { Hub = value };
value.playerStats._dictionarizedTypes[typeof(HumeShieldStat)] = value.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HumeShieldStat))] = humeShieldStat = new CustomHumeShieldStat { Hub = value };
value.playerStats._dictionarizedTypes[typeof(HealthStat)] = value.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HealthStat))] = CustomHealthStat = new CustomHealthStat { Hub = value };
value.playerStats._dictionarizedTypes[typeof(HumeShieldStat)] = value.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HumeShieldStat))] = CustomHumeShieldStat = new CustomHumeShieldStat { Hub = value };
}
}

Expand Down Expand Up @@ -867,13 +874,13 @@ public DangerStackBase[] Dangers
/// </summary>
public float Health
{
get => healthStat.CurValue;
get => CustomHealthStat.CurValue;
set
{
if (value > MaxHealth)
MaxHealth = value;

healthStat.CurValue = value;
CustomHealthStat.CurValue = value;
}
}

Expand All @@ -882,8 +889,8 @@ public float Health
/// </summary>
public float MaxHealth
{
get => healthStat.MaxValue;
set => healthStat.CustomMaxValue = value;
get => CustomHealthStat.MaxValue;
set => CustomHealthStat.CustomMaxValue = value;
}

/// <summary>
Expand Down Expand Up @@ -929,26 +936,26 @@ public float MaxArtificialHealth
/// <remarks>This value can bypass the role's hume shield maximum. However, this value will only be visible to the end-player as Hume Shield if <see cref="FpcRole.IsHumeShieldedRole"/> is <see langword="true"/>. Otherwise, the game will treat the player as though they have the amount of Hume Shield specified, even though they cannot see it.</remarks>
public float HumeShield
{
get => HumeShieldStat.CurValue;
set => HumeShieldStat.CurValue = value;
get => CustomHumeShieldStat.CurValue;
set => CustomHumeShieldStat.CurValue = value;
}

/// <summary>
/// Gets or sets the players maximum Hume Shield.
/// </summary>
public float MaxHumeShield
{
get => humeShieldStat.MaxValue;
set => humeShieldStat.CustomMaxValue = value;
get => CustomHumeShieldStat.MaxValue;
set => CustomHumeShieldStat.CustomMaxValue = value;
}

/// <summary>
/// Gets or sets the players multiplier for gaining HumeShield.
/// </summary>
public float HumeShieldRegenerationMultiplier
{
get => humeShieldStat.ShieldRegenerationMultiplier;
set => humeShieldStat.ShieldRegenerationMultiplier = value;
get => CustomHumeShieldStat.ShieldRegenerationMultiplier;
set => CustomHumeShieldStat.ShieldRegenerationMultiplier = value;
}

/// <summary>
Expand All @@ -958,9 +965,9 @@ public float HumeShieldRegenerationMultiplier

/// <summary>
/// Gets the player's <see cref="PlayerStatsSystem.HumeShieldStat"/>.
/// TODO: Change to <see cref="CustomHumeShieldStat"/>.
/// </summary>
public HumeShieldStat HumeShieldStat => humeShieldStat;
[Obsolete("Use " + nameof(CustomHumeShieldStat) + " instead.")]
public HumeShieldStat HumeShieldStat => CustomHumeShieldStat;

/// <summary>
/// Gets or sets the item in the player's hand. Value will be <see langword="null"/> if the player is not holding anything.
Expand Down
21 changes: 7 additions & 14 deletions EXILED/Exiled.Events/Patches/Events/Map/ExplodingFlashGrenade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ namespace Exiled.Events.Patches.Events.Map
using Exiled.API.Extensions;
using Exiled.Events.EventArgs.Map;
using Exiled.Events.Patches.Generic;
using Footprinting;
using HarmonyLib;
using InventorySystem.Items.ThrowableProjectiles;
using UnityEngine;
Expand Down Expand Up @@ -64,18 +63,14 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
private static void ProcessEvent(FlashbangGrenade instance, float distance)
{
HashSet<Player> targetToAffect = HashSetPool<Player>.Pool.Get();
foreach (Player player in Player.List)
foreach (ReferenceHub referenceHub in ReferenceHub.AllHubs)
{
if ((instance.transform.position - player.Position).sqrMagnitude >= distance)
continue;
if (!ExiledEvents.Instance.Config.CanFlashbangsAffectThrower && instance.PreviousOwner.CompareLife(player.ReferenceHub))
continue;
if (!IndividualFriendlyFire.CheckFriendlyFirePlayer(instance.PreviousOwner, player.ReferenceHub) && !instance.PreviousOwner.CompareLife(player.ReferenceHub))
continue;
if (Physics.Linecast(instance.transform.position, player.CameraTransform.position, instance._blindingMask))
continue;

targetToAffect.Add(player);
if (Player.TryGet(referenceHub, out Player player)
Bonjemus marked this conversation as resolved.
Show resolved Hide resolved
&& (instance.transform.position - player.Position).sqrMagnitude < distance
&& (ExiledEvents.Instance.Config.CanFlashbangsAffectThrower || !instance.PreviousOwner.CompareLife(referenceHub))
&& (IndividualFriendlyFire.CheckFriendlyFirePlayer(instance.PreviousOwner, referenceHub) || instance.PreviousOwner.CompareLife(referenceHub))
&& !Physics.Linecast(instance.transform.position, player.CameraTransform.position, instance._blindingMask))
targetToAffect.Add(player);
}

ExplodingGrenadeEventArgs explodingGrenadeEvent = new(Player.Get(instance.PreviousOwner.Hub), instance, targetToAffect);
Expand All @@ -88,9 +83,7 @@ private static void ProcessEvent(FlashbangGrenade instance, float distance)
return;

foreach (Player player in explodingGrenadeEvent.TargetsToAffect)
{
instance.ProcessPlayer(player.ReferenceHub);
}
}
}
}