public virtual bool CanEverDoBill(Bill bill, out HashSet <Pawn> pawnsAble, MagicRecipeDef mrDefIn = null) { MagicRecipeDef mrDef = null; if (bill != null) { mrDef = bill.recipe as MagicRecipeDef; } if (mrDefIn != null) { mrDef = mrDefIn; } pawnsAble = new HashSet <Pawn>(); if (mrDef != null && mrDef is MagicRecipeDef) { float manaReq = mrDef.manaCost; if (mrDef.mageCount > 0) { manaReq = mrDef.manaCost / mrDef.mageCount; } List <Pawn> magePawnsInRange = TM_Calc.FindNearbyMages(this.Position, this.Map, this.Faction, 50, true); if (magePawnsInRange != null && magePawnsInRange.Count > 0) { for (int i = 0; i < magePawnsInRange.Count; i++) { Pawn p = magePawnsInRange[i]; CompAbilityUserMagic comp = p.GetComp <CompAbilityUserMagic>(); if (p.Spawned && !p.Drafted && !p.InMentalState && p.GetPosture() == PawnPosture.Standing && p.workSettings.WorkIsActive(TorannMagicDefOf.TM_Magic) && comp != null && comp.Mana != null && comp.Mana.CurLevel >= manaReq) { pawnsAble.Add(p); if (pawnsAble.Count >= mrDef.mageCount) { return(true); } } } } } return(false); }
public virtual void ScanForRepeatJob() { List <Pawn> allPawns = this.Map.mapPawns.AllPawnsSpawned; if (allPawns != null && allPawns.Count > 0) { for (int i = 0; i < allPawns.Count; i++) { if (allPawns[i].jobs != null && allPawns[i].CurJobDef == TorannMagicDefOf.JobDriver_DoMagicBill) { //Log.Message("checking can do job"); this.MageList.Clear(); this.MageList.Add(allPawns[i]); this.IsPending = true; this.magicRecipeDef = allPawns[i].CurJob.bill.recipe as MagicRecipeDef; //Log.Message("checking mages available: " + mages.Count); //CanDoJob(allPawns[i].GetComp<CompAbilityUserMagic>(), allPawns[i].CurJob.bill.recipe as MagicRecipeDef, this); } } } }
private Job StartOrResumeBillJob(Pawn pawn, IBillGiver giver, Thing thing) { for (int i = 0; i < giver.BillStack.Count; i++) { Bill bill = giver.BillStack[i]; if ((bill.recipe.requiredGiverWorkType == null || bill.recipe.requiredGiverWorkType == def.workType) && (Find.TickManager.TicksGame >= bill.lastIngredientSearchFailTicks + ReCheckFailedBillTicksRange.RandomInRange || FloatMenuMakerMap.makingFor == pawn)) { bill.lastIngredientSearchFailTicks = 0; if (bill.ShouldDoNow() && bill.PawnAllowedToStartAnew(pawn)) { bool issueBill = true; this.magicCircle = thing as Building_TMMagicCircleBase; List <Pawn> billPawns = new List <Pawn>(); billPawns.Clear(); if (bill.recipe is MagicRecipeDef) { MagicRecipeDef magicRecipe = bill.recipe as MagicRecipeDef; CompAbilityUserMagic compMagic = pawn.TryGetComp <CompAbilityUserMagic>(); if (magicCircle.IsActive) { issueBill = false; } if (!magicCircle.CanEverDoBill(bill, out billPawns, magicRecipe)) { issueBill = false; } if (!billPawns.Contains(pawn)) { issueBill = false; } } if (issueBill) { SkillRequirement skillRequirement = bill.recipe.FirstSkillRequirementPawnDoesntSatisfy(pawn); if (skillRequirement != null) { JobFailReason.Is("UnderRequiredSkill".Translate(skillRequirement.minLevel), bill.Label); } else { Bill_ProductionWithUft bill_ProductionWithUft = bill as Bill_ProductionWithUft; if (bill_ProductionWithUft != null) { if (bill_ProductionWithUft.BoundUft != null) { if (bill_ProductionWithUft.BoundWorker == pawn && pawn.CanReserveAndReach(bill_ProductionWithUft.BoundUft, PathEndMode.Touch, Danger.Deadly) && !bill_ProductionWithUft.BoundUft.IsForbidden(pawn)) { return(FinishUftJob(pawn, bill_ProductionWithUft.BoundUft, bill_ProductionWithUft)); } continue; } UnfinishedThing unfinishedThing = ClosestUnfinishedThingForBill(pawn, bill_ProductionWithUft); if (unfinishedThing != null) { return(FinishUftJob(pawn, unfinishedThing, bill_ProductionWithUft)); } } if (TryFindBestBillIngredients(bill, pawn, (Thing)giver, chosenIngThings)) { this.magicCircle = thing as Building_TMMagicCircle; if (this.magicCircle != null && bill.recipe is MagicRecipeDef) { this.magicCircle.magicRecipeDef = bill.recipe as MagicRecipeDef; this.magicCircle.MageList.Clear(); magicCircle.MageList.Add(pawn); //Log.Message("assigning magic bill to " + pawn.LabelShort); if (bill.recipe is MagicRecipeDef && billPawns.Count > 1) { for (int j = 0; j < billPawns.Count; j++) { if (billPawns[j] != pawn) { magicCircle.MageList.Add(billPawns[j]); magicCircle.IssueAssistJob(billPawns[j]); //Log.Message("assisting magic bill to " + billPawns[j].LabelShort); } } } this.magicCircle.IsPending = true; } Job result = TryStartNewDoBillJob(pawn, bill, giver); chosenIngThings.Clear(); return(result); } if (FloatMenuMakerMap.makingFor != pawn) { bill.lastIngredientSearchFailTicks = Find.TickManager.TicksGame; } else { JobFailReason.Is(MissingMaterialsTranslated, bill.Label); } chosenIngThings.Clear(); } } } } } chosenIngThings.Clear(); return(null); }
public override void Tick() { if (this.suspendReset) { if (this.resetDelay < Find.TickManager.TicksGame) { this.suspendReset = false; } } else if (IsActive) { //rotate magic circle (draw) and do effects until job is complete this.activeDuration--; if (this.nextCircleEffect <= Find.TickManager.TicksGame) { Vector3 rndPos = GetCircleCenter.ToVector3Shifted(); rndPos.x += Rand.Range(-3, 3); rndPos.z += Rand.Range(-3, 3); MoteMaker.ThrowSmoke(rndPos, this.Map, Rand.Range(.8f, 1.5f)); this.circleRotation = Mathf.Max(this.circleRotation - 2, 8); this.nextCircleEffect = Find.TickManager.TicksGame + Mathf.Clamp(this.circleRotation, 8, 300); } if (this.activeDuration <= 0) { ModOptions.Constants.SetBypassPrediction(true); if (Rand.Chance(Mathf.Clamp01(this.magicRecipeDef.failChance - SpellSuccessModifier))) //- clamp on 0 and look for circle construction material for fail chance reduction { //do spell failure actions DoFailActions(); } else { //do spell success actions DoSuccessActions(); } DoActiveEffecter(); this.IsActive = false; this.magicRecipeDef = null; ClearAllJobs(); ModOptions.Constants.SetBypassPrediction(false); } } else { if (Find.TickManager.TicksGame % 51 == 0) { bool billsActionable = false; for (int i = 0; i < this.BillStack.Bills.Count; i++) { Bill bill = this.BillStack.Bills[i]; if (CanEverDoBill(bill, out _)) { bill.suspended = false; billsActionable = true; } else { bill.suspended = true; } } if (billsActionable) { this.GetComp <CompRefuelable>().Refuel(1); if (this.MageList.Count == 0) { ScanForRepeatJob(); } } else { this.GetComp <CompRefuelable>().ConsumeFuel(1); if (this.IsPending) { ClearAllJobs(); } } } if (this.IsPending) { if (Find.TickManager.TicksGame % 81 == 0) { if (this.magicRecipeDef == null && this.ActiveJob != null) { this.magicRecipeDef = this.ActiveJob.RecipeDef as MagicRecipeDef; } if (this.magicRecipeDef != null) { bool magesAvailable = false; if (this.MageList.Count > 0) { magesAvailable = PendingMagesStillAvailable(this.MageList); } bool ingredientsAvailable = HasIngredients; bool magesReady = false; if (magesAvailable) { magesReady = MagesReadyToAssist(this.MageList); } else { ClearAllJobs(); } //Log.Message("mages available " + magesAvailable + " ready: " + magesReady + " ingredients " + ingredientsAvailable); if (magesAvailable && ingredientsAvailable && magesReady) { this.ActiveJob.bill.Notify_IterationCompleted(mageList.First(), null); this.IsActive = true; this.activeDuration = Mathf.RoundToInt(this.magicRecipeDef.workAmount / 100); this.circleRotation = (int)(this.magicRecipeDef.workAmount / 1000); this.nextCircleEffect = Find.TickManager.TicksGame + this.circleRotation; LaunchJobPawns(); LaunchIngredients(); } } } } } }
public virtual IEnumerable <ThingDef> PotentiallyMissingIngredients(MagicRecipeDef mrDef, bool launch = false) { this.launchableThings = new List <Thing>(); List <IngredientCount> ingredients = mrDef.ingredients; for (int i = 0; i < ingredients.Count; i++) { IngredientCount ing = ingredients[i]; bool foundIng = false; List <Thing> thingList = this.Map.listerThings.ThingsInGroup(ThingRequestGroup.HaulableEver); int totalStackCount = 0; for (int j = 0; j < thingList.Count; j++) { Thing thing = thingList[j]; if ((thing.Position - this.InteractionCell).LengthHorizontal < 4 && (ing.IsFixedIngredient || mrDef.fixedIngredientFilter.Allows(thing)) && ing.filter.Allows(thing)) { this.launchableThings.Add(thing); totalStackCount += thing.stackCount; if (ing.IsFixedIngredient && totalStackCount >= ing.GetBaseCount()) { foundIng = true; break; } } } if (foundIng) { continue; } if (ing.IsFixedIngredient) { yield return(ing.filter.AllowedThingDefs.First()); continue; } ThingDef def = (from x in ing.filter.AllowedThingDefs.InRandomOrder() select x).FirstOrDefault((ThingDef x) => mrDef.fixedIngredientFilter.Allows(x)); if (def != null) { if (def.IsCorpse) { bool hasCorpses = false; List <Thing> ingredient = new List <Thing>(); for (int u = 0; u < ActiveJob.RecipeDef.ingredients.Count; u++) { ICollection <ThingDef> allowedThings = (ICollection <ThingDef>)ActiveJob.RecipeDef.ingredients[u].filter.AllowedThingDefs; if (allowedThings != null && allowedThings.Count > 0) { int corpseCount = 0; List <IntVec3> cellList = GenRadial.RadialCellsAround(this.InteractionCell, 3, true).ToList(); for (int j = 0; j < cellList.Count; j++) { List <Thing> cellThings = cellList[j].GetThingList(this.Map); for (int k = 0; k < cellThings.Count; k++) { if (cellThings[k].def.IsCorpse) { corpseCount++; } } if (ActiveJob.RecipeDef.ingredients[i].GetBaseCount() <= corpseCount) { hasCorpses = true; } } } } if (hasCorpses) { continue; } else { yield return(def); } } else { yield return(def); } } } }