Skip to content

Commit

Permalink
Show shooters who are blocked and friendlies that are blocking them i…
Browse files Browse the repository at this point in the history
…n cyan and green respectively on the map and colonist bar.
  • Loading branch information
Falconne committed Mar 14, 2019
1 parent ad53910 commit 29f901f
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 10 deletions.
6 changes: 6 additions & 0 deletions mod-structure/Defs/UpdateFeatureDefs/UpdateFeatureDefs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,10 @@
<assemblyVersion>1.0.3</assemblyVersion>
<content>In Rimworld 1.x, low skill shooters have a larger miss radius than higher skilled ones. This mod now accounts for that. This can be turned off in mod settings to revert to the fixed "one-tile miss radius" assumption, but that may result in friendly fire hits.</content>
</HugsLib.UpdateFeatureDef>

<HugsLib.UpdateFeatureDef ParentName="UpdateFeatureBase">
<defName>AvoidFriendlyFire_1_0_4</defName>
<assemblyVersion>1.0.4</assemblyVersion>
<content>Shooters who are being blocked by friendlies (but would otherwise have a target) will now have their name on the map and in the Colonist Bar be written in cyan. Likewise, the first friendly blocking any shooter will show up in green.</content>
</HugsLib.UpdateFeatureDef>
</Defs>
4 changes: 4 additions & 0 deletions src/AvoidFriendlyFire/AvoidFriendlyFire.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,15 @@
<Compile Include="FireProperties.cs" />
<Compile Include="Main.cs" />
<Compile Include="Patches\AttackTargetFinder_BestAttackTarget_Patch.cs" />
<Compile Include="Patches\TooltipUtility_ShotCalculationTipString_Patch.cs" />
<Compile Include="Patches\PawnNameColorUtility_PawnNameColorOf_Patch.cs" />
<Compile Include="Patches\Pawn_DraftController_GetGizmos_Patch.cs" />
<Compile Include="Patches\Pawn_DraftController_set_Drafted_Patch.cs" />
<Compile Include="Patches\Pawn_Kill_Patch.cs" />
<Compile Include="Patches\Targeter_TargeterUpdate_Patch.cs" />
<Compile Include="Patches\Verb_CanHitTargetFrom_Patch.cs" />
<Compile Include="PawnStatus.cs" />
<Compile Include="PawnStatusTracker.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources.cs" />
</ItemGroup>
Expand Down
12 changes: 12 additions & 0 deletions src/AvoidFriendlyFire/FireManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,23 @@ namespace AvoidFriendlyFire
{
public class FireManager
{
public bool SkipNextCheck;

private readonly Dictionary<int, Dictionary<int, CachedFireCone>> _cachedFireCones
= new Dictionary<int, Dictionary<int, CachedFireCone>>();

private int _lastCleanupTick;

public bool CanHitTargetSafely(FireProperties fireProperties)
{
if (SkipNextCheck)
{
SkipNextCheck = false;
return true;
}

Main.Instance.PawnStatusTracker.Remove(fireProperties.Caster);

HashSet<int> fireCone = GetOrCreatedCachedFireConeFor(fireProperties);
if (fireCone == null)
return true;
Expand Down Expand Up @@ -52,6 +62,8 @@ public bool CanHitTargetSafely(FireProperties fireProperties)
if (IsPawnWearingUsefulShield(pawn))
continue;

Main.Instance.PawnStatusTracker.AddBlockedShooter(fireProperties.Caster, pawn);

return false;
}

Expand Down
13 changes: 6 additions & 7 deletions src/AvoidFriendlyFire/FireProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class FireProperties
{
public IntVec3 Target;

public Map CasterMap => _caster.Map;
public Map CasterMap => Caster.Map;

public IntVec3 Origin;

Expand All @@ -30,17 +30,16 @@ public class FireProperties

public int TargetIndex => CasterMap.cellIndices.CellToIndex(Target);


private readonly Thing _caster;
public Pawn Caster { get; }

private readonly Verb _weaponVerb;

public FireProperties(Pawn caster, IntVec3 target)
{
Target = target;
_caster = caster;
Caster = caster;
_weaponVerb = GetEquippedWeaponVerb(caster);
Origin = _caster.Position;
Origin = Caster.Position;
}

public bool ArePointsVisibleAndValid()
Expand Down Expand Up @@ -78,13 +77,13 @@ public float GetAimOnTargetChance()
{
var distance = (Target - Origin).LengthHorizontal;

var factorFromShooterAndDist = ShotReport.HitFactorFromShooter(_caster, distance);
var factorFromShooterAndDist = ShotReport.HitFactorFromShooter(Caster, distance);

var factorFromEquipment = _weaponVerb.verbProps.GetHitChanceFactor(
_weaponVerb.EquipmentSource, distance);

var factorFromWeather = 1f;
if (!_caster.Position.Roofed(CasterMap) || !Target.Roofed(CasterMap))
if (!Caster.Position.Roofed(CasterMap) || !Target.Roofed(CasterMap))
{
factorFromWeather = CasterMap.weatherManager.CurWeatherAccuracyMultiplier;
}
Expand Down
4 changes: 4 additions & 0 deletions src/AvoidFriendlyFire/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class Main : HugsLib.ModBase

private ExtendedDataStorage _extendedDataStorage;

public PawnStatusTracker PawnStatusTracker { get; } = new PawnStatusTracker();

private FireManager _fireManager;

private SettingHandle<bool> _showOverlay;
Expand Down Expand Up @@ -47,6 +49,7 @@ public override void Tick(int currentTick)
if (!IsModEnabled())
return;
_fireManager?.RemoveExpiredCones(currentTick);
PawnStatusTracker.RemoveExpired();
}

public override void WorldLoaded()
Expand All @@ -64,6 +67,7 @@ public override void MapLoaded(Map map)
base.MapLoaded(map);
_fireManager = new FireManager();
_fireConeOverlay = new FireConeOverlay();
PawnStatusTracker.Reset();
}

public override void DefsLoaded()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Harmony;
using UnityEngine;
using Verse;

namespace AvoidFriendlyFire
{
[HarmonyPatch(typeof(PawnNameColorUtility), "PawnNameColorOf")]
public class PawnNameColorUtility_PawnNameColorOf_Patch
{
public static void Postfix(ref Pawn pawn, ref Color __result)
{
if (!Main.Instance.IsModEnabled())
return;

if (Main.Instance.PawnStatusTracker.IsAShooter(pawn))
{
__result = Color.cyan;
return;
}

if (Main.Instance.PawnStatusTracker.IsABlocker(pawn))
{
__result = Color.green;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ public class Pawn_DraftController_set_Drafted_Patch
{
public static void Postfix(Pawn_DraftController __instance, bool value)
{
if (!Main.Instance.ShouldEnableWhenUndrafted())
return;

if (value)
return;

Expand All @@ -22,6 +19,11 @@ public static void Postfix(Pawn_DraftController __instance, bool value)
if (!extendedDataStore.CanTrackPawn(pawn))
return;

Main.Instance.PawnStatusTracker.Remove(pawn);

if (!Main.Instance.ShouldEnableWhenUndrafted())
return;

var pawnData = extendedDataStore.GetExtendedDataFor(pawn);
pawnData.AvoidFriendlyFire = true;
}
Expand Down
2 changes: 2 additions & 0 deletions src/AvoidFriendlyFire/Patches/Pawn_Kill_Patch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public static void Postfix(ref Pawn __instance)
if (!__instance.Dead)
return;

Main.Instance.PawnStatusTracker.KillOff(__instance);

Main.Instance.GetExtendedDataStorage().DeleteExtendedDataFor(__instance);

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Harmony;
using Verse;

namespace AvoidFriendlyFire
{
[HarmonyPatch(typeof(TooltipUtility), "ShotCalculationTipString")]
public class TooltipUtility_ShotCalculationTipString_Patch
{
public static bool Prefix(ref Thing target)
{
if (Find.Selector.SingleSelectedThing is Pawn pawn)
{
if (pawn != target && pawn.equipment?.Primary != null
&& pawn.equipment.PrimaryEq.PrimaryVerb is Verb_LaunchProjectile)
{
Main.Instance.GetFireManager().SkipNextCheck = true;
}
}

return true;
}
}
}
31 changes: 31 additions & 0 deletions src/AvoidFriendlyFire/PawnStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Collections.Generic;
using Verse;

namespace AvoidFriendlyFire
{
public class PawnStatus
{
public readonly Pawn Shooter;

public readonly Pawn Blocker;

private int _expiryTime;

public PawnStatus(Pawn shooter, Pawn blocker)
{
Shooter = shooter;
Blocker = blocker;
Refresh();
}

public void Refresh()
{
_expiryTime = Find.TickManager.TicksGame + 20;
}

public bool IsExpired()
{
return Find.TickManager.TicksGame >= _expiryTime;
}
}
}
52 changes: 52 additions & 0 deletions src/AvoidFriendlyFire/PawnStatusTracker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Collections.Generic;
using System.Linq;
using Verse;

namespace AvoidFriendlyFire
{
public class PawnStatusTracker
{
private readonly List<PawnStatus> _shooters = new List<PawnStatus>();

public void AddBlockedShooter(Pawn shooter, Pawn blocker)
{
var existingEntry = _shooters.FirstOrDefault(ps => ps.Shooter == shooter);
if (existingEntry != null)
{
existingEntry.Refresh();
return;
}
_shooters.Add(new PawnStatus(shooter, blocker));
}

public bool IsAShooter(Pawn pawn)
{
return _shooters.Any(ps => ps.Shooter == pawn);
}

public bool IsABlocker(Pawn pawn)
{
return _shooters.Any(ps => ps.Blocker == pawn);
}

public void KillOff(Pawn pawn)
{
_shooters.RemoveAll(ps => ps.Shooter == pawn || ps.Blocker == pawn);
}

public void Remove(Pawn pawn)
{
_shooters.RemoveAll(ps => ps.Shooter == pawn);
}

public void RemoveExpired()
{
_shooters.RemoveAll(ps => ps.IsExpired());
}

public void Reset()
{
_shooters.Clear();
}
}
}

0 comments on commit 29f901f

Please sign in to comment.