Skip to content

Friendly fire update #33

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

Merged
merged 16 commits into from
Nov 18, 2024
Merged
Changes from all 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
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