public BillGiverTracker(ManagerJob_Production job) { manager = job.manager; Recipe = job.Bill.recipe; _job = job; _assignedBills = new Dictionary <Bill_Production, Building_WorkTable>(); SpecificBillGivers = new List <Building_WorkTable>(); }
public BillGiverTracker( ManagerJob_Production job ) { manager = job.manager; Recipe = job.Bill.recipe; _job = job; _assignedBills = new Dictionary<Bill_Production, Building_WorkTable>(); SpecificBillGivers = new List<Building_WorkTable>(); }
public Trigger_Threshold( ManagerJob_Production job ) : base(job.manager) { Op = Ops.LowerThan; MaxUpperThreshold = job.MainProduct.MaxUpperThreshold; // TODO: Better way of setting sensible defaults? Count = MaxUpperThreshold / 20; ThresholdFilter = new ThingFilter(); ThresholdFilter.SetDisallowAll(); if ( job.MainProduct.ThingDef != null ) { ThresholdFilter.SetAllow( job.MainProduct.ThingDef, true ); } if ( job.MainProduct.CategoryDef != null ) { ThresholdFilter.SetAllow( job.MainProduct.CategoryDef, true ); } }
public Trigger_Threshold( ManagerJob_Production job ) : base(job.manager) { Op = Ops.LowerThan; MaxUpperThreshold = job.MainProduct.MaxUpperThreshold; // TODO: Better way of setting sensible defaults? Count = MaxUpperThreshold / 20; ThresholdFilter = new ThingFilter(); ThresholdFilter.SetDisallowAll(); if ( job.MainProduct.ThingDef != null ) { ThresholdFilter.SetAllow( job.MainProduct.ThingDef, true ); } if ( job.MainProduct.CategoryDef != null ) { ThresholdFilter.SetAllow( job.MainProduct.CategoryDef, true ); } }
public void AddBills() { // only proceed if we selected an ingredient/thingdef (recipeSelector != null), and there is a recipe selected. if (recipeSelector?.selectedRecipe == null) { return; } // try to get a job with our recipe RecipeDef curRecipe = recipeSelector.selectedRecipe; ManagerJob_Production curJob = manager.JobStack.FullStack <ManagerJob_Production>() .FirstOrDefault(job => job.Bill.recipe == curRecipe); // if there is a job for the recipe, add our job's count - any settings beyond that are user responsibility. if (curJob != null && curJob.Trigger.Count < targetCount) { curJob.Trigger.Count = targetCount; Messages.Message("FMP.IncreasedThreshold".Translate(curRecipe.LabelCap, targetCount), MessageSound.Benefit); } // otherwise create a new job. else { curJob = new ManagerJob_Production(manager, curRecipe); // make sure the trigger is valid (everything else is user responsibility). if (curJob.Trigger.IsValid) { curJob.Managed = true; manager.JobStack.Add(curJob); Messages.Message("FMP.AddedJob".Translate(curRecipe.LabelCap), MessageSound.Benefit); } else { Messages.Message("FMP.CouldNotAddJob".Translate(curRecipe.LabelCap), MessageSound.RejectInput); } } // finally, call this method on all of our children foreach (IngredientSelector child in recipeSelector.children) { child.AddBills(); } }
public void DoContent( Rect canvas ) { Widgets.DrawMenuSection( canvas ); GUI.BeginGroup( canvas ); canvas = canvas.AtZero(); if ( _selected != null ) { // bottom buttons Rect buttonRect = new Rect( canvas.xMax - _button.x, canvas.yMax - _button.y, _button.x - _margin, _button.y - _margin ); Rect ingredientCheck = new Rect( buttonRect.xMin - 300f - _margin, buttonRect.yMin, 300f, buttonRect.height ); // add / remove to the stack if ( Source == SourceOptions.Current ) { if ( Widgets.TextButton( buttonRect, "FM.Delete".Translate() ) ) { _selected.Delete(); _selected = null; Refresh(); return; // just skip to the next tick to avoid null reference errors. } TooltipHandler.TipRegion( buttonRect, "FMP.DeleteBillTooltip".Translate() ); } else { if ( _selected.Trigger.IsValid ) { Widgets.LabelCheckbox(ingredientCheck, "FMP.IngredientDialogTitle".Translate(), ref _selected._createIngredientBills, !_selected._hasMeaningfulIngredientChoices); if ( Widgets.TextButton( buttonRect, "FM.Manage".Translate() ) ) { _selected.Managed = true; Manager.Get.JobStack.Add( _selected ); // refresh source list so that the next added job is not an exact copy. Refresh(); if ( _selected._hasMeaningfulIngredientChoices && _selected._createIngredientBills ) { Find.WindowStack.Add( new Dialog_CreateJobsForIngredients( _selected.Bill.recipe, _selected.Trigger.Count ) ); } Source = SourceOptions.Current; Refresh(); SourceFilter = ""; } TooltipHandler.TipRegion( buttonRect, "FMP.ManageBillTooltip".Translate() ); } else { GUI.color = new Color( .6f, .6f, .6f ); Widgets.DrawBox( buttonRect ); Utilities.Label( buttonRect, "FMP.NoThreshold".Translate(), "FMP.NoThresholdTooltip".Translate(), TextAnchor.MiddleCenter ); GUI.color = Color.white; } } // options Rect optionsColumnRect = new Rect( _margin / 2, _topAreaHeight, canvas.width / 2 - _margin, canvas.height - _topAreaHeight - _margin - _button.y ); Rect recipeColumnRect = new Rect( optionsColumnRect.xMax + _margin, _topAreaHeight, canvas.width / 2 - _margin, canvas.height - _topAreaHeight - _margin - _button.y ); Rect optionsColumnTitle = new Rect( optionsColumnRect.xMin, 0f, optionsColumnRect.width, _topAreaHeight ); Rect recipeColumnTitle = new Rect( recipeColumnRect.xMin, 0f, recipeColumnRect.width, _topAreaHeight ); // backgrounds GUI.DrawTexture( optionsColumnRect, Resources.SlightlyDarkBackground ); GUI.DrawTexture( recipeColumnRect, Resources.SlightlyDarkBackground ); // titles Utilities.Label( optionsColumnTitle, "FMP.Options".Translate(), anchor: TextAnchor.LowerLeft, lrMargin: _margin * 2, font: GameFont.Tiny ); Utilities.Label( recipeColumnTitle, "FMP.Recipe".Translate(), anchor: TextAnchor.LowerLeft, lrMargin: _margin * 2, font: GameFont.Tiny ); // options GUI.BeginGroup( optionsColumnRect ); Vector2 cur = Vector2.zero; float width = optionsColumnRect.width; // keep track of optionIndex for shading purposes (lazy way to avoid having to redo this all the damn time). int optionindex = 0; // suspended Rect suspendedRect = new Rect( cur.x, cur.y, width, _entryHeight ); if (optionindex++ % 2 == 0) Widgets.DrawAltRect( suspendedRect ); Utilities.DrawToggle( suspendedRect, "Suspended".Translate(), _selected.Suspended, delegate { _selected.Suspended = !_selected.Suspended; } ); cur.y += _entryHeight; // store mode Rect takeToStockRect = new Rect( cur.x, cur.y, width, _entryHeight ); if( optionindex++ % 2 == 0 ) Widgets.DrawAltRect( takeToStockRect ); Utilities.DrawToggle( takeToStockRect, "BillStoreMode_BestStockpile".Translate(), _selected.Bill.storeMode == BillStoreMode.BestStockpile, delegate { _selected.Bill.storeMode = BillStoreMode.BestStockpile; }, delegate { _selected.Bill.storeMode = BillStoreMode.DropOnFloor; } ); cur.y += _entryHeight; // ingredient search radius (3) Rect searchRadiusLabelRect = new Rect( cur.x, cur.y, width, _entryHeight ); if( optionindex % 2 == 0 ) Widgets.DrawAltRect( searchRadiusLabelRect ); Utilities.Label( searchRadiusLabelRect, "IngredientSearchRadius".Translate() + ": " + _selected.Bill.ingredientSearchRadius.ToString( " #####0" ), anchor: TextAnchor.MiddleLeft, lrMargin: _margin ); cur.y += _entryHeight; Rect searchRadiusRect = new Rect( cur.x, cur.y, width, Utilities.SliderHeight ); if( optionindex++ % 2 == 0 ) Widgets.DrawAltRect( searchRadiusRect ); _selected.Bill.ingredientSearchRadius = (int)GUI.HorizontalSlider( searchRadiusRect, _selected.Bill.ingredientSearchRadius, 0f, 250f ); cur.y += Utilities.SliderHeight; // prioritize over manually set jobs (4) Rect prioritizeRect = new Rect( cur.x, cur.y, width, _entryHeight ); if( optionindex++ % 2 == 0 ) Widgets.DrawAltRect( prioritizeRect ); Utilities.DrawToggle(prioritizeRect, "FMP.PrioritizeManual".Translate(), ref ManagerJob_Production.prioritizeManual); cur.y += _entryHeight; // min skill (5) if ( _selected.Bill.recipe.workSkill != null ) { Rect skillLabelRect = new Rect( cur.x, cur.y, width, _entryHeight ); if( optionindex % 2 == 0 ) Widgets.DrawAltRect( skillLabelRect ); Utilities.Label( skillLabelRect, "MinimumSkillLevel".Translate( _selected.Bill.recipe.workSkill.label.ToLower() ) + ": " + _selected.Bill.minSkillLevel.ToString( "#####0" ), anchor: TextAnchor.MiddleLeft, lrMargin: 6f ); cur.y += _entryHeight; Rect skillRect = new Rect( cur.x, cur.y, width, Utilities.SliderHeight ); if( optionindex % 2 == 0 ) Widgets.DrawAltRect( skillRect ); _selected.Bill.minSkillLevel = (int)GUI.HorizontalSlider( skillRect, _selected.Bill.minSkillLevel, 0f, 20f ); cur.y += Utilities.SliderHeight; Rect snapToHighestRect = new Rect( cur.x, cur.y, width, _entryHeight ); if( optionindex++ % 2 == 0 ) Widgets.DrawAltRect( snapToHighestRect ); Utilities.DrawToggle( snapToHighestRect, "FMP.SnapToHighestSkill".Translate(), ref _selected.maxSkil ); cur.y += _entryHeight; } // draw threshold and billgiver config (6, 7) _selected.Trigger.DrawTriggerConfig( ref cur, optionsColumnRect.width, _entryHeight, optionindex++ % 2 == 0 ); _selected.BillGivers.DrawBillGiverConfig( ref cur, optionsColumnRect.width, _entryHeight, optionindex++ % 2 == 0 ); // add a better recipe available notification with corresponding float menu if other recipe options are available. if( _selected.Managed && _selected.OtherRecipeAvailable() ) { Rect otherRecipeAvailableRect = new Rect(cur.x, cur.y, width, _entryHeight); Utilities.Label( otherRecipeAvailableRect, "FMP.OtherRecipeAvailable".Translate(), "FMP.OtherRecipeAvailableTooltip".Translate() ); Widgets.DrawHighlightIfMouseover( otherRecipeAvailableRect ); if ( optionindex++ % 2 == 0 ) Widgets.DrawAltRect(otherRecipeAvailableRect); // add a little icon to mark interactivity Rect searchIconRect = new Rect( otherRecipeAvailableRect.xMax - Utilities.Margin - _entryHeight, cur.y, _entryHeight, _entryHeight ); if( searchIconRect.height > Utilities.SmallIconSize ) { // center it. searchIconRect = searchIconRect.ContractedBy( ( searchIconRect.height - Utilities.SmallIconSize ) / 2 ); } GUI.DrawTexture( searchIconRect, Resources.Search ); // draw a floatmenu on click if( Widgets.InvisibleButton( otherRecipeAvailableRect ) ) { List<FloatMenuOption> options = new List<FloatMenuOption>(); string curLabel = "Current: " + _selected.Label + " (<i>" + string.Join( ", ", _selected.Targets ) + "</i>)"; options.Add(new FloatMenuOption( curLabel, null)); foreach( RecipeDef recipe in _selected.OtherRecipeDefs ) { string label = recipe.LabelCap + " (<i>" + string.Join( ", ", recipe.GetRecipeUsers().Select( td => td.LabelCap ).ToArray()) + "</i>)"; Action action = delegate { _selected.SetNewRecipe( recipe ); _selected.ForceRecacheOtherRecipe(); }; options.Add( new FloatMenuOption( label, action ) ); } Find.WindowStack.Add( new FloatMenu( options ) ); } cur.y += _entryHeight; } GUI.EndGroup(); // options // bill GUI.BeginGroup( recipeColumnRect ); cur = Vector2.zero; width = recipeColumnRect.width; // bill information Rect infoRect = new Rect( cur.x, cur.y, width, ( recipeColumnRect.height - cur.y ) / 2 ); string text = GetInfoText(); float actualHeight = Text.CalcHeight( text, infoRect.width ); // if required height is small, cull info area if ( infoRect.height > actualHeight ) { infoRect.height = actualHeight; } // set up scrolling region Rect infoViewRect = infoRect; if ( actualHeight > infoRect.height ) { infoViewRect.width -= 16f; // scrollbar infoViewRect.height = Text.CalcHeight( text, infoViewRect.width ); } Widgets.BeginScrollView( infoRect, ref _infoScrollPosition, infoViewRect ); Utilities.Label( infoRect, text, anchor: TextAnchor.UpperLeft, lrMargin: _margin ); Widgets.EndScrollView(); // if there is one or more products known to us (so not smelting, ugh!) display an infocard button if ( _selected.Bill.recipe.products.Count > 0 ) { Widgets.InfoCardButton( infoRect.xMax - Widgets.InfoCardButtonSize - _margin, infoRect.yMin + _margin, _selected.Bill.recipe.products[0].thingDef ); } cur.y += infoRect.height; // ingredients label Rect ingredientsLabelRect = new Rect( cur.x, cur.y, width, _entryHeight ); Utilities.Label( ingredientsLabelRect, "FMP.AllowedIngredients".Translate(), anchor: TextAnchor.MiddleLeft, lrMargin: _margin ); cur.y += _entryHeight; // ingredients picker, fill available space Rect ingredientsRect = new Rect( cur.x, cur.y, width, recipeColumnRect.height - cur.y ); filterUI.DoThingFilterConfigWindow( ingredientsRect, ref IngredientsScrollPosition, _selected.Bill.ingredientFilter, _selected.Bill.recipe.fixedIngredientFilter, 4 ); GUI.EndGroup(); // bill } GUI.EndGroup(); // window }
public void DoLeftRow( Rect canvas ) { Widgets.DrawMenuSection( canvas, false ); // filter Rect filterRect = new Rect( 10f, canvas.yMin + 5f, canvas.width - _leftRowEntryHeight, _entryHeight ); GUI.SetNextControlName( "filterTextfield" ); SourceFilter = Widgets.TextField( filterRect, SourceFilter ); if ( !_postOpenFocus ) { GUI.FocusControl( "filterTextfield" ); _postOpenFocus = true; } if ( SourceFilter != "" ) { Rect clearFilter = new Rect( filterRect.width + 10f, filterRect.yMin, _entryHeight, _entryHeight ); if ( Widgets.ImageButton( clearFilter, Widgets.CheckboxOffTex ) ) { SourceFilter = ""; } TooltipHandler.TipRegion( clearFilter, "FMP.ClearFilterDesc".Translate() ); } TooltipHandler.TipRegion( filterRect, "FMP.FilterDesc".Translate() ); // tabs List<TabRecord> list = new List<TabRecord>(); TabRecord availableTabRecord = new TabRecord( "FMP.Available".Translate(), delegate { Source = SourceOptions.Available; Refresh(); }, Source == SourceOptions.Available ); list.Add( availableTabRecord ); TabRecord currentTabRecord = new TabRecord( "FMP.Current".Translate(), delegate { Source = SourceOptions.Current; Refresh(); }, Source == SourceOptions.Current ); list.Add( currentTabRecord ); TabDrawer.DrawTabs( canvas, list ); // content Rect scrollCanvas = canvas; scrollCanvas.yMin = scrollCanvas.yMin + _entryHeight + _margin; float height = SourceListHeight; Rect scrollView = new Rect( 0f, 0f, scrollCanvas.width, height ); if ( height > scrollCanvas.height ) { scrollView.width -= 16f; } Widgets.BeginScrollView( scrollCanvas, ref LeftRowScrollPosition, scrollView ); Rect scrollContent = scrollView; GUI.BeginGroup( scrollContent ); float y = 0; int i = 0; foreach ( ManagerJob_Production current in from job in SourceList where job.Bill.recipe.label.ToUpper() .Contains( SourceFilter.ToUpper() ) || job.MainProduct.Label.ToUpper() .Contains( SourceFilter.ToUpper() ) select job ) { Rect row = new Rect( 0f, y, scrollContent.width, Utilities.LargeListEntryHeight ); Widgets.DrawHighlightIfMouseover( row ); if ( _selected == current ) { Widgets.DrawHighlightSelected( row ); } if ( i++ % 2 == 1 ) { Widgets.DrawAltRect( row ); } Rect jobRect = row; if ( Source == SourceOptions.Current ) { if ( ManagerTab_Overview.DrawOrderButtons( new Rect( row.xMax - _leftRowEntryHeight, row.yMin, _leftRowEntryHeight, _leftRowEntryHeight ), current ) ) { Refresh(); } jobRect.width -= _leftRowEntryHeight; } current.DrawListEntry( jobRect, false, Source == SourceOptions.Current ); if ( Widgets.InvisibleButton( jobRect ) ) { _selected = current; } y += Utilities.LargeListEntryHeight; } SourceListHeight = y; GUI.EndGroup(); Widgets.EndScrollView(); }
public void DoLeftRow(Rect canvas) { Widgets.DrawMenuSection(canvas, false); // filter var filterRect = new Rect(10f, canvas.yMin + 5f, canvas.width - _leftRowEntryHeight, _entryHeight); GUI.SetNextControlName("filterTextfield"); SourceFilter = Widgets.TextField(filterRect, SourceFilter); if (!_postOpenFocus) { GUI.FocusControl("filterTextfield"); _postOpenFocus = true; } if (SourceFilter != "") { var clearFilter = new Rect(filterRect.width + 10f, filterRect.yMin, _entryHeight, _entryHeight); if (Widgets.ButtonImage(clearFilter, Widgets.CheckboxOffTex)) { SourceFilter = ""; } TooltipHandler.TipRegion(clearFilter, "FMP.ClearFilterDesc".Translate()); } TooltipHandler.TipRegion(filterRect, "FMP.FilterDesc".Translate()); // tabs var list = new List <TabRecord>(); var availableTabRecord = new TabRecord("FMP.Available".Translate(), delegate { Source = SourceOptions.Available; Refresh(); }, Source == SourceOptions.Available); list.Add(availableTabRecord); var currentTabRecord = new TabRecord("FMP.Current".Translate(), delegate { Source = SourceOptions.Current; Refresh(); }, Source == SourceOptions.Current); list.Add(currentTabRecord); TabDrawer.DrawTabs(canvas, list); // content Rect scrollCanvas = canvas; scrollCanvas.yMin = scrollCanvas.yMin + _entryHeight + _margin; float height = SourceListHeight; var scrollView = new Rect(0f, 0f, scrollCanvas.width, height); if (height > scrollCanvas.height) { scrollView.width -= 16f; } Widgets.BeginScrollView(scrollCanvas, ref LeftRowScrollPosition, scrollView); Rect scrollContent = scrollView; GUI.BeginGroup(scrollContent); float y = 0; var i = 0; foreach (ManagerJob_Production current in from job in SourceList where job.Bill.recipe.label.ToUpper() .Contains(SourceFilter.ToUpper()) || job.MainProduct.Label.ToUpper() .Contains(SourceFilter.ToUpper()) select job) { var row = new Rect(0f, y, scrollContent.width, Utilities.LargeListEntryHeight); Widgets.DrawHighlightIfMouseover(row); if (_selected == current) { Widgets.DrawHighlightSelected(row); } if (i++ % 2 == 1) { Widgets.DrawAltRect(row); } Rect jobRect = row; if (Source == SourceOptions.Current) { if (ManagerTab_Overview.DrawOrderButtons( new Rect(row.xMax - _leftRowEntryHeight, row.yMin, _leftRowEntryHeight, _leftRowEntryHeight), manager, current)) { Refresh(); } jobRect.width -= _leftRowEntryHeight; } current.DrawListEntry(jobRect, false, Source == SourceOptions.Current); if (Widgets.ButtonInvisible(jobRect)) { _selected = current; } y += Utilities.LargeListEntryHeight; } SourceListHeight = y; GUI.EndGroup(); Widgets.EndScrollView(); }
public void DoContent(Rect canvas) { Widgets.DrawMenuSection(canvas); GUI.BeginGroup(canvas); canvas = canvas.AtZero(); if (_selected != null) { // bottom buttons var buttonRect = new Rect(canvas.xMax - _button.x, canvas.yMax - _button.y, _button.x - _margin, _button.y - _margin); var ingredientCheck = new Rect(buttonRect.xMin - 300f - _margin, buttonRect.yMin, 300f, buttonRect.height); // add / remove to the stack if (Source == SourceOptions.Current) { if (Widgets.ButtonText(buttonRect, "FM.Delete".Translate())) { _selected.Delete(); _selected = null; Refresh(); return; // just skip to the next tick to avoid null reference errors. } TooltipHandler.TipRegion(buttonRect, "FMP.DeleteBillTooltip".Translate()); } else { if (_selected.Trigger.IsValid) { Widgets.CheckboxLabeled(ingredientCheck, "FMP.IngredientDialogTitle".Translate(), ref _selected._createIngredientBills, !_selected._hasMeaningfulIngredientChoices); if (Widgets.ButtonText(buttonRect, "FM.Manage".Translate())) { _selected.Managed = true; manager.JobStack.Add(_selected); // refresh source list so that the next added job is not an exact copy. Refresh(); if (_selected._hasMeaningfulIngredientChoices && _selected._createIngredientBills) { Find.WindowStack.Add(new Dialog_CreateJobsForIngredients(manager, _selected.Bill.recipe, _selected.Trigger.Count)); } Source = SourceOptions.Current; Refresh(); SourceFilter = ""; } TooltipHandler.TipRegion(buttonRect, "FMP.ManageBillTooltip".Translate()); } else { GUI.color = new Color(.6f, .6f, .6f); Widgets.DrawBox(buttonRect); Utilities.Label(buttonRect, "FMP.NoThreshold".Translate(), "FMP.NoThresholdTooltip".Translate(), TextAnchor.MiddleCenter); GUI.color = Color.white; } } // options var optionsColumnRect = new Rect(_margin / 2, _topAreaHeight, canvas.width / 2 - _margin, canvas.height - _topAreaHeight - _margin - _button.y); var recipeColumnRect = new Rect(optionsColumnRect.xMax + _margin, _topAreaHeight, canvas.width / 2 - _margin, canvas.height - _topAreaHeight - _margin - _button.y); var optionsColumnTitle = new Rect(optionsColumnRect.xMin, 0f, optionsColumnRect.width, _topAreaHeight); var recipeColumnTitle = new Rect(recipeColumnRect.xMin, 0f, recipeColumnRect.width, _topAreaHeight); // backgrounds GUI.DrawTexture(optionsColumnRect, Resources.SlightlyDarkBackground); GUI.DrawTexture(recipeColumnRect, Resources.SlightlyDarkBackground); // titles Utilities.Label(optionsColumnTitle, "FMP.Options".Translate(), anchor: TextAnchor.LowerLeft, lrMargin: _margin * 2, font: GameFont.Tiny); Utilities.Label(recipeColumnTitle, "FMP.Recipe".Translate(), anchor: TextAnchor.LowerLeft, lrMargin: _margin * 2, font: GameFont.Tiny); // options GUI.BeginGroup(optionsColumnRect); Vector2 cur = Vector2.zero; float width = optionsColumnRect.width; // keep track of optionIndex for shading purposes (lazy way to avoid having to redo this all the damn time). var optionindex = 0; // suspended var suspendedRect = new Rect(cur.x, cur.y, width, _entryHeight); if (optionindex++ % 2 == 0) { Widgets.DrawAltRect(suspendedRect); } Utilities.DrawToggle(suspendedRect, "Suspended".Translate(), _selected.Suspended, delegate { _selected.Suspended = !_selected.Suspended; }); cur.y += _entryHeight; // store mode var takeToStockRect = new Rect(cur.x, cur.y, width, _entryHeight); if (optionindex++ % 2 == 0) { Widgets.DrawAltRect(takeToStockRect); } Utilities.DrawToggle(takeToStockRect, "BillStoreMode_BestStockpile".Translate(), _selected.Bill.storeMode == BillStoreMode.BestStockpile, delegate { _selected.Bill.storeMode = BillStoreMode.BestStockpile; }, delegate { _selected.Bill.storeMode = BillStoreMode.DropOnFloor; }); cur.y += _entryHeight; // ingredient search radius (3) var searchRadiusLabelRect = new Rect(cur.x, cur.y, width, _entryHeight); if (optionindex % 2 == 0) { Widgets.DrawAltRect(searchRadiusLabelRect); } Utilities.Label(searchRadiusLabelRect, "IngredientSearchRadius".Translate() + ": " + _selected.Bill.ingredientSearchRadius.ToString(" #####0"), anchor: TextAnchor.MiddleLeft, lrMargin: _margin); cur.y += _entryHeight; var searchRadiusRect = new Rect(cur.x, cur.y, width, Utilities.SliderHeight); if (optionindex++ % 2 == 0) { Widgets.DrawAltRect(searchRadiusRect); } _selected.Bill.ingredientSearchRadius = (int)GUI.HorizontalSlider(searchRadiusRect, _selected.Bill.ingredientSearchRadius, 0f, 250f); cur.y += Utilities.SliderHeight; // prioritize over manually set jobs (4) var prioritizeRect = new Rect(cur.x, cur.y, width, _entryHeight); if (optionindex++ % 2 == 0) { Widgets.DrawAltRect(prioritizeRect); } Utilities.DrawToggle(prioritizeRect, "FMP.PrioritizeManual".Translate(), ref ManagerJob_Production.prioritizeManual); cur.y += _entryHeight; // skill range (5) if (_selected.Bill.recipe.workSkill != null) { var skillLabelRect = new Rect(cur.x, cur.y, width, _entryHeight); if (optionindex % 2 == 0) { Widgets.DrawAltRect(skillLabelRect); } Utilities.Label(skillLabelRect, "FMP.AllowedSkillRange".Translate() + ": " + _selected.Bill.allowedSkillRange); cur.y += _entryHeight; var skillRect = new Rect(cur.x, cur.y, width, Utilities.SliderHeight); if (optionindex % 2 == 0) { Widgets.DrawAltRect(skillRect); } Widgets.IntRange(skillRect, 2134112311, ref _selected.Bill.allowedSkillRange, 0, 20); cur.y += Utilities.SliderHeight; var snapToHighestRect = new Rect(cur.x, cur.y, width, _entryHeight); if (optionindex++ % 2 == 0) { Widgets.DrawAltRect(snapToHighestRect); } Utilities.DrawToggle(snapToHighestRect, "FMP.SnapToHighestSkill".Translate(), ref _selected.restrictToMaxSkill); cur.y += _entryHeight; } // draw threshold and billgiver config (6, 7) _selected.Trigger.DrawTriggerConfig(ref cur, optionsColumnRect.width, _entryHeight, optionindex++ % 2 == 0); _selected.BillGivers.DrawBillGiverConfig(ref cur, optionsColumnRect.width, _entryHeight, optionindex++ % 2 == 0); // add a better recipe available notification with corresponding float menu if other recipe options are available. if (_selected.Managed && _selected.OtherRecipeAvailable()) { var otherRecipeAvailableRect = new Rect(cur.x, cur.y, width, _entryHeight); Utilities.Label(otherRecipeAvailableRect, "FMP.OtherRecipeAvailable".Translate(), "FMP.OtherRecipeAvailableTooltip".Translate()); Widgets.DrawHighlightIfMouseover(otherRecipeAvailableRect); if (optionindex++ % 2 == 0) { Widgets.DrawAltRect(otherRecipeAvailableRect); } // add a little icon to mark interactivity var searchIconRect = new Rect(otherRecipeAvailableRect.xMax - Utilities.Margin - _entryHeight, cur.y, _entryHeight, _entryHeight); if (searchIconRect.height > Utilities.SmallIconSize) { // center it. searchIconRect = searchIconRect.ContractedBy((searchIconRect.height - Utilities.SmallIconSize) / 2); } GUI.DrawTexture(searchIconRect, Resources.Search); // draw a floatmenu on click if (Widgets.ButtonInvisible(otherRecipeAvailableRect)) { var options = new List <FloatMenuOption>(); string curLabel = "Current: " + _selected.Label + " (<i>" + string.Join(", ", _selected.Targets) + "</i>)"; options.Add(new FloatMenuOption(curLabel, null)); foreach (RecipeDef recipe in _selected.OtherRecipeDefs) { string label = recipe.LabelCap + " (<i>" + string.Join(", ", recipe.GetRecipeUsers().Select(td => td.LabelCap).ToArray()) + "</i>)"; Action action = delegate { _selected.SetNewRecipe(recipe); _selected.ForceRecacheOtherRecipe(); }; options.Add(new FloatMenuOption(label, action)); } Find.WindowStack.Add(new FloatMenu(options)); } cur.y += _entryHeight; } GUI.EndGroup(); // options // bill GUI.BeginGroup(recipeColumnRect); cur = Vector2.zero; width = recipeColumnRect.width; // bill information var infoRect = new Rect(cur.x, cur.y, width, (recipeColumnRect.height - cur.y) / 2); string text = GetInfoText(); float actualHeight = Text.CalcHeight(text, infoRect.width); // if required height is small, cull info area if (infoRect.height > actualHeight) { infoRect.height = actualHeight; } // set up scrolling region Rect infoViewRect = infoRect; if (actualHeight > infoRect.height) { infoViewRect.width -= 16f; // scrollbar infoViewRect.height = Text.CalcHeight(text, infoViewRect.width); } Widgets.BeginScrollView(infoRect, ref _infoScrollPosition, infoViewRect); Utilities.Label(infoRect, text, anchor: TextAnchor.UpperLeft, lrMargin: _margin); Widgets.EndScrollView(); // if there is one or more products known to us (so not smelting, ugh!) display an infocard button if (_selected.Bill.recipe.products.Count > 0) { Widgets.InfoCardButton(infoRect.xMax - Widgets.InfoCardButtonSize - _margin, infoRect.yMin + _margin, _selected.Bill.recipe.products[0].thingDef); } cur.y += infoRect.height; // ingredients label var ingredientsLabelRect = new Rect(cur.x, cur.y, width, _entryHeight); Utilities.Label(ingredientsLabelRect, "FMP.AllowedIngredients".Translate(), anchor: TextAnchor.MiddleLeft, lrMargin: _margin); cur.y += _entryHeight; // ingredients picker, fill available space var ingredientsRect = new Rect(cur.x, cur.y, width, recipeColumnRect.height - cur.y); filterUI.DoThingFilterConfigWindow(ingredientsRect, ref IngredientsScrollPosition, _selected.Bill.ingredientFilter, _selected.Bill.recipe.fixedIngredientFilter, 4); GUI.EndGroup(); // bill } GUI.EndGroup(); // window }
public void AddBills() { // only proceed if we selected an ingredient/thingdef (recipeSelector != null), and there is a recipe selected. if ( recipeSelector?.selectedRecipe == null ) { return; } // try to get a job with our recipe RecipeDef curRecipe = recipeSelector.selectedRecipe; ManagerJob_Production curJob = manager.JobStack.FullStack<ManagerJob_Production>() .FirstOrDefault( job => job.Bill.recipe == curRecipe ); // if there is a job for the recipe, add our job's count - any settings beyond that are user responsibility. if ( curJob != null && curJob.Trigger.Count < targetCount ) { curJob.Trigger.Count = targetCount; Messages.Message( "FMP.IncreasedThreshold".Translate( curRecipe.LabelCap, targetCount ), MessageSound.Benefit ); } // otherwise create a new job. else { curJob = new ManagerJob_Production( manager, curRecipe ); // make sure the trigger is valid (everything else is user responsibility). if ( curJob.Trigger.IsValid ) { curJob.Managed = true; manager.JobStack.Add( curJob ); Messages.Message( "FMP.AddedJob".Translate( curRecipe.LabelCap ), MessageSound.Benefit ); } else { Messages.Message( "FMP.CouldNotAddJob".Translate( curRecipe.LabelCap ), MessageSound.RejectInput ); } } // finally, call this method on all of our children foreach ( IngredientSelector child in recipeSelector.children ) { child.AddBills(); } }
/// <summary> /// Amount per worker to satsify the bill. /// </summary> /// <param name="job"></param> /// <param name="workerIndex"></param> /// <returns></returns> public static int CountPerWorker(this ManagerJob_Production job, int workerIndex) { int n = job.BillGivers.CurBillGiverCount; int diff = job.Trigger.Count - job.Trigger.CurCount; int bills; // if diff is negative we can assume this is a destructive job. if (diff < 0) { // default input count set to 1 float inputCount = 1; IEnumerable <ThingDef> filterThingDefs = job.Trigger.ThresholdFilter.AllowedThingDefs; // if the filter is a single thingdef, try to figure out what the input count of it is for the managed recipe. if (filterThingDefs?.Count() == 1) { // only one thingdef in the filter, so get the first. ThingDef filterThingDef = filterThingDefs.First(); // the ingredient list of the managed recipe. List <IngredientCount> ingredients = job.Bill.recipe.ingredients; // get the total input count of any ingredients that allow our thingdef (probably 0 or 1, but who knows - could be a stuff + specific listing). if (ingredients != null) { float?recipeInput = (ingredients?.Where( ing => ing .filter .AllowedThingDefs.Contains(filterThingDef))).Select(ing => ing .CountRequiredOfFor (filterThingDef, job .Bill .recipe)) .Sum(); // if this wasn't null or close to zero, set the reduction count per bill to this number. if (recipeInput != null && Math.Abs(recipeInput.Value) > 1) { inputCount = recipeInput.Value; } } } // divide by negative reduction amount per bill to get a positive number of bills. bills = Mathf.CeilToInt(diff / -inputCount); } else { // this one is a bit simpler - mainly because we already did the complicated stuff in the MainProduct class. bills = Mathf.CeilToInt(diff / job.MainProduct.Count); } // naive number of bills per worker (float) float naive = bills / (float)n; // round up or down to get a total that matches the desired total exactly if (bills % n > workerIndex) { return((int)Math.Floor(naive)); } return((int)Math.Ceiling(naive)); }