private float GetBaseEstimatedLifespan(SurvivalTool tool, BuildableDef def) { SurvivalToolProperties props = def.GetModExtension <SurvivalToolProperties>() ?? SurvivalToolProperties.defaultValues; if (!((ThingDef)def).useHitPoints) { return(float.PositiveInfinity); } // For def if (tool == null) { return(GenDate.TicksToDays(Mathf.RoundToInt((BaseWearInterval * def.GetStatValueAbstract(StatDefOf.MaxHitPoints)) / props.toolWearFactor))); } // For thing StuffPropsTool stuffProps = tool.Stuff?.GetModExtension <StuffPropsTool>() ?? StuffPropsTool.defaultValues; float wearFactor = tool.def.GetModExtension <SurvivalToolProperties>().toolWearFactor *(stuffProps.wearFactorMultiplier); return(GenDate.TicksToDays(Mathf.RoundToInt((BaseWearInterval * tool.MaxHitPoints) / wearFactor))); }
private static float SurvivalToolScore(Thing toolThing, List <StatDef> workRelevantStats) { SurvivalTool tool = toolThing as SurvivalTool; if (tool == null) { return(0f); } float optimality = 0f; foreach (StatDef stat in workRelevantStats) { optimality += StatUtility.GetStatValueFromList(tool.WorkStatFactors.ToList(), stat, 0f); } if (tool.def.useHitPoints) { float lifespanRemaining = tool.GetStatValue(ST_StatDefOf.ToolEstimatedLifespan, true) * ((float)tool.HitPoints * tool.MaxHitPoints); optimality *= LifespanDaysToOptimalityMultiplierCurve.Evaluate(lifespanRemaining); } return(optimality); }
public override string GetExplanationUnfinalized(StatRequest req, ToStringNumberSense numberSense) { SurvivalTool tool = req.Thing as SurvivalTool; return($"{"StatsReport_BaseValue".Translate()}: {GetBaseEstimatedLifespan(tool, req.BuildableDef).ToString("F1")}"); }
public override float GetValueUnfinalized(StatRequest req, bool applyPostProcess = true) { SurvivalTool tool = req.Thing as SurvivalTool; return(GetBaseEstimatedLifespan(tool, req.BuildableDef)); }
// This is a janky mess and a half, but works! protected override Job TryGiveJob(Pawn pawn) { if (SurvivalToolsSettings.toolOptimization) { Pawn_SurvivalToolAssignmentTracker assignmentTracker = pawn.TryGetComp <Pawn_SurvivalToolAssignmentTracker>(); // Pawn can't use tools, lacks a tool assignment tracker or it isn't yet time to re-optimise tools if (!pawn.CanUseSurvivalTools() || assignmentTracker == null || Find.TickManager.TicksGame < assignmentTracker.nextSurvivalToolOptimizeTick) { return(null); } // Check if current tool assignment allows for each tool, auto-removing those that aren't allowed. SurvivalToolAssignment curAssignment = assignmentTracker.CurrentSurvivalToolAssignment; List <Thing> heldTools = pawn.GetHeldSurvivalTools().ToList(); foreach (Thing tool in heldTools) { if ((!curAssignment.filter.Allows(tool) || !pawn.NeedsSurvivalTool((SurvivalTool)tool)) && assignmentTracker.forcedHandler.AllowedToAutomaticallyDrop(tool)) { return(pawn.DequipAndTryStoreSurvivalTool(tool)); } } // Look for better alternative tools to what the colonist currently has, based on what stats are relevant to the work types the colonist is assigned to List <Thing> heldUsableTools = heldTools.Where(t => heldTools.IndexOf(t).IsUnderSurvivalToolCarryLimitFor(pawn)).ToList(); List <Thing> mapTools = pawn.MapHeld.listerThings.AllThings.Where(t => t is SurvivalTool).ToList(); List <StatDef> workRelevantStats = pawn.AssignedToolRelevantWorkGiversStatDefs(); Thing curTool = null; Thing newTool = null; float optimality = 0f; foreach (StatDef stat in workRelevantStats) { curTool = pawn.GetBestSurvivalTool(stat); optimality = SurvivalToolScore(curTool, workRelevantStats); foreach (Thing potentialToolThing in mapTools) { SurvivalTool potentialTool = (SurvivalTool)potentialToolThing; if (StatUtility.StatListContains(potentialTool.WorkStatFactors.ToList(), stat) && curAssignment.filter.Allows(potentialTool) && potentialTool.BetterThanWorkingToollessFor(stat) && pawn.CanUseSurvivalTool(potentialTool.def) && potentialTool.IsInAnyStorage() && !potentialTool.IsForbidden(pawn) && !potentialTool.IsBurning()) { float potentialOptimality = SurvivalToolScore(potentialTool, workRelevantStats); float delta = potentialOptimality - optimality; if (delta > 0f && pawn.CanReserveAndReach(potentialTool, PathEndMode.OnCell, pawn.NormalMaxDanger())) { newTool = potentialTool; optimality = potentialOptimality; } } } if (newTool != null) { break; } } // Return a job based on whether or not a better tool was located // Failure if (newTool == null) { SetNextOptimizeTick(pawn); return(null); } // Success int heldToolOffset = 0; if (curTool != null && assignmentTracker.forcedHandler.AllowedToAutomaticallyDrop(curTool)) { pawn.jobs.jobQueue.EnqueueFirst(pawn.DequipAndTryStoreSurvivalTool(curTool, false)); heldToolOffset = -1; } if (pawn.CanCarryAnyMoreSurvivalTools(heldToolOffset)) { Job pickupJob = new Job(JobDefOf.TakeInventory, newTool) { count = 1 }; return(pickupJob); } // Final failure state SetNextOptimizeTick(pawn); } return(null); }
// This is a janky mess and a half, but works! protected override Job TryGiveJob(Pawn pawn) { Pawn_SurvivalToolAssignmentTracker assignmentTracker = pawn.TryGetComp <Pawn_SurvivalToolAssignmentTracker>(); // Pawn can't use tools, lacks a tool assignment tracker or it isn't yet time to re-optimise tools if (!pawn.CanUseSurvivalTools() || assignmentTracker == null || Find.TickManager.TicksGame < assignmentTracker.nextSurvivalToolOptimizeTick) { return(null); } if (SurvivalToolsSettings.toolAutoDropExcess) { assignmentTracker.CheckToolsInUse(); // Check if current tool assignment allows for each tool, auto-removing those that aren't allowed. SurvivalToolAssignment curAssignment = assignmentTracker.CurrentSurvivalToolAssignment; List <SurvivalTool> heldTools = pawn.GetHeldSurvivalTools(); foreach (SurvivalTool tool in heldTools) { if ((!curAssignment.filter.Allows(tool) || !pawn.NeedsSurvivalTool(tool) || !tool.InUse) && !tool.Forced && StoreUtility.TryFindBestBetterStoreCellFor(tool, pawn, pawn.Map, StoreUtility.CurrentStoragePriorityOf(tool), pawn.Faction, out IntVec3 c)) { return(pawn.DequipAndTryStoreSurvivalTool(tool, true, c)); } } } if (SurvivalToolsSettings.toolOptimization) { SurvivalToolAssignment curAssignment = assignmentTracker.CurrentSurvivalToolAssignment; List <StatDef> workRelevantStats = pawn.AssignedToolRelevantWorkGiversStatDefs(); List <Thing> mapTools = pawn.MapHeld.listerThings.AllThings.Where(t => t is SurvivalTool).ToList(); SurvivalTool curTool = null; SurvivalTool newTool = null; float optimality = 0f; foreach (StatDef stat in workRelevantStats) { curTool = pawn.GetBestSurvivalTool(stat); optimality = SurvivalToolScore(curTool, workRelevantStats); foreach (SurvivalTool potentialTool in mapTools) { if (StatUtility.StatListContains(potentialTool.WorkStatFactors.ToList(), stat) && curAssignment.filter.Allows(potentialTool) && potentialTool.BetterThanWorkingToollessFor(stat) && pawn.CanUseSurvivalTool(potentialTool.def) && potentialTool.IsInAnyStorage() && !potentialTool.IsForbidden(pawn) && !potentialTool.IsBurning()) { float potentialOptimality = SurvivalToolScore(potentialTool, workRelevantStats); float delta = potentialOptimality - optimality; if (delta > 0f && pawn.CanReserveAndReach(potentialTool, PathEndMode.OnCell, pawn.NormalMaxDanger())) { newTool = potentialTool; optimality = potentialOptimality; } } } if (newTool != null) { break; } } // Return a job based on whether or not a better tool was located // Failure if (newTool == null) { SetNextOptimizeTick(pawn); return(null); } // Success int heldToolOffset = 0; if (curTool != null && !curTool.Forced) { pawn.jobs.jobQueue.EnqueueFirst(pawn.DequipAndTryStoreSurvivalTool(curTool, false)); heldToolOffset = -1; } if (pawn.CanCarryAnyMoreSurvivalTools(heldToolOffset)) { Job pickupJob = new Job(JobDefOf.TakeInventory, newTool) { count = 1 }; return(pickupJob); } } // Final failure state SetNextOptimizeTick(pawn); return(null); }