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);
                    }
                }
            }
        }
Example #3
0
        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);
                    }
                }
            }
        }