From 2b95ab32f29ab286c120c8420a0a7c350be00034 Mon Sep 17 00:00:00 2001
From: Jaxe-Dev <42095078+Jaxe-Dev@users.noreply.github.com>
Date: Sun, 16 Sep 2018 01:53:24 +0800
Subject: [PATCH] v1.1.3
- More fixes to animal training food handling
- Added support for non-Latin characters in preset names
---
About/About.xml | 2 +-
About/ModSync.xml | 2 +-
Defs/UpdateFeaturesDef/UpdateFeatures.xml | 8 +--
README.md | 4 +-
Source/Data/Persistent.cs | 3 +-
Source/Data/Presetable.cs | 5 +-
Source/Data/Registry.cs | 18 +++---
Source/Interface/Dialog_Global.cs | 2 +-
Source/Interface/Dialog_Plans.cs | 2 +-
Source/Interface/WindowPlus.cs | 1 -
Source/Mod.cs | 23 ++++----
Source/Patch/Access.cs | 2 -
Source/Patch/Extensions.cs | 4 +-
...imWorld_FoodUtility_BestFoodInInventory.cs | 12 +++-
...imWorld_FoodUtility_BestFoodSourceOnMap.cs | 16 +++--
...ld_FoodUtility_TryFindBestFoodSourceFor.cs | 4 +-
...obDriver_InteractAnimal_StartFeedAnimal.cs | 58 +++++++++++++++++++
...JobGiver_PackFood_IsGoodPackableFoodFor.cs | 6 +-
...imWorld_JoyGiver_Ingest_CanIngestForJoy.cs | 3 +-
...mWorld_Pawn_GuestTracker_SetGuestStatus.cs | 4 +-
..._InteractAnimal_HasFoodToInteractAnimal.cs | 50 ++++++++++++++++
...actAnimal_TakeFoodForAnimalInteractJob.cs} | 2 +-
Source/PawnRules.csproj | 6 +-
Source/Properties/AssemblyInfo.cs | 2 +-
24 files changed, 175 insertions(+), 64 deletions(-)
create mode 100644 Source/Patch/RimWorld_JobDriver_InteractAnimal_StartFeedAnimal.cs
create mode 100644 Source/Patch/RimWorld_WorkGiver_InteractAnimal_HasFoodToInteractAnimal.cs
rename Source/Patch/{RimWorld_WorkGiver_InteractAnimal.cs => RimWorld_WorkGiver_InteractAnimal_TakeFoodForAnimalInteractJob.cs} (93%)
diff --git a/About/About.xml b/About/About.xml
index b3166ff..7136ebb 100644
--- a/About/About.xml
+++ b/About/About.xml
@@ -4,6 +4,6 @@
Pawn Rules
Jaxe
0.19.0
- Mod Version: 1.1.2\n\n\nPawn Rules is a mod that allows custom rules to be assigned individually to your colonists, animals, guests and prisoners.\n\nCurrently the following rules can be applied:\n\n- Disallow certain foods\n- Disallow bonding with certain animals\n- Disallow new romances\n- Disallow constructing items that have a quality level\n\nAny of these rules can be disabled and hidden from the rules window. Rules presets and defaults can be imported and exported between games.
+ Mod Version: 1.1.3\n\n\nPawn Rules is a mod that allows custom rules to be assigned individually to your colonists, animals, guests and prisoners.\n\nCurrently the following rules can be applied:\n\n- Disallow certain foods\n- Disallow bonding with certain animals\n- Disallow new romances\n- Disallow constructing items that have a quality level\n\nAny of these rules can be disabled and hidden from the rules window. Rules presets and defaults can be imported and exported between games.
https://github.com/Jaxe-Dev/PawnRules
diff --git a/About/ModSync.xml b/About/ModSync.xml
index 765d319..e3d5ad1 100644
--- a/About/ModSync.xml
+++ b/About/ModSync.xml
@@ -3,7 +3,7 @@
59f538ed-f86d-4506-a4a5-7e9faaa37508
Pawn Rules
- v1.1.2
+ v1.1.3
False
Jaxe-Dev
diff --git a/Defs/UpdateFeaturesDef/UpdateFeatures.xml b/Defs/UpdateFeaturesDef/UpdateFeatures.xml
index 8826a2b..b525e81 100644
--- a/Defs/UpdateFeaturesDef/UpdateFeatures.xml
+++ b/Defs/UpdateFeaturesDef/UpdateFeatures.xml
@@ -10,13 +10,7 @@
PawnRules_1_1_1
1.1.1
- - Re-fixed "not allowed artisan builds" tooltip\n\n- Fixed "Could not find player faction" error on new game\n\n- Fixed ability to train animals if an animal has a food policy set\n\n- New Global option: Allow food if malnourished (if a pawn is is suffering from malnutrition they will ignore all food rules) [Default: False]\n\n- New Global option: Allow food if training (if an animal is being trained they ignore all food rules) [Default: False]\n\n- Plans can be imported/exported between games. A plan consists of all rule presets and defaults bundled into one file.
-
-
-
- PawnRules_1_1_2
- 1.1.2
- - Fixed null reference error when a pawn without rules attempts to build
+ - New Global option: Allow food if malnourished (if a pawn is is suffering from malnutrition they will ignore all food rules) [Default: False]\n\n- New Global option: Allow food if training (if an animal is being trained they ignore all food rules) [Default: False]\n\n- Plans can be imported/exported between games. A plan consists of all rule presets and defaults bundled into one file.
diff --git a/README.md b/README.md
index ed86ef4..b0e527b 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Pawn Rules
-![](https://img.shields.io/badge/Mod_Version-1.1.2-blue.svg)
+![](https://img.shields.io/badge/Mod_Version-1.1.3-blue.svg)
![](https://img.shields.io/badge/Built_for_RimWorld-B19-blue.svg)
![](https://img.shields.io/badge/Powered_by_Harmony-1.2.0.1-blue.svg)
@@ -53,11 +53,13 @@ Prefix : RimWorld.FoodUtility.TryFindBestFoodSourceFor
Postfix : RimWorld.GenConstruct.CanConstruct
Prefix : RimWorld.InteractionWorker_RomanceAttempt.RandomSelectionWeight
Prefix : RimWorld.InteractionWorker_RomanceAttempt.SuccessChance
+Prefix : RimWorld.JobDriver_InteractAnimal.StartFeedAnimal
Postfix : RimWorld.JobGiver_PackFood.IsGoodPackableFoodFor
Prefix : RimWorld.JoyGiver_Ingest.CanIngestForJoy
Prefix : RimWorld.Pawn_GuestTracker.SetGuestStatus
Postfix : RimWorld.PawnUtility.TrySpawnHatchedOrBornPawn
Prefix : RimWorld.RelationsUtility.TryDevelopBondRelation
+Prefix : RimWorld.WorkGiver_InteractAnimal.HasFoodToInteractAnimal
Prefix : RimWorld.WorkGiver_InteractAnimal.TakeFoodForAnimalInteractJob
Postfix : Verse.Game.FinalizeInit
Prefix : Verse.Game.InitNewGame
diff --git a/Source/Data/Persistent.cs b/Source/Data/Persistent.cs
index 17f5074..3d8567a 100644
--- a/Source/Data/Persistent.cs
+++ b/Source/Data/Persistent.cs
@@ -15,7 +15,7 @@ internal static class Persistent
private const string ExportsExtension = ".xml";
private const string ExportPrefix = "Plan_";
- private static readonly Regex ValidNameRegex = new Regex("^(?:[a-zA-Z0-9_\\-]|[a-zA-Z0-9_\\-]+[a-zA-Z0-9_\\- ]*[a-zA-Z0-9_\\-]+)$");
+ private static readonly Regex ValidNameRegex = new Regex("^(?:[\\p{L}\\p{N}_\\-]|[\\p{L}\\p{N}_\\-]+[\\p{L}\\p{N}_\\- ]*[\\p{L}\\p{N}_\\-]+)$");
private static readonly DirectoryInfo ExportsDirectory = Mod.ConfigDirectory.CreateSubdirectory(ExportsDirectoryName);
@@ -28,7 +28,6 @@ public static void DeletePlan(string name)
{
var file = GetPlanFile(name);
- Mod.Warning($"Delete => {file.FullName}");
if (!file.Exists) { return; }
file.Delete();
diff --git a/Source/Data/Presetable.cs b/Source/Data/Presetable.cs
index fe0c9fc..82b84a3 100644
--- a/Source/Data/Presetable.cs
+++ b/Source/Data/Presetable.cs
@@ -2,6 +2,7 @@
using System.Text.RegularExpressions;
using System.Xml.Linq;
using PawnRules.Interface;
+using PawnRules.Patch;
using Verse;
namespace PawnRules.Data
@@ -12,7 +13,7 @@ internal abstract class Presetable : IExposable, ILoadReferenceable
public static readonly string VoidName = Lang.Get("Preset.None");
- private static readonly Regex ValidNameRegex = new Regex("^(?:[a-zA-Z0-9]|[a-zA-Z0-9]+[a-zA-Z0-9 ]*[a-zA-Z0-9]+)$");
+ private static readonly Regex ValidNameRegex = new Regex("^(?:[\\p{L}\\p{N}]|[\\p{L}\\p{N}]+[\\p{L}\\p{N} ]*[\\p{L}\\p{N}])$");
private static int _count;
protected readonly int Id;
@@ -54,7 +55,7 @@ public static void SetName(T preset, Action onRename) where T : Presetable
var localPreset = preset;
void OnCommit(string name) => onRename(Registry.RenamePreset(localPreset, name));
- Dialog_SetName.Open(Lang.Get("Dialog_SetName.PresetTitle", preset.Name), Lang.Get("Dialog_SetName.PresetLabel"), OnCommit, name => NameIsValid(preset.Type, name), preset.Name);
+ Dialog_SetName.Open(Lang.Get("Dialog_SetName.PresetTitle", preset.Name.Bold()), Lang.Get("Dialog_SetName.PresetLabel"), OnCommit, name => NameIsValid(preset.Type, name), preset.Name);
}
public static bool NameIsValid(IPresetableType type, string name) => (name.Length <= MaxIdLength) && !string.Equals(name, Lang.Get("Preset.None"), StringComparison.OrdinalIgnoreCase) && !string.Equals(name, Lang.Get("Preset.Personalized"), StringComparison.OrdinalIgnoreCase) && ValidNameRegex.IsMatch(name) && !Registry.PresetNameExists(type, name);
diff --git a/Source/Data/Registry.cs b/Source/Data/Registry.cs
index 3a18d76..8cb2e82 100644
--- a/Source/Data/Registry.cs
+++ b/Source/Data/Registry.cs
@@ -23,14 +23,16 @@ internal class Registry : WorldObject
private static bool _isDeactivating;
- public static bool AllowEmergencyFood { get => _instance._allowEmergencyFood; set => _instance._allowEmergencyFood = value; }
- public static bool AllowTrainingFood { get => _instance._allowTrainingFood; set => _instance._allowTrainingFood = value; }
public static bool ShowFoodPolicy { get => _instance._showFoodPolicy; set => _instance._showFoodPolicy = value; }
public static bool ShowBondingPolicy { get => _instance._showBondingPolicy; set => _instance._showBondingPolicy = value; }
public static bool ShowAllowCourting { get => _instance._showAllowCourting; set => _instance._showAllowCourting = value; }
public static bool ShowAllowArtisan { get => _instance._showAllowArtisan; set => _instance._showAllowArtisan = value; }
+ public static bool AllowEmergencyFood { get => _instance._allowEmergencyFood; set => _instance._allowEmergencyFood = value; }
+ public static bool AllowTrainingFood { get => _instance._allowTrainingFood; set => _instance._allowTrainingFood = value; }
+ public static Pawn ExemptedTrainer { get; set; }
+
private string _loadedVersion;
private readonly Dictionary> _voidPresets = new Dictionary>();
@@ -42,14 +44,14 @@ internal class Registry : WorldObject
private List _savedBindings = new List();
private List _savedDefaults = new List();
- private bool _allowEmergencyFood;
- private bool _allowTrainingFood;
-
private bool _showFoodPolicy = true;
private bool _showBondingPolicy = true;
private bool _showAllowCourting = true;
private bool _showAllowArtisan = true;
+ private bool _allowEmergencyFood;
+ private bool _allowTrainingFood;
+
public static void Initialize()
{
var worldObjects = Current.Game.World.worldObjects;
@@ -316,14 +318,14 @@ public override void ExposeData()
_savedBindings.AddRange(_rules.Where(rules => rules.Key.CanHaveRules()).Select(rules => new Binding(rules.Key, rules.Value.IsIgnored() ? null : rules.Value)).ToArray());
}
- Scribe_Values.Look(ref _allowEmergencyFood, "allowEmergencyFood");
- Scribe_Values.Look(ref _allowTrainingFood, "allowTrainingFood");
-
Scribe_Values.Look(ref _showFoodPolicy, "showFoodPolicy", true);
Scribe_Values.Look(ref _showBondingPolicy, "showBondingPolicy", true);
Scribe_Values.Look(ref _showAllowCourting, "showAllowCourting", true);
Scribe_Values.Look(ref _showAllowArtisan, "showAllowArtisan", true);
+ Scribe_Values.Look(ref _allowEmergencyFood, "allowEmergencyFood");
+ Scribe_Values.Look(ref _allowTrainingFood, "allowTrainingFood");
+
Scribe_Collections.Look(ref _savedPresets, "presets", LookMode.Deep);
Scribe_Collections.Look(ref _savedBindings, "bindings", LookMode.Deep);
Scribe_Collections.Look(ref _savedDefaults, "defaults", LookMode.Deep);
diff --git a/Source/Interface/Dialog_Global.cs b/Source/Interface/Dialog_Global.cs
index 207df76..9efea8e 100644
--- a/Source/Interface/Dialog_Global.cs
+++ b/Source/Interface/Dialog_Global.cs
@@ -7,7 +7,7 @@ namespace PawnRules.Interface
{
internal class Dialog_Global : WindowPlus
{
- private Dialog_Global() : base(Lang.Get("Dialog_Global.Title"), new Vector2(300f, 400f))
+ private Dialog_Global() : base(Lang.Get("Dialog_Global.Title").Bold(), new Vector2(300f, 400f))
{ }
public static void Open() => Find.WindowStack.Add(new Dialog_Global());
diff --git a/Source/Interface/Dialog_Plans.cs b/Source/Interface/Dialog_Plans.cs
index 5d03736..069e249 100644
--- a/Source/Interface/Dialog_Plans.cs
+++ b/Source/Interface/Dialog_Plans.cs
@@ -13,7 +13,7 @@ internal class Dialog_Plans : WindowPlus
private IEnumerable _plans;
private string _selected;
- private Dialog_Plans() : base(Lang.Get("Dialog_Plans.Title"), new Vector2(500f, 600f))
+ private Dialog_Plans() : base(Lang.Get("Dialog_Plans.Title").Bold(), new Vector2(500f, 600f))
{
doCloseButton = false;
diff --git a/Source/Interface/WindowPlus.cs b/Source/Interface/WindowPlus.cs
index 3983408..ad3a6f2 100644
--- a/Source/Interface/WindowPlus.cs
+++ b/Source/Interface/WindowPlus.cs
@@ -43,7 +43,6 @@ private Rect DoTitle(Rect rect)
var header = new Listing_StandardPlus();
header.Begin(rect);
- Text.Font = GameFont.Medium;
header.LabelMedium(Title);
header.GapLine();
header.End();
diff --git a/Source/Mod.cs b/Source/Mod.cs
index 9ad7de2..798c3e8 100644
--- a/Source/Mod.cs
+++ b/Source/Mod.cs
@@ -6,6 +6,7 @@
using PawnRules.Data;
using PawnRules.Interface;
using PawnRules.Patch;
+using RimWorld;
using UnityEngine;
using Verse;
@@ -15,19 +16,22 @@ internal class Mod : Verse.Mod
{
public const string Id = "PawnRules";
public const string Name = "Pawn Rules";
- public const string Author = "Jaxe";
- public const string Version = "1.1.2";
+ public const string Version = "1.1.3";
- public static readonly DirectoryInfo ConfigDirectory = new DirectoryInfo(GenFilePaths.ConfigFolderPath).CreateSubdirectory(Id);
+ public static readonly DirectoryInfo ConfigDirectory = new DirectoryInfo(Path.Combine(GenFilePaths.ConfigFolderPath, Id));
public static Mod Instance { get; private set; }
+ public static bool FirstTimeUser { get; private set; }
public Mod(ModContentPack contentPack) : base(contentPack)
{
Instance = this;
Log("Loaded");
- TryRegisterHugsLibUpdateFeature();
+ FirstTimeUser = !ConfigDirectory.Exists;
+ ConfigDirectory.Create();
+
+ if (!FirstTimeUser) { TryRegisterHugsLibUpdateFeature(); }
}
private static void TryRegisterHugsLibUpdateFeature()
@@ -35,19 +39,16 @@ private static void TryRegisterHugsLibUpdateFeature()
var hugsLib = (from assembly in AppDomain.CurrentDomain.GetAssemblies() from type in assembly.GetTypes() where type.Name == "HugsLibController" select type).FirstOrDefault();
if (hugsLib == null) { return; }
- var controllerField = AccessTools.Field(hugsLib, "instance");
- var controller = controllerField.GetValue(null);
-
- var updateFeaturesField = AccessTools.Property(controller.GetType(), "UpdateFeatures");
- var updateFeatures = updateFeaturesField.GetValue(controller, null);
+ var updateFeatures = Traverse.Create(hugsLib)?.Field("instance")?.Property("UpdateFeatures")?.GetValue();
+ if (updateFeatures == null) { return; }
- var inspectActiveModMethod = AccessTools.Method(updateFeatures.GetType(), "InspectActiveMod");
- inspectActiveModMethod.Invoke(updateFeatures, new object[] { Id, Assembly.GetExecutingAssembly().GetName().Version });
+ AccessTools.Method(updateFeatures.GetType(), "InspectActiveMod")?.Invoke(updateFeatures, new object[] { Id, Assembly.GetExecutingAssembly().GetName().Version });
}
public static void Log(string message) => Verse.Log.Message(PrefixMessage(message));
public static void Warning(string message) => Verse.Log.Warning(PrefixMessage(message));
public static void Error(string message) => Verse.Log.Error(PrefixMessage(message));
+ public static void Message(string message) => Messages.Message(message, MessageTypeDefOf.TaskCompletion, false);
public static string PrefixMessage(string message) => $"[{Name} v{Version}] {message}";
public override string SettingsCategory() => Name;
diff --git a/Source/Patch/Access.cs b/Source/Patch/Access.cs
index b2efeea..a4a32f7 100644
--- a/Source/Patch/Access.cs
+++ b/Source/Patch/Access.cs
@@ -15,7 +15,6 @@ internal static class Access
private static readonly MethodInfo Method_RimWorld_FoodUtility_IsFoodSourceOnMapSociallyProper = AccessTools.Method(typeof(FoodUtility), "IsFoodSourceOnMapSociallyProper");
private static readonly MethodInfo Method_RimWorld_FoodUtility_SpawnedFoodSearchInnerScan = AccessTools.Method(typeof(FoodUtility), "SpawnedFoodSearchInnerScan");
private static readonly FieldInfo Field_RimWorld_FoodUtility_Filtered = AccessTools.Field(typeof(FoodUtility), "filtered");
- private static readonly FieldInfo Field_RimWorld_Pawn_GuestTracker_Pawn = AccessTools.Field(typeof(Pawn_GuestTracker), "pawn");
private static readonly FieldInfo Field_Verse_LoadedModManager_RunningMods = AccessTools.Field(typeof(LoadedModManager), "runningMods");
public static Pawn Method_RimWorld_FoodUtility_BestPawnToHuntForPredator_Call(Pawn predator, bool forceScanWholeMap) => (Pawn) Method_RimWorld_FoodUtility_BestPawnToHuntForPredator.Invoke(null, new object[] { predator, forceScanWholeMap });
@@ -23,7 +22,6 @@ internal static class Access
public static bool Method_RimWorld_FoodUtility_IsFoodSourceOnMapSociallyProper_Call(Thing thing, Pawn getter, Pawn eater, bool allowSociallyImproper) => (bool) Method_RimWorld_FoodUtility_IsFoodSourceOnMapSociallyProper.Invoke(null, new object[] { thing, getter, eater, allowSociallyImproper });
public static Thing Method_RimWorld_FoodUtility_SpawnedFoodSearchInnerScan_Call(Pawn eater, IntVec3 root, List searchSet, PathEndMode peMode, TraverseParms traverseParams, float maxDistance = 9999f, Predicate validator = null) => (Thing) Method_RimWorld_FoodUtility_SpawnedFoodSearchInnerScan.Invoke(null, new object[] { eater, root, searchSet, peMode, traverseParams, maxDistance, validator });
public static HashSet Field_RimWorld_FoodUtility_Filtered_Get() => (HashSet) Field_RimWorld_FoodUtility_Filtered.GetValue(null);
- public static Pawn Field_RimWorld_Pawn_GuestTracker_Pawn_Get(Pawn_GuestTracker instance) => (Pawn) Field_RimWorld_Pawn_GuestTracker_Pawn.GetValue(instance);
public static List Field_Verse_LoadedModManager_RunningMods_Get() => (List) Field_Verse_LoadedModManager_RunningMods.GetValue(null);
}
}
diff --git a/Source/Patch/Extensions.cs b/Source/Patch/Extensions.cs
index 688dea4..83c6238 100644
--- a/Source/Patch/Extensions.cs
+++ b/Source/Patch/Extensions.cs
@@ -1,4 +1,4 @@
-using System;
+using System.Collections;
using PawnRules.Data;
using RimWorld;
using UnityEngine;
@@ -11,7 +11,7 @@ internal static class Extensions
public static string Italic(this string self) => "" + self + "";
public static string Bold(this string self) => "" + self + "";
- public static int LastIndex(this Array self) => self.Length - 1;
+ public static int LastIndex(this IList self) => self.Count - 1;
public static int ToInt(this string self, int defaultValue = 0) => int.TryParse(self, out var result) ? result : defaultValue;
public static float ToFloat(this string self, float defaultValue = 0f) => float.TryParse(self, out var result) ? result : defaultValue;
diff --git a/Source/Patch/RimWorld_FoodUtility_BestFoodInInventory.cs b/Source/Patch/RimWorld_FoodUtility_BestFoodInInventory.cs
index 7a3a162..628b7ff 100644
--- a/Source/Patch/RimWorld_FoodUtility_BestFoodInInventory.cs
+++ b/Source/Patch/RimWorld_FoodUtility_BestFoodInInventory.cs
@@ -11,7 +11,13 @@ internal static class RimWorld_FoodUtility_BestFoodInInventory
{
private static bool Prefix(ref Thing __result, Pawn holder, Pawn eater = null, FoodPreferability minFoodPref = FoodPreferability.NeverForNutrition, FoodPreferability maxFoodPref = FoodPreferability.MealLavish, float minStackNutrition = 0.0f, bool allowDrug = false)
{
+ if (Registry.ExemptedTrainer != null)
+ {
+ Registry.ExemptedTrainer = null;
+ return true;
+ }
if (!Registry.IsActive) { return true; }
+
if (holder.inventory == null)
{
__result = null;
@@ -20,14 +26,14 @@ private static bool Prefix(ref Thing __result, Pawn holder, Pawn eater = null, F
if (eater == null) { eater = holder; }
- var rules = Registry.GetRules(eater);
- if (eater.InMentalState || (rules == null) || rules.GetRestriction(RestrictionType.Food).IsVoid) { return true; }
+ var restriction = Registry.GetRules(eater)?.GetRestriction(RestrictionType.Food);
+ if (eater.InMentalState || (restriction == null) || restriction.IsVoid) { return true; }
var innerContainer = holder.inventory.innerContainer;
foreach (var thing in innerContainer.ToArray())
{
// Pawn Rules - Food check below
- if (!thing.def.IsNutritionGivingIngestible || !thing.IngestibleNow || !eater.RaceProps.CanEverEat(thing) || (thing.def.ingestible.preferability < minFoodPref) || (thing.def.ingestible.preferability > maxFoodPref) || (!allowDrug && thing.def.IsDrug) || !(thing.GetStatValue(StatDefOf.Nutrition) * thing.stackCount >= (double) minStackNutrition) || !rules.GetRestriction(RestrictionType.Food).AllowsFood(thing.def, eater)) { continue; }
+ if (!thing.def.IsNutritionGivingIngestible || !thing.IngestibleNow || !eater.RaceProps.CanEverEat(thing) || (thing.def.ingestible.preferability < minFoodPref) || (thing.def.ingestible.preferability > maxFoodPref) || (!allowDrug && thing.def.IsDrug) || !(thing.GetStatValue(StatDefOf.Nutrition) * thing.stackCount >= (double) minStackNutrition) || !restriction.AllowsFood(thing.def, eater)) { continue; }
__result = thing;
return false;
diff --git a/Source/Patch/RimWorld_FoodUtility_BestFoodSourceOnMap.cs b/Source/Patch/RimWorld_FoodUtility_BestFoodSourceOnMap.cs
index c5b43ae..827b75f 100644
--- a/Source/Patch/RimWorld_FoodUtility_BestFoodSourceOnMap.cs
+++ b/Source/Patch/RimWorld_FoodUtility_BestFoodSourceOnMap.cs
@@ -10,21 +10,19 @@ namespace PawnRules.Patch
[HarmonyPatch(typeof(FoodUtility), "BestFoodSourceOnMap")]
internal static class RimWorld_FoodUtility_BestFoodSourceOnMap
{
- public static Pawn ExemptTrainer { get; set; }
-
private static bool Prefix(ref Thing __result, Pawn getter, Pawn eater, bool desperate, out ThingDef foodDef, FoodPreferability maxPref = FoodPreferability.MealLavish, bool allowPlant = true, bool allowDrug = true, bool allowCorpse = true, bool allowDispenserFull = true, bool allowDispenserEmpty = true, bool allowForbidden = false, bool allowSociallyImproper = false, bool allowHarvest = false, bool forceScanWholeMap = false)
{
foodDef = null;
- if (!Registry.IsActive) { return true; }
- if (ExemptTrainer != null)
+ if (Registry.ExemptedTrainer != null)
{
- ExemptTrainer = null;
+ Registry.ExemptedTrainer = null;
return true;
}
+ if (!Registry.IsActive) { return true; }
- var rules = Registry.GetRules(eater);
- if (eater.InMentalState || (rules == null) || rules.GetRestriction(RestrictionType.Food).IsVoid) { return true; }
+ var restriction = Registry.GetRules(eater)?.GetRestriction(RestrictionType.Food);
+ if (eater.InMentalState || (restriction == null) || restriction.IsVoid) { return true; }
var filtered = Access.Field_RimWorld_FoodUtility_Filtered_Get();
@@ -45,7 +43,7 @@ private static bool Prefix(ref Thing __result, Pawn getter, Pawn eater, bool des
else if ((thing.def.ingestible.preferability < minPref) || (thing.def.ingestible.preferability > maxPref) || !eater.RaceProps.WillAutomaticallyEat(thing) || !thing.def.IsNutritionGivingIngestible || !thing.IngestibleNow || (!allowCorpse && thing is Corpse) || (!allowDrug && thing.def.IsDrug) || (!allowForbidden && thing.IsForbidden(getter)) || (!desperate && thing.IsNotFresh()) || thing.IsDessicated() || !Access.Method_RimWorld_FoodUtility_IsFoodSourceOnMapSociallyProper_Call(thing, getter, eater, allowSociallyImproper) || (!getter.AnimalAwareOf(thing) && !forceScanWholeMap) || !getter.CanReserve(thing)) { return false; }
// Pawn Rules - Food check below
- return rules.GetRestriction(RestrictionType.Food).AllowsFood(thing.def, eater);
+ return restriction.AllowsFood(thing.def, eater);
});
var req = ((eater.RaceProps.foodType & (FoodTypeFlags.Plant | FoodTypeFlags.Tree)) == FoodTypeFlags.None) || !allowPlant ? ThingRequest.ForGroup(ThingRequestGroup.FoodSourceNotPlantOrTree) : ThingRequest.ForGroup(ThingRequestGroup.FoodSource);
@@ -64,7 +62,7 @@ bool Validator(Thing thing)
var harvestedThingDef = plant.def.plant.harvestedThingDef;
// Pawn Rules - Food check below
- return harvestedThingDef.IsNutritionGivingIngestible && eater.RaceProps.CanEverEat(harvestedThingDef) && getter.CanReserve(plant) && (allowForbidden || !plant.IsForbidden(getter)) && ((bestThing == null) || (FoodUtility.GetFinalIngestibleDef(bestThing).ingestible.preferability < harvestedThingDef.ingestible.preferability)) && rules.GetRestriction(RestrictionType.Food).AllowsFood(plant.def, eater);
+ return harvestedThingDef.IsNutritionGivingIngestible && eater.RaceProps.CanEverEat(harvestedThingDef) && getter.CanReserve(plant) && (allowForbidden || !plant.IsForbidden(getter)) && ((bestThing == null) || (FoodUtility.GetFinalIngestibleDef(bestThing).ingestible.preferability < harvestedThingDef.ingestible.preferability)) && restriction.AllowsFood(plant.def, eater);
}
var foodSource = GenClosest.ClosestThingReachable(getter.Position, getter.Map, ThingRequest.ForGroup(ThingRequestGroup.HarvestablePlant), PathEndMode.Touch, TraverseParms.For(getter), 9999f, Validator, null, 0, searchRegionsMax);
diff --git a/Source/Patch/RimWorld_FoodUtility_TryFindBestFoodSourceFor.cs b/Source/Patch/RimWorld_FoodUtility_TryFindBestFoodSourceFor.cs
index 75af585..9aca22f 100644
--- a/Source/Patch/RimWorld_FoodUtility_TryFindBestFoodSourceFor.cs
+++ b/Source/Patch/RimWorld_FoodUtility_TryFindBestFoodSourceFor.cs
@@ -15,8 +15,8 @@ private static bool Prefix(ref bool __result, Pawn getter, Pawn eater, bool desp
if (!Registry.IsActive) { return true; }
- var rules = Registry.GetRules(eater);
- if (eater.InMentalState || (rules == null) || rules.GetRestriction(RestrictionType.Food).IsVoid) { return true; }
+ var restriction = Registry.GetRules(eater)?.GetRestriction(RestrictionType.Food);
+ if (eater.InMentalState || (restriction == null) || restriction.IsVoid) { return true; }
var hasInventory = getter.RaceProps.ToolUser && getter.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation);
var allowDrug = !eater.IsTeetotaler();
diff --git a/Source/Patch/RimWorld_JobDriver_InteractAnimal_StartFeedAnimal.cs b/Source/Patch/RimWorld_JobDriver_InteractAnimal_StartFeedAnimal.cs
new file mode 100644
index 0000000..42c3a75
--- /dev/null
+++ b/Source/Patch/RimWorld_JobDriver_InteractAnimal_StartFeedAnimal.cs
@@ -0,0 +1,58 @@
+using Harmony;
+using PawnRules.Data;
+using RimWorld;
+using UnityEngine;
+using Verse;
+using Verse.AI;
+
+namespace PawnRules.Patch
+{
+ [HarmonyPatch(typeof(JobDriver_InteractAnimal), "StartFeedAnimal")]
+ internal static class RimWorld_JobDriver_InteractAnimal_StartFeedAnimal
+ {
+ private static bool Prefix(ref Toil __result, JobDriver_InteractAnimal __instance, TargetIndex tameeInd)
+ {
+ var toil = new Toil();
+ toil.initAction = () =>
+ {
+ var feedNutritionLeft = Traverse.Create(__instance).Field("feedNutritionLeft");
+
+ var actor = toil.GetActor();
+ var target = (Pawn) (Thing) actor.CurJob.GetTarget(tameeInd);
+
+ PawnUtility.ForceWait(target, 270, actor);
+
+ Registry.ExemptedTrainer = actor;
+ var thing1 = FoodUtility.BestFoodInInventory(actor, target, FoodPreferability.NeverForNutrition, FoodPreferability.RawTasty);
+ if (thing1 == null) { actor.jobs.EndCurrentJob(JobCondition.Incompletable); }
+ else
+ {
+ actor.mindState.lastInventoryRawFoodUseTick = Find.TickManager.TicksGame;
+
+ var stackCountForNutrition = FoodUtility.StackCountForNutrition(feedNutritionLeft.Value, thing1.GetStatValue(StatDefOf.Nutrition));
+ var stackCount = thing1.stackCount;
+ var thing2 = actor.inventory.innerContainer.Take(thing1, Mathf.Min(stackCountForNutrition, stackCount));
+
+ actor.carryTracker.TryStartCarry(thing2);
+ actor.CurJob.SetTarget(TargetIndex.B, thing2);
+
+ var nutrition = thing2.stackCount * thing2.GetStatValue(StatDefOf.Nutrition);
+ __instance.ticksLeftThisToil = Mathf.CeilToInt((270f * (nutrition / JobDriver_InteractAnimal.RequiredNutritionPerFeed(target))));
+
+ if (stackCountForNutrition <= stackCount) { Traverse.Create(__instance).Field("feedNutritionLeft").Value = 0f; }
+ else
+ {
+ feedNutritionLeft.Value -= nutrition;
+ if (feedNutritionLeft.Value >= 0.001f) { return; }
+ feedNutritionLeft.Value = 0f;
+ }
+ }
+ };
+
+ toil.defaultCompleteMode = ToilCompleteMode.Delay;
+
+ __result = toil;
+ return false;
+ }
+ }
+}
diff --git a/Source/Patch/RimWorld_JobGiver_PackFood_IsGoodPackableFoodFor.cs b/Source/Patch/RimWorld_JobGiver_PackFood_IsGoodPackableFoodFor.cs
index ffa7937..36f503f 100644
--- a/Source/Patch/RimWorld_JobGiver_PackFood_IsGoodPackableFoodFor.cs
+++ b/Source/Patch/RimWorld_JobGiver_PackFood_IsGoodPackableFoodFor.cs
@@ -12,10 +12,10 @@ private static void Postfix(ref bool __result, Thing food, Pawn forPawn)
{
if (!Registry.IsActive) { return; }
- var rules = Registry.GetRules(forPawn);
- if (forPawn.InMentalState || (rules == null) || rules.GetRestriction(RestrictionType.Food).IsVoid) { return; }
+ var restriction = Registry.GetRules(forPawn)?.GetRestriction(RestrictionType.Food);
+ if (forPawn.InMentalState || (restriction == null) || restriction.IsVoid) { return; }
- __result = __result && rules.GetRestriction(RestrictionType.Food).AllowsFood(food.def, forPawn);
+ __result = __result && restriction.AllowsFood(food.def, forPawn);
}
}
}
diff --git a/Source/Patch/RimWorld_JoyGiver_Ingest_CanIngestForJoy.cs b/Source/Patch/RimWorld_JoyGiver_Ingest_CanIngestForJoy.cs
index ec59b02..962ff3f 100644
--- a/Source/Patch/RimWorld_JoyGiver_Ingest_CanIngestForJoy.cs
+++ b/Source/Patch/RimWorld_JoyGiver_Ingest_CanIngestForJoy.cs
@@ -10,8 +10,7 @@ internal static class RimWorld_JoyGiver_Ingest_CanIngestForJoy
{
private static bool Prefix(ref bool __result, Pawn pawn, Thing t)
{
- var rules = Registry.GetRules(pawn);
- var restriction = rules?.GetRestriction(RestrictionType.Food);
+ var restriction = Registry.GetRules(pawn)?.GetRestriction(RestrictionType.Food);
if (pawn.InMentalState || (restriction == null) || restriction.IsVoid || restriction.AllowsFood(t.def, pawn)) { return true; }
__result = false;
diff --git a/Source/Patch/RimWorld_Pawn_GuestTracker_SetGuestStatus.cs b/Source/Patch/RimWorld_Pawn_GuestTracker_SetGuestStatus.cs
index 9a839de..22d7a57 100644
--- a/Source/Patch/RimWorld_Pawn_GuestTracker_SetGuestStatus.cs
+++ b/Source/Patch/RimWorld_Pawn_GuestTracker_SetGuestStatus.cs
@@ -1,6 +1,7 @@
using Harmony;
using PawnRules.Data;
using RimWorld;
+using Verse;
namespace PawnRules.Patch
{
@@ -11,7 +12,8 @@ private static void Prefix(Pawn_GuestTracker __instance, Faction newHost, bool p
{
if (!Registry.IsActive) { return; }
- Registry.FactionUpdate(Access.Field_RimWorld_Pawn_GuestTracker_Pawn_Get(__instance), newHost, !prisoner);
+ Registry.FactionUpdate(Traverse.Create(__instance).Field("pawn").Value, newHost, !prisoner);
+ //Registry.FactionUpdate(Access.Field_RimWorld_Pawn_GuestTracker_Pawn_Get(__instance), newHost, !prisoner);
}
}
}
diff --git a/Source/Patch/RimWorld_WorkGiver_InteractAnimal_HasFoodToInteractAnimal.cs b/Source/Patch/RimWorld_WorkGiver_InteractAnimal_HasFoodToInteractAnimal.cs
new file mode 100644
index 0000000..923cd30
--- /dev/null
+++ b/Source/Patch/RimWorld_WorkGiver_InteractAnimal_HasFoodToInteractAnimal.cs
@@ -0,0 +1,50 @@
+using System.Linq;
+using Harmony;
+using PawnRules.Data;
+using RimWorld;
+using Verse;
+
+namespace PawnRules.Patch
+{
+ [HarmonyPatch(typeof(WorkGiver_InteractAnimal), "HasFoodToInteractAnimal")]
+ internal static class RimWorld_WorkGiver_InteractAnimal_HasFoodToInteractAnimal
+ {
+ private static bool Prefix(ref bool __result, Pawn pawn, Pawn tamee)
+ {
+ if (!Registry.IsActive || Registry.AllowTrainingFood) { return true; }
+
+ var restriction = Registry.GetRules(tamee)?.GetRestriction(RestrictionType.Food);
+ if ((restriction == null) || restriction.IsVoid) { return true; }
+
+ var innerContainer = pawn.inventory.innerContainer;
+ var requiredNutritionPerFeed = JobDriver_InteractAnimal.RequiredNutritionPerFeed(tamee);
+
+ var count = 0;
+ var nutrition = 0.0f;
+
+ foreach (var thing in innerContainer.ToArray())
+ {
+ if (!tamee.RaceProps.CanEverEat(thing) || (thing.def.ingestible.preferability > FoodPreferability.RawTasty) || thing.def.IsDrug || !restriction.Allows(thing.def)) { continue; }
+
+ for (var index = 0; index < thing.stackCount; ++index)
+ {
+ nutrition += thing.GetStatValue(StatDefOf.Nutrition);
+
+ if (nutrition >= (double) requiredNutritionPerFeed)
+ {
+ count++;
+ nutrition = 0.0f;
+ }
+
+ if (count < 2) { continue; }
+
+ __result = true;
+ return false;
+ }
+ }
+
+ __result = false;
+ return false;
+ }
+ }
+}
diff --git a/Source/Patch/RimWorld_WorkGiver_InteractAnimal.cs b/Source/Patch/RimWorld_WorkGiver_InteractAnimal_TakeFoodForAnimalInteractJob.cs
similarity index 93%
rename from Source/Patch/RimWorld_WorkGiver_InteractAnimal.cs
rename to Source/Patch/RimWorld_WorkGiver_InteractAnimal_TakeFoodForAnimalInteractJob.cs
index 80b1e0e..bd10837 100644
--- a/Source/Patch/RimWorld_WorkGiver_InteractAnimal.cs
+++ b/Source/Patch/RimWorld_WorkGiver_InteractAnimal_TakeFoodForAnimalInteractJob.cs
@@ -16,7 +16,7 @@ private static bool Prefix(ref Job __result, Pawn pawn, Pawn tamee)
var required = JobDriver_InteractAnimal.RequiredNutritionPerFeed(tamee) * 2f * 4f;
- RimWorld_FoodUtility_BestFoodSourceOnMap.ExemptTrainer = pawn;
+ Registry.ExemptedTrainer = pawn;
var foodSource = FoodUtility.BestFoodSourceOnMap(pawn, tamee, false, out var foodDef, FoodPreferability.RawTasty, false, false, false, false, false);
if (foodSource == null)
diff --git a/Source/PawnRules.csproj b/Source/PawnRules.csproj
index b2ec2a4..6159e7d 100644
--- a/Source/PawnRules.csproj
+++ b/Source/PawnRules.csproj
@@ -90,12 +90,14 @@
-
+
+
-
+
+
diff --git a/Source/Properties/AssemblyInfo.cs b/Source/Properties/AssemblyInfo.cs
index ecce163..7321b07 100644
--- a/Source/Properties/AssemblyInfo.cs
+++ b/Source/Properties/AssemblyInfo.cs
@@ -3,5 +3,5 @@
[assembly: AssemblyTitle(Mod.Name)]
[assembly: AssemblyProduct("RimWorld Mods by Jaxe")]
-[assembly: AssemblyCopyright("© " + Mod.Author)]
+[assembly: AssemblyCopyright("© Jaxe")]
[assembly: AssemblyVersion(Mod.Version)]