diff --git a/About/About.xml b/About/About.xml
index 11c9d18..56a295e 100644
--- a/About/About.xml
+++ b/About/About.xml
@@ -4,5 +4,5 @@
XeoNovaDan
https://ludeon.com/forums/index.php?topic=29503.0
0.19.0
- Current Version: v1.0.6 (24th September 2018)\n\nV.A.T.S for RimWorld! Allow your colonists, obedient animals and even some raiders to prioritize targeting certain body part groups of their enemies. Shoot those heads off in style!
+ Current Version: v1.1 (25th September 2018)\n\nV.A.T.S for RimWorld! Allow your colonists, obedient animals and even some raiders to prioritize targeting certain body part groups of their enemies. Shoot those heads off in style!
\ No newline at end of file
diff --git a/About/ModSync.xml b/About/ModSync.xml
index 07981d4..1c65652 100644
--- a/About/ModSync.xml
+++ b/About/ModSync.xml
@@ -2,7 +2,7 @@
6ff764b2-16e6-400f-be30-c004b847f984
[XND] Targeting Modes
- 1.0.6
+ 1.1
False
XeoNovaDan
diff --git a/Assemblies/1SettingsHelper.dll b/Assemblies/1SettingsHelper.dll
new file mode 100644
index 0000000..a11a867
Binary files /dev/null and b/Assemblies/1SettingsHelper.dll differ
diff --git a/Assemblies/TargetingModes.dll b/Assemblies/TargetingModes.dll
index df9ff41..146a708 100644
Binary files a/Assemblies/TargetingModes.dll and b/Assemblies/TargetingModes.dll differ
diff --git a/Languages/English/Keyed/GameplayCommands.xml b/Languages/English/Keyed/GameplayCommands.xml
deleted file mode 100644
index 19b28bf..0000000
--- a/Languages/English/Keyed/GameplayCommands.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- Set targeting mode
- Targeting: {0}
- Determine which targeting mode the pawn should use.
-
-
\ No newline at end of file
diff --git a/Languages/English/Keyed/Keys.xml b/Languages/English/Keyed/Keys.xml
new file mode 100644
index 0000000..9e814bb
--- /dev/null
+++ b/Languages/English/Keyed/Keys.xml
@@ -0,0 +1,27 @@
+
+
+
+ Targeting Modes
+ Accuracy penalties
+ Whether or not targeting modes have an effect on the accuracy of a pawn's attacks.
+
+ Targeting mode resetting frequency
+ Never
+ 1d
+ 12h
+ 6h
+ 3h
+ 1h
+
+ Hostile NPCs use Targeting Modes
+ Whether or not any hostile NPCs are able to use targeting modes other than general.
+ Minimum weapon skill for raiders
+ Chance for mechanoids
+ Base chance for manhunters
+
+
+ Set targeting mode
+ Targeting: {0}
+ Determine which targeting mode the pawn should use.
+
+
\ No newline at end of file
diff --git a/Source/TargetingModes/.vs/TargetingModes/v15/.suo b/Source/TargetingModes/.vs/TargetingModes/v15/.suo
index 29e3d85..da2e976 100644
Binary files a/Source/TargetingModes/.vs/TargetingModes/v15/.suo and b/Source/TargetingModes/.vs/TargetingModes/v15/.suo differ
diff --git a/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide b/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide
index 5f90bbb..4071c93 100644
Binary files a/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide and b/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide differ
diff --git a/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide-shm b/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide-shm
index 4cd7655..e1c3bc3 100644
Binary files a/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide-shm and b/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide-shm differ
diff --git a/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide-wal b/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide-wal
index 1d5c122..3f4da50 100644
Binary files a/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide-wal and b/Source/TargetingModes/.vs/TargetingModes/v15/Server/sqlite3/storage.ide-wal differ
diff --git a/Source/TargetingModes/Command_SetTargetingMode.cs b/Source/TargetingModes/Command_SetTargetingMode.cs
index c75d8ac..3ad7b82 100644
--- a/Source/TargetingModes/Command_SetTargetingMode.cs
+++ b/Source/TargetingModes/Command_SetTargetingMode.cs
@@ -59,8 +59,8 @@ public override void ProcessInput(Event ev)
private string FloatMenuLabel(TargetingModeDef targetingMode)
{
string label = targetingMode.LabelCap;
- if (targetingMode.hitChanceFactor != 1f)
- label += $" (x{targetingMode.hitChanceFactor.ToStringPercent()} Acc)";
+ if (targetingMode.HitChanceFactor != 1f)
+ label += $" (x{targetingMode.HitChanceFactor.ToStringPercent()} Acc)";
return label;
}
diff --git a/Source/TargetingModes/CompTargetingMode.cs b/Source/TargetingModes/CompTargetingMode.cs
index 98bccc5..b254f69 100644
--- a/Source/TargetingModes/CompTargetingMode.cs
+++ b/Source/TargetingModes/CompTargetingMode.cs
@@ -4,6 +4,7 @@
using System.Text;
using UnityEngine;
using Verse;
+using Verse.AI;
using RimWorld;
namespace TargetingModes
@@ -25,13 +26,64 @@ public override void CompTick()
{
base.CompTick();
// Debugging
- //if (Find.TickManager.TicksGame % (GenTicks.TicksPerRealSecond * 4) == 0)
- // Log.Message(this.ToString());
+ if (Find.TickManager.TicksGame % (GenTicks.TicksPerRealSecond * 4) == 0)
+ Log.Message(this.ToString());
// For compatibility with existing saves
- if (_targetingMode == null)
+ if (_targetingMode == null || CanResetTargetingMode())
_targetingMode = TargetingModesUtility.DefaultTargetingMode;
}
+ public bool CanResetTargetingMode()
+ {
+ // Non-player world pawns are exempt to player restrictions
+ if (parent.Faction != Faction.OfPlayer && parent.Map == null)
+ return Find.TickManager.TicksGame % TargModeResetAttemptInterval(3) == 0;
+
+ // If player's set it to never reset, if it isn't time to update or if it's already been reset
+ if (TargetingModesSettings.TargModeResetFrequencyInt == 0 ||
+ Find.TickManager.TicksGame % TargModeResetAttemptInterval(TargetingModesSettings.TargModeResetFrequencyInt) != 0 ||
+ _targetingMode == TargetingModesUtility.DefaultTargetingMode)
+ return false;
+
+ // Not super efficient code, but legibility's the priority
+ if (Pawn != null)
+ {
+ if (Pawn.drafter?.Drafted == false)
+ return true;
+ if (!GenAI.InDangerousCombat(Pawn))
+ return true;
+ }
+ if (parent is Building_TurretGun turret)
+ {
+ if (turret.CurrentTarget == null)
+ return true;
+ }
+
+ return false;
+ }
+
+ private static int TargModeResetAttemptInterval(int freqInt)
+ {
+ switch (freqInt)
+ {
+ // 1 = 1d
+ case 1:
+ return GenDate.TicksPerDay;
+ // 2 = 12h
+ case 2:
+ return GenDate.TicksPerHour * 12;
+ // 3 = 6h
+ case 3:
+ return GenDate.TicksPerHour * 6;
+ // 4 = 3h
+ case 4:
+ return GenDate.TicksPerHour * 3;
+ // other (5) = 1h
+ default:
+ return GenDate.TicksPerHour;
+ };
+ }
+
public override void PostExposeData()
{
base.PostExposeData();
diff --git a/Source/TargetingModes/HarmonyPatches.cs b/Source/TargetingModes/HarmonyPatches.cs
index 83447f3..8461b04 100644
--- a/Source/TargetingModes/HarmonyPatches.cs
+++ b/Source/TargetingModes/HarmonyPatches.cs
@@ -22,9 +22,13 @@ static HarmonyPatches()
{
HarmonyInstance h = HarmonyInstance.Create("XeoNovaDan.TargetingModes");
+ #region Patches
h.Patch(AccessTools.Method(typeof(PawnGroupMakerUtility), nameof(PawnGroupMakerUtility.GeneratePawns)),
postfix: new HarmonyMethod(patchType, nameof(Postfix_GeneratePawns)));
+ h.Patch(AccessTools.Method(typeof(ManhunterPackIncidentUtility), nameof(ManhunterPackIncidentUtility.GenerateAnimals)),
+ postfix: new HarmonyMethod(patchType, nameof(Postfix_GenerateAnimals)));
+
h.Patch(AccessTools.Method(typeof(Pawn), nameof(Pawn.GetGizmos)),
postfix: new HarmonyMethod(patchType, nameof(Postfix_GetGizmos)));
@@ -54,6 +58,7 @@ static HarmonyPatches()
h.Patch(AccessTools.Method(typeof(CompSpawnerMechanoidsOnDamaged), "TrySpawnMechanoids"),
transpiler: new HarmonyMethod(patchType, nameof(Transpile_TrySpawnMechanoids)));
+ #endregion
}
@@ -69,7 +74,7 @@ private static IEnumerable ModifiedPawnGroup(IEnumerable result, Paw
foreach (Pawn pawn in result)
{
if ((pawn.RaceProps.Humanlike && parms.raidStrategy == TM_RaidStrategyDefOf.ImmediateAttackSmart && pawn.IsCompetentWithWeapon()) ||
- (pawn.RaceProps.IsMechanoid && Rand.Chance(TargetingModesUtility.MechanoidRandomTargetingModeChance)))
+ (pawn.RaceProps.IsMechanoid && Rand.Chance(TargetingModesSettings.mechanoidTargModeChance)))
{
// Validation for CompTargetingMode is done within this method
pawn.TryAssignRandomTargetingMode();
@@ -79,6 +84,26 @@ private static IEnumerable ModifiedPawnGroup(IEnumerable result, Paw
}
#endregion
+ #region Postfix_GenerateAnimals
+ public static void Postfix_GenerateAnimals(ref List __result)
+ {
+ __result = ModifiedAnimalGroup(__result).ToList();
+ }
+
+ private static IEnumerable ModifiedAnimalGroup(List result)
+ {
+ if (!result.NullOrEmpty())
+ foreach (Pawn pawn in result)
+ {
+ if (Rand.Chance(TargetingModesUtility.AdjustedChanceForAnimal(pawn)))
+ {
+ pawn.TryAssignRandomTargetingMode();
+ }
+ yield return pawn;
+ }
+ }
+ #endregion
+
#region Postfix_GetGizmos
public static void Postfix_GetGizmos(Pawn __instance, ref IEnumerable __result)
{
@@ -103,13 +128,13 @@ private static bool IsPlayerControlledAnimal(this Pawn pawn) =>
public static void Postfix_HitFactorFromShooter(ref float __result, Thing caster)
{
if (caster.TryGetComp() is CompTargetingMode targetingComp)
- __result = Mathf.Max(__result * targetingComp.GetTargetingMode().hitChanceFactor, ShootTuning.MinAccuracyFactorFromShooterAndDistance);
+ __result = Mathf.Max(__result * targetingComp.GetTargetingMode().HitChanceFactor, ShootTuning.MinAccuracyFactorFromShooterAndDistance);
}
public static void Postfix_GetNonMissChance(Verb_MeleeAttack __instance, ref float __result)
{
if (__instance.caster is Thing caster && caster.TryGetComp() is CompTargetingMode targetingComp && __result == caster.GetStatValue(StatDefOf.MeleeHitChance))
- __result *= __result * targetingComp.GetTargetingMode().hitChanceFactor;
+ __result *= __result * targetingComp.GetTargetingMode().HitChanceFactor;
}
#endregion
@@ -196,7 +221,7 @@ private static bool IsTheInstructionIAmLookingFor(this CodeInstruction instructi
private static void TryAssignRandomTargetingModeMechanoid(this Pawn pawn)
{
- if (Rand.Chance(TargetingModesUtility.MechanoidRandomTargetingModeChance))
+ if (Rand.Chance(TargetingModesSettings.mechanoidTargModeChance))
pawn.TryAssignRandomTargetingMode();
}
#endregion
diff --git a/Source/TargetingModes/Properties/AssemblyInfo.cs b/Source/TargetingModes/Properties/AssemblyInfo.cs
index 2a24a21..7ed5ddd 100644
--- a/Source/TargetingModes/Properties/AssemblyInfo.cs
+++ b/Source/TargetingModes/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.6.0")]
+[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Source/TargetingModes/TargetingModeDef.cs b/Source/TargetingModes/TargetingModeDef.cs
index 56107af..ba367fb 100644
--- a/Source/TargetingModes/TargetingModeDef.cs
+++ b/Source/TargetingModes/TargetingModeDef.cs
@@ -14,6 +14,9 @@ public class TargetingModeDef : Def
public bool HasNoSpecifiedPartDetails =>
parts.NullOrEmpty() && partsOrAnyChildren.NullOrEmpty() && tags.NullOrEmpty();
+ public float HitChanceFactor =>
+ (TargetingModesSettings.accuracyPenalties) ? hitChanceFactor : 1f;
+
public bool PartsListContains(BodyPartDef def) => !parts.NullOrEmpty() && parts.Contains(def);
public bool PartsOrAnyChildrenListContains(BodyPartRecord part)
diff --git a/Source/TargetingModes/TargetingModes.csproj b/Source/TargetingModes/TargetingModes.csproj
index 561be9a..81e7b0b 100644
--- a/Source/TargetingModes/TargetingModes.csproj
+++ b/Source/TargetingModes/TargetingModes.csproj
@@ -34,6 +34,11 @@
..\..\Assemblies\0Harmony.dll
False
+
+ False
+ ..\..\Assemblies\1SettingsHelper.dll
+ False
+
references\AbilityUser.dll
False
@@ -61,6 +66,7 @@
+
diff --git a/Source/TargetingModes/TargetingModesSettings.cs b/Source/TargetingModes/TargetingModesSettings.cs
new file mode 100644
index 0000000..a981b2c
--- /dev/null
+++ b/Source/TargetingModes/TargetingModesSettings.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UnityEngine;
+using Verse;
+using RimWorld;
+using SettingsHelper;
+
+namespace TargetingModes
+{
+ public class TargetingModesSettings : ModSettings
+ {
+
+ public static bool accuracyPenalties = true;
+ #region TargModeResetFrequencyInt
+ private static float targModeResetFrequencyInt = 3f;
+ public static int TargModeResetFrequencyInt =>
+ (int)targModeResetFrequencyInt;
+ #endregion
+ public static bool raidersUseTargModes = true;
+ #region MinimumSkillForRandomTargetingMode
+ private static float raiderMinSkillForTargMode = 8f;
+ public static int MinimumSkillForRandomTargetingMode =>
+ (int)raiderMinSkillForTargMode;
+ #endregion
+ public static float mechanoidTargModeChance = 0.35f;
+ public static float baseManhunterTargModeChance = 0.2f;
+
+ public void DoWindowContents(Rect wrect)
+ {
+ Listing_Standard options = new Listing_Standard();
+ Color defaultColor = GUI.color;
+ options.Begin(wrect);
+
+ GUI.color = defaultColor;
+ Text.Font = GameFont.Small;
+ Text.Anchor = TextAnchor.UpperLeft;
+ options.Gap();
+ // General settings
+ options.CheckboxLabeled("Settings_AccuracyPenalties".Translate(), ref accuracyPenalties, "Settings_AccuracyPenalties_Tooltip".Translate());
+ options.Gap();
+ options.AddLabeledSlider("Settings_TargModeResetFrequency".Translate(), ref targModeResetFrequencyInt, 0, 5,
+ rightAlignedLabel: $"Settings_TargModeResetFrequency_{targModeResetFrequencyInt}".Translate(), roundTo: 1);
+ options.GapLine(24);
+
+ // Settings for AI
+ options.CheckboxLabeled("Settings_RaidersUseTargetingModes".Translate(), ref raidersUseTargModes, "Settings_RaidersUseTargetingModes_Tooltip".Translate());
+ options.Gap();
+
+ // Grey out this section if raiders can't use targeting modes
+ if (!raidersUseTargModes)
+ GUI.color = Color.grey;
+
+ options.AddLabeledSlider("Settings_MinRaiderWeaponSkill".Translate(), ref raiderMinSkillForTargMode, 0, 20,
+ rightAlignedLabel: raiderMinSkillForTargMode.ToString(), roundTo: 1);
+ options.Gap();
+ options.AddLabeledSlider("Settings_MechTargModeChance".Translate(), ref mechanoidTargModeChance, 0, 1,
+ rightAlignedLabel: mechanoidTargModeChance.ToStringPercent(), roundTo: 0.01f);
+ options.Gap();
+ options.AddLabeledSlider("Settings_BaseManhunterTargModeChance".Translate(), ref baseManhunterTargModeChance, 0, 1,
+ rightAlignedLabel: baseManhunterTargModeChance.ToStringPercent(), roundTo: 0.01f);
+ // End of section
+ GUI.color = defaultColor;
+
+ options.End();
+
+ Mod.GetSettings().Write();
+
+ }
+
+ public override void ExposeData()
+ {
+ Scribe_Values.Look(ref accuracyPenalties, "accuracyPenalties", true);
+ Scribe_Values.Look(ref raidersUseTargModes, "raidersUseTargModes", true);
+ Scribe_Values.Look(ref raiderMinSkillForTargMode, "raiderMinSkillForTargMode", 8f);
+ Scribe_Values.Look(ref mechanoidTargModeChance, "mechanoidTargModeChance", 0.35f);
+ Scribe_Values.Look(ref baseManhunterTargModeChance, "baseManhunterTargModeChance", 0.2f);
+ }
+
+ }
+
+ public class TargetingModes : Mod
+ {
+ public TargetingModesSettings settings;
+
+ public TargetingModes(ModContentPack content) : base(content)
+ {
+ GetSettings();
+ }
+
+ public override string SettingsCategory() => "TargetingModesSettingsCategory".Translate();
+
+ public override void DoSettingsWindowContents(Rect inRect)
+ {
+ GetSettings().DoWindowContents(inRect);
+ }
+ }
+}
diff --git a/Source/TargetingModes/TargetingModesUtility.cs b/Source/TargetingModes/TargetingModesUtility.cs
index 6064bd6..696eafc 100644
--- a/Source/TargetingModes/TargetingModesUtility.cs
+++ b/Source/TargetingModes/TargetingModesUtility.cs
@@ -5,7 +5,6 @@
using UnityEngine;
using Verse;
using RimWorld;
-using AbilityUser;
namespace TargetingModes
{
@@ -13,8 +12,7 @@ public static class TargetingModesUtility
{
public static TargetingModeDef DefaultTargetingMode = TargetingModeDefOf.Standard;
- public const int MinimumSkillForRandomTargetingMode = 8;
- public const float MechanoidRandomTargetingModeChance = 0.35f;
+ private const float TargModeChanceFactorOffsetPerTrainabilityOrder = 0.05f;
public static Command_SetTargetingMode SetTargetModeCommand(ITargetModeSettable settable) =>
new Command_SetTargetingMode
@@ -36,7 +34,7 @@ public static bool CanUseTargetingModes(this ThingDef weapon, Thing instigator)
if (instigator == null || !instigator.def.HasComp(typeof(CompTargetingMode)) || weapon == null)
return false;
- if (weapon.GetType().IsAssignableFrom(typeof(ProjectileDef_Ability)))
+ if (weapon.GetType().IsAssignableFrom(typeof(AbilityUser.ProjectileDef_Ability)))
return true;
if (weapon.thingClass.IsAssignableFrom(typeof(Pawn)) || weapon.IsMeleeWeapon)
return true;
@@ -98,19 +96,29 @@ public static bool IsCompetentWithWeapon(this Pawn pawn)
if (pawn.skills == null || pawn.equipment == null)
return false;
- if (pawn.equipment.Primary?.def.IsRangedWeapon == true && pawn.skills.GetSkill(SkillDefOf.Shooting).Level >= MinimumSkillForRandomTargetingMode)
+ if (pawn.equipment.Primary?.def.IsRangedWeapon == true && pawn.skills.GetSkill(SkillDefOf.Shooting).Level >= TargetingModesSettings.MinimumSkillForRandomTargetingMode)
return true;
- return pawn.skills.GetSkill(SkillDefOf.Melee).Level >= MinimumSkillForRandomTargetingMode;
+ return pawn.skills.GetSkill(SkillDefOf.Melee).Level >= TargetingModesSettings.MinimumSkillForRandomTargetingMode;
}
public static void TryAssignRandomTargetingMode(this Pawn pawn)
{
- if (pawn.TryGetComp() is CompTargetingMode targetingComp)
+ if (TargetingModesSettings.raidersUseTargModes && pawn.TryGetComp() is CompTargetingMode targetingComp)
{
TargetingModeDef newTargetingMode = DefDatabase.AllDefsListForReading.RandomElementByWeight(t => t.commonality);
targetingComp.SetTargetingMode(newTargetingMode);
}
}
+ public static float AdjustedChanceForAnimal(Pawn animal)
+ {
+ int orderOverIntermediate = animal.RaceProps.trainability.intelligenceOrder - TrainabilityDefOf.Intermediate.intelligenceOrder;
+
+ // Animal needs at least intermediate intelligence to use targeting modes
+ if (orderOverIntermediate >= 0)
+ return TargetingModesSettings.baseManhunterTargModeChance * (1 + orderOverIntermediate * TargModeChanceFactorOffsetPerTrainabilityOrder);
+ return 0f;
+ }
+
}
}
diff --git a/Source/TargetingModes/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/Source/TargetingModes/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache
index 16f88f0..fcaa9df 100644
Binary files a/Source/TargetingModes/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache and b/Source/TargetingModes/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ
diff --git a/Source/TargetingModes/obj/Debug/TargetingModes.csproj.CoreCompileInputs.cache b/Source/TargetingModes/obj/Debug/TargetingModes.csproj.CoreCompileInputs.cache
index f9d1cce..5095a41 100644
--- a/Source/TargetingModes/obj/Debug/TargetingModes.csproj.CoreCompileInputs.cache
+++ b/Source/TargetingModes/obj/Debug/TargetingModes.csproj.CoreCompileInputs.cache
@@ -1 +1 @@
-c45965a061fe9b29e936a9d08b6a29933a79350e
+74f536ccffc18782bd1182be9cd04286731b609e
diff --git a/Source/TargetingModes/obj/Debug/TargetingModes.csprojAssemblyReference.cache b/Source/TargetingModes/obj/Debug/TargetingModes.csprojAssemblyReference.cache
index ea626a9..055f5ae 100644
Binary files a/Source/TargetingModes/obj/Debug/TargetingModes.csprojAssemblyReference.cache and b/Source/TargetingModes/obj/Debug/TargetingModes.csprojAssemblyReference.cache differ
diff --git a/Source/TargetingModes/obj/Debug/TargetingModes.dll b/Source/TargetingModes/obj/Debug/TargetingModes.dll
index df9ff41..146a708 100644
Binary files a/Source/TargetingModes/obj/Debug/TargetingModes.dll and b/Source/TargetingModes/obj/Debug/TargetingModes.dll differ