/* * Based on the Caravan's resources, Pawns & the road's cost (modified by terrain) : * - Determine the amount of work done in a tick * - Consume the caravan's resources * - Return whether or not the Caravan must now stop because it ran out of resources * - NOTE : Does this need to be here ? Maybe better in Mod.cs * Returns TRUE if work finished * CALLED FROM : CompTick() of WorldObjectComp_Caravan */ public static bool DoSomeWork(Caravan caravan, RoadConstructionSite site, out bool noMoreResources) { var caravanComp = caravan.GetComponent <WorldObjectComp_Caravan>(); var siteComp = site.GetComponent <WorldObjectComp_ConstructionSite>(); _ = site.roadDef.GetModExtension <DefModExtension_RotR_RoadDef>(); noMoreResources = false; var useISR2G = caravanComp.UseISR2G(); var available = new Dictionary <string, int>(); var needed = new Dictionary <string, int>(); var ratio = new Dictionary <string, float>(); float ratio_final = 1; //RoadsOfTheRim.DebugLog("[RotR] DEBUG ========== doSomeWork() =========="); //RoadsOfTheRim.DebugLog("[RotR] DEBUG ISR2G set to "+useISR2G); if (DebugSettings.godMode) { return(siteComp.FinishWork(caravan)); } if (caravanComp.CaravanCurrentState() != CaravanState.ReadyToWork) { DebugLog("[RotR] DEBUG : doSomeWork() failed because the caravan can't work."); return(false); } // Percentage of total work that can be done in this batch, might be 0 if no pawn was found with enough skill var amountOfWork = caravanComp.AmountOfWork(true); // Work was 0 (not enough skill) if (Math.Abs(amountOfWork) < double.Epsilon) { Messages.Message("RoadsOfTheRim_CaravanNoWork".Translate(caravan.Name, site.roadDef.label), MessageTypeDefOf.RejectInput); caravanComp.StopWorking(); return(false); } // calculate material present in the caravan foreach (var resourceName in DefModExtension_RotR_RoadDef.allResources) { available[resourceName] = 0; } foreach (var aThing in CaravanInventoryUtility.AllInventoryItems(caravan)) { foreach (var resourceName in DefModExtension_RotR_RoadDef.allResources) { if (IsThis(aThing.def, resourceName)) { available[resourceName] += aThing.stackCount; } } } // What percentage of work will remain after amountOfWork is done ? var percentOfWorkLeftToDoAfter = (siteComp.GetLeft("Work") - amountOfWork) / siteComp.GetCost("Work"); // The amount of each resource left to spend in total is : percentOfWorkLeftToDoAfter * {this resource cost} // Materials that would be needed to do that much work foreach (var resourceName in DefModExtension_RotR_RoadDef.allResources) { needed[resourceName] = (int)Math.Round(siteComp.GetLeft(resourceName) - (percentOfWorkLeftToDoAfter * siteComp.GetCost(resourceName))); // Check if there's enough material to go through this batch. Materials with a cost of 0 are always OK // Don't check when ISR2G is in use for this resource, don't check for work if (DefModExtension_RotR_RoadDef.GetInSituModifier(resourceName, useISR2G) || resourceName == "Work") { continue; } ratio[resourceName] = needed[resourceName] == 0 ? 1f : Math.Min(available[resourceName] / (float)needed[resourceName], 1f); if (ratio[resourceName] < ratio_final) { ratio_final = ratio[resourceName]; } } // The caravan didn't have enough resources for a full batch of work. Use as much as we can then stop working if (ratio_final < 1f) { Messages.Message("RoadsOfTheRim_CaravanNoResource".Translate(caravan.Name, site.roadDef.label), MessageTypeDefOf.RejectInput); foreach (var resourceName in DefModExtension_RotR_RoadDef.allResources) { needed[resourceName] = (int)(needed[resourceName] * ratio_final); } caravanComp.StopWorking(); } //RoadsOfTheRim.DebugLog("[RotR] ISR2G DEBUG ratio final = " + ratio_final); // Consume resources from the caravan _ = site.roadDef.defName == "DirtPathBuilt"; // Always consider resources have been consumed when the road is a dirt path foreach (var aThing in CaravanInventoryUtility.AllInventoryItems(caravan)) { foreach (var resourceName in DefModExtension_RotR_RoadDef.allResources) { if (!DefModExtension_RotR_RoadDef.GetInSituModifier(resourceName, useISR2G)) { if (needed[resourceName] <= 0 || !IsThis(aThing.def, resourceName)) { continue; //RoadsOfTheRim.DebugLog("[RotR] ISR2G consumption DEBUG =" + resourceName + " Qty consumed = " + amountUsed); } var amountUsed = aThing.stackCount > needed[resourceName] ? needed[resourceName] : aThing.stackCount; aThing.stackCount -= amountUsed; // Reduce how much of this resource is needed needed[resourceName] -= amountUsed; siteComp.ReduceLeft(resourceName, amountUsed); } else { if (needed[resourceName] <= 0) { continue; } //RoadsOfTheRim.DebugLog("[RotR] ISR2G consumption DEBUG =" + resourceName + " Qty freely awarded = " + needed[resourceName]); siteComp.ReduceLeft(resourceName, needed[resourceName]); needed[resourceName] = 0; } } if (aThing.stackCount == 0) { aThing.Destroy(); } } caravanComp.TeachPawns(ratio_final); // Pawns learn some construction // HARDCODED : ISR2G divides work done by 4 , AISR2G by 2 for all roads except dirt path if (useISR2G > 0 && site.roadDef.defName != "DirtPathBuilt") { amountOfWork = amountOfWork * 0.25f * useISR2G; } // Update amountOfWork based on the actual ratio worked & finally reducing the work & resources left amountOfWork = ratio_final * amountOfWork; return(siteComp.UpdateProgress(amountOfWork, caravan)); }
public string progressDescription() { RoadConstructionSite parentSite = this.parent as RoadConstructionSite; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("RoadsOfTheRim_ConstructionSiteDescription_Main".Translate(String.Format("{0:P1}", GetPercentageDone("Work")))); // Description of ally's help, if any if (parentSite.helpFromFaction != null) { stringBuilder.Append("RoadsOfTheRim_ConstructionSiteDescription_Help".Translate(parentSite.helpFromFaction.Name, (int)parentSite.helpAmount, String.Format("{0:0.0}", parentSite.helpWorkPerTick))); if (parentSite.helpFromTick > Find.TickManager.TicksGame) { stringBuilder.Append("RoadsOfTheRim_ConstructionSiteDescription_HelpStartsWhen".Translate(String.Format("{0:0.00}", (float)(parentSite.helpFromTick - Find.TickManager.TicksGame) / (float)GenDate.TicksPerDay))); } } // Show total cost modifiers float totalCostModifier = 0f; stringBuilder.Append(WorldObjectComp_ConstructionSite.CostModifersDescription(parentSite.Tile, parentSite.GetNextLeg().Tile, ref totalCostModifier)); List <Caravan> AllCaravansHere = new List <Caravan>(); Find.WorldObjects.GetPlayerControlledCaravansAt(parentSite.Tile, AllCaravansHere); int ISR2G = 0; foreach (Caravan c in AllCaravansHere) { int caravanISR2G = c.GetComponent <WorldObjectComp_Caravan>().useISR2G(); if (caravanISR2G > ISR2G) { ISR2G = caravanISR2G; } } // Per resource : show costs & how much is left to do foreach (string resourceName in DefModExtension_RotR_RoadDef.allResourcesAndWork) { if (GetCost(resourceName) > 0) { stringBuilder.AppendLine(); string ISR2Gmsg = ""; if (ISR2G > 0) { if (resourceName == "Work") { ISR2Gmsg = (ISR2G == 1 ? "RoadsOfTheRim_ConstructionSiteDescription_ISR2Gwork".Translate() : "RoadsOfTheRim_ConstructionSiteDescription_AISR2Gwork".Translate()); } else if (DefModExtension_RotR_RoadDef.GetInSituModifier(resourceName, ISR2G)) { ISR2Gmsg = (ISR2G == 1 ? "RoadsOfTheRim_ConstructionSiteDescription_ISR2GFree".Translate() : "RoadsOfTheRim_ConstructionSiteDescription_AISR2GFree".Translate()); } } stringBuilder.Append("RoadsOfTheRim_ConstructionSiteDescription_Resource".Translate( resourceName, String.Format((resourceName == "Work" ? "{0:##.00}" : "{0:##}"), GetLeft(resourceName)), // Only Work should be shown with 2 decimals (int)GetCost(resourceName), ISR2Gmsg )); } } return(stringBuilder.ToString()); }