diff --git a/Languages/English/Keyed/Manager_Keyed.xml b/Languages/English/Keyed/Manager_Keyed.xml index 8e8cb447..e7e9c63f 100644 --- a/Languages/English/Keyed/Manager_Keyed.xml +++ b/Languages/English/Keyed/Manager_Keyed.xml @@ -167,6 +167,10 @@ Training Restrict animals to area? Restrict animals to a specific area, optionally separated by gender and lifestage + Restrict hungry animals + Restrict hungry animals to a specific area, optionally separated by gender and lifestage, as long as they are not restricted animals marked for slaughter. + Animal Food Need + An animal whose food need is below or equal to this value will be restricted to this area. Butcher excess livestock Should excess livestock be butchered for meat? Trained diff --git a/Source/Helpers/Utilities.cs b/Source/Helpers/Utilities.cs index ff57f044..23a4bbc6 100644 --- a/Source/Helpers/Utilities.cs +++ b/Source/Helpers/Utilities.cs @@ -327,6 +327,22 @@ public static void DrawToggle( Rect rect, string label, string tooltip, bool che DrawToggle( rect, label, tooltip, checkOn, !checkOn, on, off, expensive, size, margin, wrap ); } + public static void DrawSlider(Rect rect, string label, string tooltip, ref float value, float size = 5*SmallIconSize, + float margin = Margin, bool wrap = true) + { + // set up rects + var labelRect = rect; + var sliderRect = new Rect(rect.xMax - size - margin, 0f, size, labelRect.height/2f); + labelRect.xMax = sliderRect.xMin - Margin / 2f; + // finetune rects + sliderRect = sliderRect.CenteredOnYIn(labelRect); + // draw label + Label(rect, label, TextAnchor.MiddleLeft, GameFont.Small, margin: margin, wrap: wrap); + // tooltip + if (!tooltip.NullOrEmpty()) TooltipHandler.TipRegion(rect, tooltip ); + // draw slider + value = Widgets.HorizontalSlider(sliderRect, value, 0f, 1f, true, String.Format("{0:P0}", value)); // GUI.HorizontalSlider(sliderRect, value, 0f, 1f); + } public static void DrawToggle( Rect rect, string label, string tooltip, bool checkOn, bool checkOff, Action on, Action off, bool expensive = false, float size = SmallIconSize, diff --git a/Source/ManagerJobs/ManagerJob_Livestock.cs b/Source/ManagerJobs/ManagerJob_Livestock.cs index 1443bc21..35f1e0b1 100644 --- a/Source/ManagerJobs/ManagerJob_Livestock.cs +++ b/Source/ManagerJobs/ManagerJob_Livestock.cs @@ -31,6 +31,9 @@ public class ManagerJob_Livestock : ManagerJob public bool RespectBonds = true; public List RestrictArea; public bool RestrictToArea; + public List RestrictHungryArea; + public bool RestrictToHungryArea; + public float SendToHungryAreaMaximumFoodNeed; public bool SendToSlaughterArea; public bool SendToTrainingArea; public bool SetFollow; @@ -72,6 +75,11 @@ public ManagerJob_Livestock( Manager manager ) : base( manager ) RestrictToArea = false; RestrictArea = Utilities_Livestock.AgeSexArray.Select( k => (Area) null ).ToList(); + // set hungry animals areas for restriction + RestrictToHungryArea = false; + SendToHungryAreaMaximumFoodNeed = 0.01f; + RestrictHungryArea = Utilities_Livestock.AgeSexArray.Select(k => (Area)null).ToList(); + // set up sending animals designated for slaughter to an area (freezer) SendToSlaughterArea = false; SlaughterArea = null; @@ -141,6 +149,7 @@ public override void ExposeData() Scribe_References.Look( ref Master, "Master" ); Scribe_References.Look( ref Trainer, "Trainer" ); Scribe_Collections.Look( ref RestrictArea, "AreaRestrictions", LookMode.Reference ); + Scribe_Collections.Look(ref RestrictHungryArea, "HungryAreaRestrictions", LookMode.Reference); Scribe_Deep.Look( ref Trigger, "trigger", manager ); Scribe_Deep.Look( ref Training, "Training" ); Scribe_Deep.Look( ref _history, "History" ); @@ -149,6 +158,8 @@ public override void ExposeData() Scribe_Values.Look( ref ButcherPregnant, "ButcherPregnant" ); Scribe_Values.Look( ref ButcherBonded, "ButcherBonded" ); Scribe_Values.Look( ref RestrictToArea, "RestrictToArea" ); + Scribe_Values.Look( ref RestrictToHungryArea, "RestrictToHungryArea", false); + Scribe_Values.Look( ref SendToHungryAreaMaximumFoodNeed, "SendToHungryAreaMaximumFoodNeed", 0.01f); Scribe_Values.Look( ref SendToSlaughterArea, "SendToSlaughterArea" ); Scribe_Values.Look( ref SendToTrainingArea, "SendToTrainingArea" ); Scribe_Values.Look( ref TryTameMore, "TryTameMore" ); @@ -221,6 +232,12 @@ private void DoAreaRestrictions( ref bool actionTaken ) p.playerSettings.AreaRestriction = SlaughterArea; } + // hungry + else if (RestrictToHungryArea && p.needs.food.CurLevelPercentage <= SendToHungryAreaMaximumFoodNeed) + { + actionTaken = true; + p.playerSettings.AreaRestriction = RestrictHungryArea[i]; + } // training else if ( SendToTrainingArea && p.training.NextTrainableToTrain() != null ) { diff --git a/Source/ManagerTabs/ManagerTab_Livestock.cs b/Source/ManagerTabs/ManagerTab_Livestock.cs index b3a4d262..8f9024d1 100644 --- a/Source/ManagerTabs/ManagerTab_Livestock.cs +++ b/Source/ManagerTabs/ManagerTab_Livestock.cs @@ -361,44 +361,8 @@ private float DrawAreaRestrictionsSection( Vector2 pos, float width ) if ( _selectedCurrent.RestrictToArea ) { - // area selectors table - // set up a 3x3 table of rects - var cols = 3; - var fifth = width / 5; - float[] widths = {fifth, fifth * 2, fifth * 2}; - float[] heights = {ListEntryHeight * 2 / 3, ListEntryHeight, ListEntryHeight}; - - var areaRects = new Rect[cols, cols]; - for ( var x = 0; x < cols; x++ ) - for ( var y = 0; y < cols; y++ ) - areaRects[x, y] = new Rect( - widths.Take( x ).Sum(), - pos.y + heights.Take( y ).Sum(), - widths[x], - heights[y] ); - - // headers - Label( areaRects[1, 0], Gender.Female.ToString(), TextAnchor.LowerCenter, GameFont.Tiny ); - Label( areaRects[2, 0], Gender.Male.ToString(), TextAnchor.LowerCenter, GameFont.Tiny ); - Label( areaRects[0, 1], "FML.Adult".Translate(), TextAnchor.MiddleRight, GameFont.Tiny ); - Label( areaRects[0, 2], "FML.Juvenile".Translate(), TextAnchor.MiddleRight, GameFont.Tiny ); - - // do the selectors - _selectedCurrent.RestrictArea[0] = AreaAllowedGUI.DoAllowedAreaSelectors( areaRects[1, 1], - _selectedCurrent.RestrictArea[ - 0], manager, Margin ); - _selectedCurrent.RestrictArea[1] = AreaAllowedGUI.DoAllowedAreaSelectors( areaRects[2, 1], - _selectedCurrent.RestrictArea[ - 1], manager, Margin ); - _selectedCurrent.RestrictArea[2] = AreaAllowedGUI.DoAllowedAreaSelectors( areaRects[1, 2], - _selectedCurrent.RestrictArea[ - 2], manager, Margin ); - _selectedCurrent.RestrictArea[3] = AreaAllowedGUI.DoAllowedAreaSelectors( areaRects[2, 2], - _selectedCurrent.RestrictArea[ - 3], manager, Margin ); - - Text.Anchor = TextAnchor.UpperLeft; // DoAllowedAreaMode leaves the anchor in an incorrect state. - pos.y += 3 * ListEntryHeight; + DrawAreaSelectorPerGenderAndAge(pos, width, ref _selectedCurrent.RestrictArea); + pos.y += 3 * ListEntryHeight; } var sendToSlaughterAreaRect = new Rect( pos.x, pos.y, width, ListEntryHeight ); @@ -426,6 +390,29 @@ private float DrawAreaRestrictionsSection( Vector2 pos, float width ) color: Color.grey ); } + // restrict to hungry area + var RestrictHungryAreaRect = new Rect(pos.x, pos.y, width, ListEntryHeight); + + DrawToggle(RestrictHungryAreaRect, + "FML.RestrictToHungryArea".Translate(), + "FML.RestrictToHungryArea.Tip".Translate(), + ref _selectedCurrent.RestrictToHungryArea); + pos.y += ListEntryHeight; + if (_selectedCurrent.RestrictToHungryArea) + { + if (_selectedCurrent.RestrictHungryArea.Count != _selectedCurrent.RestrictArea.Count) + { + _selectedCurrent.RestrictHungryArea = Utilities_Livestock.AgeSexArray.Select(k => (Area)null).ToList(); + } + DrawAreaSelectorPerGenderAndAge(pos, width, ref _selectedCurrent.RestrictHungryArea); + pos.y += 3 * ListEntryHeight; + var HungryAreaFoodFullness = new Rect(pos.x, pos.y, width, ListEntryHeight); + HungryAreaFoodFullness.xMin += 3 * Margin; + DrawSlider(HungryAreaFoodFullness, "FML.SendToHungryAreaMaximumFoodNeed.Label".Translate(), "FML.SendToHungryAreaMaximumFoodNeed.Tip".Translate(), + ref _selectedCurrent.SendToHungryAreaMaximumFoodNeed); + pos.y += ListEntryHeight; + } + var sendToTrainingAreaRect = new Rect( pos.x, pos.y, width, ListEntryHeight ); pos.y += ListEntryHeight; if ( _selectedCurrent.Training.Any ) @@ -454,6 +441,41 @@ private float DrawAreaRestrictionsSection( Vector2 pos, float width ) return pos.y - start.y; } + + + private void DrawAreaSelectorPerGenderAndAge(Vector2 pos, float width, ref List restrictArea) + { + // area selectors table + // set up a 3x3 table of rects + var cols = 3; + var fifth = width / 5; + float[] widths = { fifth, fifth * 2, fifth * 2 }; + float[] heights = { ListEntryHeight * 2 / 3, ListEntryHeight, ListEntryHeight }; + + var areaRects = new Rect[cols, cols]; + for (var x = 0; x < cols; x++) + for (var y = 0; y < cols; y++) + areaRects[x, y] = new Rect( + widths.Take(x).Sum(), + pos.y + heights.Take(y).Sum(), + widths[x], + heights[y]); + + // headers + Label(areaRects[1, 0], Gender.Female.ToString(), TextAnchor.LowerCenter, GameFont.Tiny); + Label(areaRects[2, 0], Gender.Male.ToString(), TextAnchor.LowerCenter, GameFont.Tiny); + Label(areaRects[0, 1], "FML.Adult".Translate(), TextAnchor.MiddleRight, GameFont.Tiny); + Label(areaRects[0, 2], "FML.Juvenile".Translate(), TextAnchor.MiddleRight, GameFont.Tiny); + + // do the selectors + restrictArea[0] = AreaAllowedGUI.DoAllowedAreaSelectors(areaRects[1, 1], restrictArea[0], manager, Margin); + restrictArea[1] = AreaAllowedGUI.DoAllowedAreaSelectors(areaRects[2, 1], restrictArea[1], manager, Margin); + restrictArea[2] = AreaAllowedGUI.DoAllowedAreaSelectors(areaRects[1, 2], restrictArea[2], manager, Margin); + restrictArea[3] = AreaAllowedGUI.DoAllowedAreaSelectors(areaRects[2, 2], restrictArea[3], manager, Margin); + + Text.Anchor = TextAnchor.UpperLeft; // DoAllowedAreaMode leaves the anchor in an incorrect state. + } + private float DrawTrainingSection( Vector2 pos, float width ) { var trainingRect = new Rect( pos.x, pos.y, width, ListEntryHeight );