Skip to content

Commit

Permalink
Friendly fire update (#33)
Browse files Browse the repository at this point in the history
* Untested

* Testing alternative.

* Update EXILED/Exiled.Events/Patches/Generic/IndividualFriendlyFire.cs

* Option 1.

* Option 2

* Option 2 updated.

* Var removal.
  • Loading branch information
Undid-Iridium authored Nov 18, 2024
1 parent 9be2dcd commit ef52b45
Showing 1 changed file with 26 additions and 41 deletions.
67 changes: 26 additions & 41 deletions EXILED/Exiled.Events/Patches/Generic/IndividualFriendlyFire.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,18 @@ public static bool CheckFriendlyFirePlayerRules(Footprint attackerFootprint, Ref

// Return false, no custom friendly fire allowed, default to NW logic for FF. No point in processing if FF is enabled across the board.
if (Server.FriendlyFire)
return HitboxIdentity.IsEnemy(attackerFootprint.Role, victimHub.roleManager.CurrentRole.RoleTypeId);
return HitboxIdentity.IsDamageable(attackerFootprint.Role, victimHub.roleManager.CurrentRole.RoleTypeId);

// always allow damage from Server.Host
// Always allow damage from Server.Host
if (attackerFootprint.Hub == Server.Host.ReferenceHub)
return true;

// Only check friendlyFire if the FootPrint hasn't changed (Fix for Grenade not dealing damage because it's from a dead player)
// TODO rework FriendlyFireRule to make it compatible with Footprint
if (!attackerFootprint.SameLife(new(attackerFootprint.Hub)))
return HitboxIdentity.IsEnemy(attackerFootprint.Role, victimHub.roleManager.CurrentRole.RoleTypeId);
if (!attackerFootprint.SameLife(new Footprint(attackerFootprint.Hub)))
return false;

// Check if attackerFootprint.Hub or victimHub is null and log debug information
if (attackerFootprint.Hub is null || victimHub is null)
{
Log.Debug($"CheckFriendlyFirePlayerRules, Attacker hub null: {attackerFootprint.Hub is null}, Victim hub null: {victimHub is null}");
Expand All @@ -110,6 +111,7 @@ public static bool CheckFriendlyFirePlayerRules(Footprint attackerFootprint, Ref
{
Player attacker = Player.Get(attackerFootprint.Hub);
Player victim = Player.Get(victimHub);

if (attacker is null || victim is null)
{
Log.Debug($"CheckFriendlyFirePlayerRules, Attacker null: {attacker is null}, Victim null: {victim is null}");
Expand All @@ -124,53 +126,36 @@ public static bool CheckFriendlyFirePlayerRules(Footprint attackerFootprint, Ref

Log.Debug($"CheckFriendlyFirePlayerRules, Attacker role {attacker.Role} and Victim {victim.Role}");

if (!string.IsNullOrEmpty(victim.UniqueRole))
// Check victim's UniqueRole for custom FF multiplier
if (!string.IsNullOrEmpty(victim.UniqueRole) &&
victim.CustomRoleFriendlyFireMultiplier.TryGetValue(victim.UniqueRole, out Dictionary<RoleTypeId, float> victimPairedData) &&
victimPairedData.TryGetValue(attacker.Role, out ffMultiplier))
{
// If 035 is being shot, then we need to check if we are an 035, then check if the attacker is allowed to attack us
if (victim.CustomRoleFriendlyFireMultiplier.Count > 0)
{
if (victim.CustomRoleFriendlyFireMultiplier.TryGetValue(victim.UniqueRole, out Dictionary<RoleTypeId, float> pairedData))
{
if (pairedData.ContainsKey(attacker.Role))
{
ffMultiplier = pairedData[attacker.Role];
return true;
}
}
}
return true;
}
else if (!string.IsNullOrEmpty(attacker.UniqueRole))

// Check attacker's UniqueRole for custom FF multiplier
if (!string.IsNullOrEmpty(attacker.UniqueRole) &&
attacker.CustomRoleFriendlyFireMultiplier.TryGetValue(attacker.UniqueRole, out Dictionary<RoleTypeId, float> attackerPairedData) &&
attackerPairedData.TryGetValue(victim.Role, out ffMultiplier))
{
// If 035 is attacking, whether to allow or disallow based on victim role.
if (attacker.CustomRoleFriendlyFireMultiplier.Count > 0)
{
if (attacker.CustomRoleFriendlyFireMultiplier.TryGetValue(attacker.UniqueRole, out Dictionary<RoleTypeId, float> pairedData))
{
if (pairedData.ContainsKey(victim.Role))
{
ffMultiplier = pairedData[victim.Role];
return true;
}
}
}
return true;
}

// If we're SCP then we need to check if we can attack other SCP, or D-Class, etc. This is default FF logic without unique roles.
if (attacker.FriendlyFireMultiplier.Count > 0)
// Default FF logic for SCP or other roles without unique roles
if (!attacker.FriendlyFireMultiplier.IsEmpty() &&
attacker.FriendlyFireMultiplier.TryGetValue(victim.Role, out ffMultiplier))
{
if (attacker.FriendlyFireMultiplier.TryGetValue(victim.Role, out float ffMulti))
{
ffMultiplier = ffMulti;
return true;
}
return true;
}
}
catch (Exception ex)
{
Log.Error($"CheckFriendlyFirePlayerRules failed to handle friendly fire because: {ex}");
}

return HitboxIdentity.IsEnemy(attackerFootprint.Role, victimHub.roleManager.CurrentRole.RoleTypeId);
// Default to NW logic
return HitboxIdentity.IsDamageable(attackerFootprint.Role, victimHub.roleManager.CurrentRole.RoleTypeId);
}
}

Expand Down Expand Up @@ -226,7 +211,7 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi

int offset = -1;
int index = newInstructions.FindLastIndex(
instruction => instruction.Calls(PropertyGetter(typeof(AttackerDamageHandler), nameof(AttackerDamageHandler.Attacker)))) + offset;
instruction => instruction.LoadsField(Field(typeof(ReferenceHub), nameof(ReferenceHub.networkIdentity)))) + offset;

LocalBuilder ffMulti = generator.DeclareLocal(typeof(float));

Expand All @@ -235,7 +220,7 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi

newInstructions.InsertRange(
index,
new CodeInstruction[]
new[]
{
// Load Attacker (this.Attacker)
new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]),
Expand Down Expand Up @@ -269,7 +254,7 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
// int ffMultiplierIndex = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Ret) + ffMultiplierIndexOffset;
newInstructions.InsertRange(
ffMultiplierIndex,
new CodeInstruction[]
new[]
{
// Do not run our custom logic, skip over.
new(OpCodes.Br, normalProcessing),
Expand Down

0 comments on commit ef52b45

Please sign in to comment.