Skip to content

Commit

Permalink
Merge pull request #2809 from CombatExtended-Continued/ShieldsAndSupp…
Browse files Browse the repository at this point in the history
…resion

Shields and suppresion
  • Loading branch information
N7Huntsman authored Jan 1, 2024
2 parents 544aaef + 465ab52 commit 23f8fd5
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Verse.AI;
using UnityEngine;
using CombatExtended.AI;
using CombatExtended.Compatibility;

namespace CombatExtended
{
Expand Down Expand Up @@ -243,6 +244,10 @@ public void AddSuppression(float amount, IntVec3 origin)
}
}
}
public bool IgnoreSuppresion(IntVec3 origin)
{
return BlockerRegistry.PawnUnsuppresableFromCallback(parent as Pawn, origin) || SuppressionUtility.InterceptorZonesFor((Pawn)parent).Where(x => x.Contains(parent.Position)).Any(x => !x.Contains(origin));
}

public override void CompTick()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,8 @@ protected void ApplySuppression(Pawn pawn, float suppressionMultiplier = 1f)
var compSuppressable = pawn.TryGetComp<CompSuppressable>();
if (compSuppressable != null
&& pawn.Faction != launcher?.Faction
&& (shield == null || shield.ShieldState == ShieldState.Resetting))
&& (shield == null || shield.ShieldState == ShieldState.Resetting)
&& !compSuppressable.IgnoreSuppresion(OriginIV3))
{
suppressionAmount = def.projectile.damageAmountBase * suppressionMultiplier;

Expand Down
29 changes: 18 additions & 11 deletions Source/CombatExtended/CombatExtended/SuppressionUtility.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using CombatExtended.AI;
using CombatExtended.Compatibility;
using CombatExtended.Utilities;
using RimWorld;
using UnityEngine;
Expand All @@ -23,7 +24,7 @@ public static class SuppressionUtility

private static DangerTracker dangerTracker;

private static List<CompProjectileInterceptor> interceptors;
private static IEnumerable<CompProjectileInterceptor> Interceptors(Thing pawn) => pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.ProjectileInterceptor).Select(t => t.TryGetComp<CompProjectileInterceptor>()).Where(x => x.Props.interceptNonHostileProjectiles || !x.parent.HostileTo(pawn));

public static bool TryRequestHelp(Pawn pawn)
{
Expand Down Expand Up @@ -91,7 +92,6 @@ private static bool GetCoverPositionFrom(Pawn pawn, IntVec3 fromPosition, float
{
List<IntVec3> cellList = new List<IntVec3>(GenRadial.RadialCellsAround(pawn.Position, maxDist, true));
IntVec3 bestPos = pawn.Position;
interceptors = pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.ProjectileInterceptor).Select(t => t.TryGetComp<CompProjectileInterceptor>()).ToList();
lightingTracker = pawn.Map.GetLightingTracker();
dangerTracker = pawn.Map.GetDangerTracker();

Expand Down Expand Up @@ -203,14 +203,8 @@ private static float GetCellCoverRatingForPawn(Pawn pawn, IntVec3 cell, IntVec3

cellRating += 10f - (bonusCellRating * 10f);

for (int i = 0; i < interceptors.Count; i++)
{
CompProjectileInterceptor interceptor = interceptors[i];
if (interceptor.Active && interceptor.parent.Position.DistanceTo(cell) < interceptor.Props.radius)
{
cellRating += 15f;
}
}
// If the cell is covered by a shield and there are no enemies inside, then increases by 15 (for each such shield)
cellRating += InterceptorZonesFor(pawn).Where(x => !IsOccupiedByEnemies(x, pawn)).Count(x => x.Contains(cell)) * 15;

// Avoid bullets and other danger sources;
// Yet do not discard cover that is extremely good, even if it may be dangerous
Expand Down Expand Up @@ -246,7 +240,20 @@ private static float GetCellCoverRatingForPawn(Pawn pawn, IntVec3 cell, IntVec3
}
return cellRating;
}

public static IEnumerable<IEnumerable<IntVec3>> InterceptorZonesFor(Pawn pawn)
{
var result = Interceptors(pawn).Where(x => x.Active).Select(x => GenRadial.RadialCellsAround(x.parent.Position, x.Props.radius, true));
var compatibilityZones = BlockerRegistry.ShieldZonesCallback(pawn);
if (compatibilityZones != null)
{
result = result.Union(compatibilityZones);
}
return result;
}
private static bool IsOccupiedByEnemies(IEnumerable<IntVec3> cells, Pawn pawn)
{
return cells.Any(cell => pawn.Map.thingGrid.ThingsListAt(cell).Any(thing => (thing.HostileTo(pawn))));
}
private static float GetCoverRating(Thing cover)
{
// Higher values mean more effective at being considered cover.
Expand Down
57 changes: 54 additions & 3 deletions Source/CombatExtended/Compatibility/BlockerRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ public static class BlockerRegistry
private static bool enabledCFC = false;
private static bool enabledIS = false;
private static bool enabledBCW = false;
private static bool enabledPUF = false;
private static bool enabledSZ = false;
private static List<Func<ProjectileCE, Vector3, Vector3, bool>> checkForCollisionBetweenCallbacks;
private static List<Func<ProjectileCE, IntVec3, Thing, bool>> checkCellForCollisionCallbacks;
private static List<Func<ProjectileCE, Thing, bool>> impactSomethingCallbacks;
private static List<Func<ProjectileCE, Thing, bool>> beforeCollideWithCallbacks;
private static List<Func<Pawn, IntVec3, bool>> pawnUnsuppresableFromCallback;
private static List<Func<Thing, IEnumerable<IEnumerable<IntVec3>>>> shieldZonesCallback;

private static void EnableCB()
{
Expand All @@ -35,6 +39,16 @@ private static void EnableCFC()
enabledCFC = true;
checkCellForCollisionCallbacks = new List<Func<ProjectileCE, IntVec3, Thing, bool>>();
}
private static void EnableSZ()
{
enabledSZ = true;
shieldZonesCallback = new List<Func<Thing, IEnumerable<IEnumerable<IntVec3>>>>();
}
private static void EnablePUF()
{
enabledPUF = true;
pawnUnsuppresableFromCallback = new List<Func<Pawn, IntVec3, bool>>();
}
private static void EnableBCW()
{
enabledBCW = true;
Expand Down Expand Up @@ -90,6 +104,23 @@ public static bool CheckForCollisionBetweenCallback(ProjectileCE projectile, Vec
return false;
}

public static void RegisterShieldZonesCallback(Func<Thing, IEnumerable<IEnumerable<IntVec3>>> f)
{
if (!enabledSZ)
{
EnableSZ();
}
shieldZonesCallback.Add(f);
}
public static void RegisterUnsuppresableFromCallback(Func<Pawn, IntVec3, bool> f)
{
if (!enabledPUF)
{
EnablePUF();
}
pawnUnsuppresableFromCallback.Add(f);
}

public static bool CheckCellForCollisionCallback(ProjectileCE projectile, IntVec3 cell, Thing launcher)
{
if (!enabledCFC)
Expand All @@ -105,7 +136,6 @@ public static bool CheckCellForCollisionCallback(ProjectileCE projectile, IntVec
}
return false;
}

public static bool ImpactSomethingCallback(ProjectileCE projectile, Thing launcher)
{
if (!enabledIS)
Expand All @@ -121,7 +151,29 @@ public static bool ImpactSomethingCallback(ProjectileCE projectile, Thing launch
}
return false;
}

public static IEnumerable<IEnumerable<IntVec3>> ShieldZonesCallback(Thing thing)
{
if (!enabledSZ)
{
return null;
}
return shieldZonesCallback.SelectMany(cb => cb(thing));
}
public static bool PawnUnsuppresableFromCallback(Pawn pawn, IntVec3 origin)
{
if (!enabledPUF)
{
return false;
}
foreach (var cb in pawnUnsuppresableFromCallback)
{
if (cb(pawn, origin))
{
return true;
}
}
return false;
}
public static bool BeforeCollideWithCallback(ProjectileCE projectile, Thing collideWith)
{
if (!enabledBCW)
Expand All @@ -137,7 +189,6 @@ public static bool BeforeCollideWithCallback(ProjectileCE projectile, Thing coll
}
return false;
}

public static Vector3 GetExactPosition(Vector3 origin, Vector3 curPosition, Vector3 shieldPosition, float radiusSq)
{
Vector3 velocity = curPosition - origin;
Expand Down
30 changes: 29 additions & 1 deletion Source/CombatExtended/Compatibility/EDShields.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,12 @@ public void Install()
{
BlockerRegistry.RegisterCheckForCollisionBetweenCallback(EDShields.CheckForCollisionBetweenCallback);
BlockerRegistry.RegisterImpactSomethingCallback(EDShields.ImpactSomethingCallback);
BlockerRegistry.RegisterShieldZonesCallback(EDShields.ShieldZonesCallback);
Type t = Type.GetType("Jaxxa.EnhancedDevelopment.Shields.Shields.ShieldManagerMapComp, ED-Shields");
HitSoundDef = (SoundDef)t.GetField("HitSoundDef", BindingFlags.Static | BindingFlags.Public).GetValue(null);
}


public IEnumerable<string> GetCompatList()
{
yield break;
Expand Down Expand Up @@ -84,7 +87,6 @@ public static bool CheckForCollisionBetweenCallback(ProjectileCE projectile, Vec
continue;
}

int fieldRadiusSq = fieldRadius * fieldRadius;
Quaternion shieldProjAng = Quaternion.LookRotation(from - shieldPosition2D);
if ((Quaternion.Angle(targetAngle, shieldProjAng) > 90))
{
Expand Down Expand Up @@ -156,5 +158,31 @@ public static void getShields(Map map)
}
}

private static IEnumerable<IEnumerable<IntVec3>> ShieldZonesCallback(Thing pawnToSuppress)
{
Map map = pawnToSuppress.Map;
getShields(map);
List<IEnumerable<IntVec3>> result = new List<IEnumerable<IntVec3>>();
foreach (Building building in shields)
{
var shield = building as Building_Shield;
var generator = shield.GetComp<Comp_ShieldGenerator>();
bool isActive = generator.IsActive();
if (!isActive)
{
continue;
}
bool blockDirect = generator.BlockDirect_Active();
if (!blockDirect)
{
continue;
}
//Is there no shields that doesn't intercept ingoing friendly projectiles?
int fieldRadius = (int)generator.FieldRadius_Active();
result.Add(GenRadial.RadialCellsAround(shield.Position, fieldRadius, true));
}
return result;
}

}
}
23 changes: 23 additions & 0 deletions Source/CombatExtended/Compatibility/Rimatomics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public void Install()
{
BlockerRegistry.RegisterCheckForCollisionBetweenCallback(Rimatomics.CheckForCollisionBetweenCallback);
BlockerRegistry.RegisterImpactSomethingCallback(Rimatomics.ImpactSomethingCallback);
BlockerRegistry.RegisterShieldZonesCallback(Rimatomics.ShieldZonesCallback);
}

public IEnumerable<string> GetCompatList()
Expand Down Expand Up @@ -149,6 +150,28 @@ public static bool ImpactSomethingCallback(ProjectileCE projectile, Thing launch
return false;
}

private static IEnumerable<IEnumerable<IntVec3>> ShieldZonesCallback(Thing pawnToSuppress)
{
Map map = pawnToSuppress.Map;
getShields(map);
List<IEnumerable<IntVec3>> result = new List<IEnumerable<IntVec3>>();
foreach (CompRimatomicsShield shield in shields)
{
if (!shield.Active || shield.ShieldState != ShieldState.Active)
{
continue;
}
if (GenHostility.HostileTo(pawnToSuppress, shield.parent) && !shield.debugInterceptNonHostileProjectiles && !shield.Props.interceptNonHostileProjectiles)
{
// Avoid hostile shields because they aren't intercepting friendly projectiles
continue;
}

int fieldRadius = (int)shield.Radius;
result.Add(GenRadial.RadialCellsAround(shield.parent.Position, fieldRadius, true));
}
return result;
}

public static void getShields(Map map)
{
Expand Down
21 changes: 21 additions & 0 deletions Source/CombatExtended/Compatibility/VanillaExpandedFramework.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,28 @@ IEnumerable<string> IPatch.GetCompatList()
void IPatch.Install()
{
BlockerRegistry.RegisterCheckForCollisionCallback(CheckIntercept);
BlockerRegistry.RegisterShieldZonesCallback(ShieldZonesCallback);
}

private IEnumerable<IEnumerable<IntVec3>> ShieldZonesCallback(Thing pawnToSuppress)
{
IEnumerable<CompShieldField> interceptors = CompShieldField.ListerShieldGensActiveIn(pawnToSuppress.Map).ToList();
List<IEnumerable<IntVec3>> result = new List<IEnumerable<IntVec3>>();
if (!interceptors.Any())
{
return result;
}
foreach (var interceptor in interceptors)
{
if (!interceptor.CanFunction)
{
continue;
}
result.Add(GenRadial.RadialCellsAround(interceptor.HostThing.Position, interceptor.ShieldRadius, true));
}
return result;
}

private static bool CheckIntercept(ProjectileCE projectile, IntVec3 cell, Thing launcher)
{
if (projectile.def.projectile.flyOverhead)
Expand Down
23 changes: 23 additions & 0 deletions Source/CombatExtended/Compatibility/VanillaPsycastExpanded.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,35 @@ public IEnumerable<string> GetCompatList()
}
public void Install()
{

BlockerRegistry.RegisterImpactSomethingCallback(ImpactSomething); //temp commented
BlockerRegistry.RegisterBeforeCollideWithCallback(BeforeCollideWith);
BlockerRegistry.RegisterCheckForCollisionCallback(Hediff_Overshield_InterceptCheck);
BlockerRegistry.RegisterCheckForCollisionBetweenCallback(AOE_CheckIntercept);
BlockerRegistry.RegisterShieldZonesCallback(ShieldZones);
BlockerRegistry.RegisterUnsuppresableFromCallback(Unsuppresable);
}
private static Dictionary<Map, IEnumerable<IEnumerable<IntVec3>>> shieldZones;
private static int shieldZonesCacheTick = -1;
private static IEnumerable<IEnumerable<IntVec3>> ShieldZones(Thing thing)
{
IEnumerable<IEnumerable<IntVec3>> result = null;
var currentTick = GenTicks.TicksGame;
if (shieldZonesCacheTick != currentTick)
{
shieldZonesCacheTick = currentTick;
shieldZones = new Dictionary<Map, IEnumerable<IEnumerable<IntVec3>>>();
}
if (!shieldZones.TryGetValue(thing.Map, out result))
{
result = thing.Map.listerThings.ThingsInGroup(ThingRequestGroup.Pawn).Cast<Pawn>().SelectMany(x => x.health.hediffSet.hediffs).Where(x => x is Hediff_Overshield).Select(x => { var ho = x as Hediff_Overshield; return GenRadial.RadialCellsAround(ho.pawn.Position, ho.OverlaySize, true); }).ToList();
shieldZones.Add(thing.Map, result);
}
return result;
}

private static bool Unsuppresable(Pawn pawn, IntVec3 origin) => pawn.health.hediffSet.hediffs.Any(x => x.GetType() == typeof(Hediff_Overshield));

private static bool BeforeCollideWith(ProjectileCE projectile, Thing collideWith)
{
if (collideWith is Pawn pawn)
Expand Down

0 comments on commit 23f8fd5

Please sign in to comment.