Skip to content
Open
Show file tree
Hide file tree
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
Binary file added 1.5/Assemblies/0Harmony.dll
Binary file not shown.
Binary file added 1.5/Assemblies/RunAndGun.dll
Binary file not shown.
106 changes: 106 additions & 0 deletions 1.5/Source/RunAndGun/Base.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HugsLib;
using HugsLib.Settings;

using RunAndGun.Utilities;
using UnityEngine;
using RimWorld;
using Verse;
using Verse.Sound;
using System.Xml;

namespace RunAndGun
{
public class Base : ModBase
{
public override string ModIdentifier
{
get { return "RunAndGun"; }
}
public static Base Instance { get; private set; }
internal static SettingHandle<int> accuracyPenalty;
internal static SettingHandle<int> movementPenaltyHeavy;
internal static SettingHandle<int> movementPenaltyLight;
internal static SettingHandle<int> enableForFleeChance;
internal static SettingHandle<bool> enableForAI;
internal static SettingHandle<DictWeaponRecordHandler> weaponSelecter;
internal static SettingHandle<DictWeaponRecordHandler> weaponForbidder;
internal static SettingHandle<String> tabsHandler;
List<ThingDef> allWeapons;
internal static SettingHandle<float> weightLimitFilter;
internal static SettingHandle<bool> dialogCEShown;


private const int minPercentage = 0;
private const int maxPercentage = 100;
private static Color highlight1 = new Color(0.5f, 0, 0, 0.1f);
String[] tabNames = { "RG_tab1".Translate(), "RG_tab2".Translate()};


public Base()
{
Instance = this;
}
public override void DefsLoaded()
{
float maxWeightMelee;
float maxWeightRanged;
allWeapons = WeaponUtility.getAllWeapons();
WeaponUtility.getHeaviestWeapons(allWeapons, out maxWeightMelee, out maxWeightRanged);
maxWeightMelee += 1;
maxWeightRanged += 1;
float maxWeightTotal = Math.Max(maxWeightMelee, maxWeightRanged);
dialogCEShown = Settings.GetHandle<bool>("dialogCEShown", "", "", false);
dialogCEShown.VisibilityPredicate = delegate { return false; };



enableForAI = Settings.GetHandle<bool>("enableRGForAI", "RG_EnableRGForAI_Title".Translate(), "RG_EnableRGForAI_Description".Translate(), true);
enableForFleeChance = Settings.GetHandle<int>("enableRGForFleeChance", "RG_EnableRGForFleeChance_Title".Translate(), "RG_EnableRGForFleeChance_Description".Translate(), 100, Validators.IntRangeValidator(minPercentage, maxPercentage));
enableForFleeChance.VisibilityPredicate = delegate { return enableForAI.Value; };

accuracyPenalty = Settings.GetHandle<int>("accuracyPenalty", "RG_AccuracyPenalty_Title".Translate(), "RG_AccuracyPenalty_Description".Translate(), 10, Validators.IntRangeValidator(minPercentage, maxPercentage));

movementPenaltyHeavy = Settings.GetHandle<int>("movementPenaltyHeavy", "RG_MovementPenaltyHeavy_Title".Translate(), "RG_MovementPenaltyHeavy_Description".Translate(), 40, Validators.IntRangeValidator(minPercentage, maxPercentage));
movementPenaltyLight = Settings.GetHandle<int>("movementPenaltyLight", "RG_MovementPenaltyLight_Title".Translate(), "RG_MovementPenaltyLight_Description".Translate(), 10, Validators.IntRangeValidator(minPercentage, maxPercentage));

tabsHandler = Settings.GetHandle<String>("tabs", "RG_Tabs_Title".Translate(), "", "none");
tabsHandler.CustomDrawer = rect => { return DrawUtility.CustomDrawer_Tabs(rect, tabsHandler, tabNames); };

weightLimitFilter = Settings.GetHandle<float>("weightLimitFilter", "RG_WeightLimitFilter_Title".Translate(), "RG_WeightLimitFilter_Description".Translate(), 3.4f);
weightLimitFilter.CustomDrawer = rect => { return DrawUtility.CustomDrawer_Filter(rect, weightLimitFilter, false, 0, maxWeightTotal, highlight1); };
weightLimitFilter.VisibilityPredicate = delegate { return tabsHandler.Value == tabNames[0]; };

weaponSelecter = Settings.GetHandle<DictWeaponRecordHandler>("weaponSelecter_new", "RG_WeaponSelection_Title".Translate(), "RG_WeaponSelection_Description".Translate(), null);
weaponSelecter.VisibilityPredicate = delegate { return tabsHandler.Value == tabNames[0]; };

weaponForbidder = Settings.GetHandle<DictWeaponRecordHandler>("weaponForbidder_new", "RG_WeaponForbidder_Title".Translate(), "RG_WeaponForbidder_Description".Translate(), null);
weaponForbidder.VisibilityPredicate = delegate { return tabsHandler.Value == tabNames[1]; };

weaponSelecter.CustomDrawer = rect => { return DrawUtility.CustomDrawer_MatchingWeapons_active(rect, weaponSelecter, allWeapons, weightLimitFilter, "RG_ConsideredLight".Translate(), "RG_ConsideredHeavy".Translate()); };
weaponForbidder.CustomDrawer = rect => { return DrawUtility.CustomDrawer_MatchingWeapons_active(rect, weaponForbidder, allWeapons, null, "RG_Allow".Translate(), "RG_Forbid".Translate() ); };

DrawUtility.filterWeapons(ref weaponSelecter, allWeapons, weightLimitFilter);
DrawUtility.filterWeapons(ref weaponForbidder, allWeapons, null);

}
internal void ResetForbidden()
{
weaponForbidder.Value = null;
DrawUtility.filterWeapons(ref weaponForbidder, allWeapons, null);
}
private bool AssemblyExists(string assemblyName)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (assembly.FullName.StartsWith(assemblyName))
return true;
}
return false;
}

}
}
16 changes: 16 additions & 0 deletions 1.5/Source/RunAndGun/CompProperties_RunAndGun.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Verse;

namespace RunAndGun
{
class CompProperties_RunAndGun : CompProperties
{
public CompProperties_RunAndGun()
{
compClass = typeof(CompRunAndGun);
}
}
}
68 changes: 68 additions & 0 deletions 1.5/Source/RunAndGun/CompRunAndGun.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Verse;
using RimWorld;
using UnityEngine;
using HugsLib.Settings;
using HugsLib;

namespace RunAndGun
{
public class CompRunAndGun : ThingComp
{

private Pawn pawn
{
get
{

Pawn pawn = (Pawn) (parent as Pawn);
if (pawn == null)
Log.Error("pawn is null");
return pawn;
}
}
public bool isEnabled = false;

//This can be misused to read isEnabled from other mods without using (expensive) reflection.
public override string GetDescriptionPart()
{
return isEnabled.ToString();
}


public override void CompTickRare()
{
if (pawn.equipment != null && pawn.equipment.Primary != null)
{
bool found = Base.weaponForbidder.Value.InnerList.TryGetValue(pawn.equipment.Primary.def.defName, out WeaponRecord value);
if (found && value.isSelected)
{
isEnabled = false;
}
}
}


public override void Initialize(CompProperties props)
{
base.Initialize(props);
Pawn pawn = (Pawn)(parent as Pawn);
bool enableRGForAI = Base.enableForAI.Value;
if (!pawn.IsColonist && enableRGForAI)
{
isEnabled = true;
}
}

public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref isEnabled, "isEnabled", false);
}

}
}

45 changes: 45 additions & 0 deletions 1.5/Source/RunAndGun/DictWeaponRecordHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using HugsLib.Settings;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RunAndGun
{
class DictWeaponRecordHandler : SettingHandleConvertible
{
public Dictionary<String, WeaponRecord> inner = new Dictionary<String, WeaponRecord>();
public Dictionary<String, WeaponRecord> InnerList { get { return inner; } set { inner = value; } }

public override void FromString(string settingValue)
{
inner = new Dictionary<String, WeaponRecord>();
if (!settingValue.Equals(string.Empty))
{
foreach (string str in settingValue.Split('|'))
{
string[] split = str.Split(',');
if (split.Count() < 4) //ensures that it works for users that still have old WeaponRecords saved.
{
inner.Add(str.Split(',')[0], new WeaponRecord(Convert.ToBoolean(str.Split(',')[1]), Convert.ToBoolean(str.Split(',')[2]), ""));
}
else
{
inner.Add(str.Split(',')[0], new WeaponRecord(Convert.ToBoolean(str.Split(',')[1]), Convert.ToBoolean(str.Split(',')[2]), str.Split(',')[3]));
}
}
}
}

public override string ToString()
{
List<String> strings = new List<string>();
foreach (KeyValuePair<string, WeaponRecord> item in inner)
{
strings.Add(item.Key + "," + item.Value.ToString());
}

return inner != null ? String.Join("|", strings.ToArray()) : "";
}
}
}
33 changes: 33 additions & 0 deletions 1.5/Source/RunAndGun/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using Verse;

namespace RunAndGun
{
public static class Extensions
{
public static bool HasRangedWeapon(this Pawn instance)
{
if(instance.equipment != null && instance.equipment.Primary != null && instance.equipment.Primary.def.IsWeaponUsingProjectiles)
{
return true;
}
return false;
}
public static bool Contains(this Rect rect, Rect otherRect)
{
if (!rect.Contains(new Vector2(otherRect.xMin, otherRect.yMin)))
return false;
if (!rect.Contains(new Vector2(otherRect.xMin, otherRect.yMax)))
return false;
if (!rect.Contains(new Vector2(otherRect.xMax, otherRect.yMax)))
return false;
if (!rect.Contains(new Vector2(otherRect.xMax, otherRect.yMin)))
return false;
return true;
}
}
}
74 changes: 74 additions & 0 deletions 1.5/Source/RunAndGun/Harmony/JobDriver_Goto_SetupToils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HarmonyLib;
using Verse;
using Verse.AI;
using RimWorld;


namespace RunAndGun.Harmony
{
[HarmonyPatch(typeof(JobDriver), "SetupToils")]
static class JobDriver_SetupToils
{
static void Postfix(JobDriver __instance, List<Toil> ___toils)
{
if(!(__instance is JobDriver_Goto))
{
return;
}
JobDriver_Goto jobDriver = (JobDriver_Goto)__instance;
if (___toils.Count() > 0)
{

Toil toil = ___toils.ElementAt(0);
toil.AddPreTickAction(delegate
{
if (jobDriver.pawn != null &&
jobDriver.pawn.IsHashIntervalTick(10) &&
!jobDriver.pawn.IsBurning() &&
(jobDriver.pawn.Drafted || !jobDriver.pawn.IsColonist) && !jobDriver.pawn.Downed)
{
checkForAutoAttack(jobDriver);
}
});

}
}
static void checkForAutoAttack(JobDriver_Goto __instance)
{
if ((__instance.pawn.story == null || !__instance.pawn.story.DisabledWorkTagsBackstoryAndTraits.HasFlag(WorkTags.Violent))
&& __instance.pawn.Faction != null
&& !(__instance.pawn.stances.curStance is Stance_RunAndGun)
&& __instance.pawn.jobs.curJob.def == JobDefOf.Goto
&& (__instance.pawn.drafter == null || __instance.pawn.drafter.FireAtWill))
{
CompRunAndGun comp = __instance.pawn.TryGetComp<CompRunAndGun>();
if (comp == null || comp.isEnabled == false)
{
return;
}
Verb verb = __instance.pawn.TryGetAttackVerb(null);

if (verb != null)
{
TargetScanFlags targetScanFlags = TargetScanFlags.NeedLOSToPawns | TargetScanFlags.NeedLOSToNonPawns | TargetScanFlags.NeedThreat;
if (verb.IsIncendiary_Ranged())
{
targetScanFlags |= TargetScanFlags.NeedNonBurning;
}
Thing thing = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(__instance.pawn, targetScanFlags, null, 0f, 9999f);
if (thing != null && !(verb.IsMeleeAttack && __instance.pawn.CanReachImmediate(thing, PathEndMode.Touch))) //Don't allow melee attacks, but take into account ranged animals or dual wield users
{
__instance.pawn.TryStartAttack(thing);
return;
}
}
}
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Verse;
using HarmonyLib;
using RimWorld;
using Verse.AI;
using HugsLib.Settings;
using HugsLib;

namespace RunAndGun.Harmony
{
[HarmonyPatch(typeof(MentalStateHandler), "TryStartMentalState")]
public class MentalStateHandler_TryStartMentalState
{
static void Postfix(MentalStateHandler __instance, MentalStateDef stateDef, ref Pawn ___pawn)
{
if (stateDef != MentalStateDefOf.PanicFlee)
{
return;
}
CompRunAndGun comp = ___pawn.TryGetComp<CompRunAndGun>();
if (comp != null && Base.enableForAI.Value)
{
comp.isEnabled = shouldRunAndGun();
}
}
static bool shouldRunAndGun()
{
var rndInt = new Random(DateTime.Now.Millisecond).Next(1, 100);
int chance = Base.enableForFleeChance.Value;
if (rndInt <= chance)
{
return true;
}
else
{
return false;
}

}
}
}
Loading