/// <summary> /// Gets the largest cordial available to use. /// </summary> /// <param name="cordialType"></param> /// <returns></returns> public InventoryItem GetLargestCordial(CordialType cordialType) { return(this.cordialStock .Where(k => cordialType != CordialType.None && (cordialType == CordialType.Auto || k.Key.Id == (uint)cordialType) && k.Value.Quantity > 0 && k.Value.CanUse(ExProfileBehavior.Me)) .OrderByDescending(k => CordialDataMap[k.Key].Gp) .Select(k => k.Value) .FirstOrDefault()); }
/// <summary> /// Gets the most appropriate cordial available that gives the player enough GP. /// </summary> /// <param name="gpNeeded">Amount of GP needed to gather.</param> /// <returns></returns> public InventoryItem GetFulfillingCordial(int gpNeeded, CordialType cordialType) { var best = this.cordialStock .Where(k => cordialType != CordialType.None && (cordialType == CordialType.Auto || k.Key.Id == (uint)cordialType) && k.Value.Quantity > 0 && k.Value.CanUse(ExProfileBehavior.Me) && CordialDataMap[k.Key].Gp >= gpNeeded) .OrderBy(k => CordialDataMap[k.Key].Gp) .Select(k => k.Value) .FirstOrDefault(); return(best); }
/// <summary> /// Gets the most appropriate cordial available that gives the player GP without going over the missing GP. /// </summary> /// <param name="gpMissing"></param> /// <param name="cordialType"></param> /// <returns></returns> public InventoryItem GetBestCordial(int gpMissing, CordialType cordialType) { var best = this.cordialStock .Where(k => cordialType != CordialType.None && (cordialType == CordialType.Auto || k.Key.Id == (uint)cordialType) && k.Value.Quantity > 0 && k.Value.CanUse(ExProfileBehavior.Me) && CordialDataMap[k.Key].Gp <= gpMissing) .OrderByDescending(k => CordialDataMap[k.Key].Gp) .Select(k => k.Value) .FirstOrDefault(); return best; }
private async Task <bool> UseCordial(CordialType cordialType, int maxTimeoutSeconds = 5) { if (!(CordialSpellData.Cooldown.TotalSeconds < maxTimeoutSeconds)) { return(false); } BagSlot cordial = InventoryManager.FilledSlots.FirstOrDefault(slot => slot.RawItemId == (uint)cordialType); if (cordial != null) { StatusText = Localization.ExFish_UseCordialWhenAvailable; Logger.Info( Localization.ExFish_UseCordial, (int)CordialSpellData.Cooldown.TotalSeconds, ExProfileBehavior.Me.CurrentGP); if (!await Coroutine.Wait( TimeSpan.FromSeconds(maxTimeoutSeconds), () => { if (!ExProfileBehavior.Me.IsMounted || !(CordialSpellData.Cooldown.TotalSeconds < 2)) { return(cordial.CanUse(ExProfileBehavior.Me)); } ActionManager.Dismount(); return(false); })) { return(false); } await Coroutine.Sleep(500); Logger.Info("Using " + cordialType); cordial.UseItem(ExProfileBehavior.Me); await Coroutine.Sleep(1500); return(true); } Logger.Warn(Localization.ExFish_NoCordial + cordialType); return(false); }
/// <summary> /// Executes the strategy logic in charge of regenerating GP after the gather. /// </summary> /// <returns></returns> public async Task <GpRegenStrategyResult> RegenerateGp(GatheringPointObject node, IGatheringRotation gatherRotation, GatherStrategy gatherStrategy, CordialTime cordialTime, CordialType cordialType) { var rtn = new GpRegenStrategyResult() { StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.OK, EffectiveCordialType = cordialType, OriginalCordialType = cordialType, }; var useCordial = cordialTime.HasFlag(CordialTime.AfterGather) && this.cordialStock.HasStock() && this.cordialStock.GetCordialCooldown() == TimeSpan.Zero; var currentGp = ExProfileBehavior.Me.CurrentGP; var maxGp = ExProfileBehavior.Me.MaxGP; var missingGp = maxGp - currentGp; var cordial = this.cordialStock.GetBestCordial(missingGp, cordialType); // Return OK if there is no cordial to use if (cordial == null) { rtn.UseState = InventoryItem.UseResult.OK; return(rtn); } // Use the cordial rtn.UseState = await cordial.Use( ExProfileBehavior.Me ); // Log the result this.LogCordialResult( rtn.UseState ?? InventoryItem.UseResult.CantUse, cordial, currentGp ); return(rtn); }
/// <summary> /// Executes the strategy logic in charge of regenerating GP before the gather. /// </summary> /// <returns></returns> public async Task <GpRegenStrategyResult> RegenerateGp(GatheringPointObject node, IGatheringRotation gatherRotation, GatherStrategy gatherStrategy, CordialTime cordialTime, CordialType cordialType) { var rtn = new GpRegenStrategyResult() { EffectiveCordialType = this.effectiveCordialType, OriginalCordialType = this.requestedCordialType, }; // Return OK immediately if there is no node if (node == null) { this.logger.GatheringNodeIsGone(); rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.NodeGone; return(rtn); } // Configure the strategy and report to the log this.Configure(node, gatherRotation, gatherStrategy, cordialTime, cordialType); this.logger.LogReport(this); // Return not enough time if player has less than 3 seconds to gather if (this.EffectiveTimeTillGather.TotalSeconds < 3) { this.logger.GatheringNotEnoughTime(); rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.NotEnoughTime; return(rtn); } if (this.gatherStrategy == GatherStrategy.GatherOrCollect) { // Return not enough GP if we cannot meet the target breakpoint for the rotation if (this.BreakpointGp > this.TargetGp) { this.logger.RegeneratingNotEnoughGp(); rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.NotEnoughGp; return(rtn); } } // Use the cordial if one was selected if (this.Cordial != null) { rtn.UseState = await this.Cordial.Use( ExProfileBehavior.Me, maxTimeout : this.EffectiveTimeTillGather, dismount : true ); this.LogCordialResult(rtn.UseState.Value); // Recalculate player's ability to gather after cordial use failure if (rtn.UseState != InventoryItem.UseResult.OK) { this.effectiveCordialType = CordialType.None; this.CalculateTargetAndCordialSelection(); this.logger.LogReport(this); // Return not enough GP if we cannot meet the target breakpoint for the rotation if (this.BreakpointGp > this.TargetGp) { this.logger.RegeneratingNotEnoughGp(); rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.NotEnoughGp; return(rtn); } } } // Handle TouchAndGo overrides if (this.gatherStrategy == GatherStrategy.TouchAndGo) { // Do nothing if this is not ephemeral if (!node.IsEphemeral()) { this.logger.GatheringNodeSkippedNotEphemeral(); rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.OK; return(rtn); } if (this.EffectiveTimeToRegenerate.TotalSeconds > MAX_TOUCHANDGO_WAIT) { this.logger.RegeneratingSkippedExceedsEphemeralMaxWait( this.EffectiveTimeToRegenerate.TotalSeconds, MAX_TOUCHANDGO_WAIT ); rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.OK; return(rtn); } } // Return OK immediately if the rotation forcefully gathers the item if (gatherRotation.ShouldForceGather(node)) { rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.OK; return(rtn); } // Execute wait logic rtn.StrategyState = await this.WaitForGpRegeneration(); return(rtn); }
/// <summary> /// Configures the strategy for use /// </summary> protected void Configure(GatheringPointObject node, IGatheringRotation gatherRotation, GatherStrategy gatherStrategy, CordialTime cordialTime, CordialType cordialType) { if (gatherRotation == null) { throw new ArgumentNullException("gatherRotation"); } // Set gathering parameters this.gatherRotation = gatherRotation; this.gatherStrategy = gatherStrategy; // Set cordial parameters this.cordialTime = cordialTime; this.requestedCordialType = this.effectiveCordialType = cordialType; // Override cordial type if (this.requestedCordialType > CordialType.None) { // Turn off cordial when there is no stock if (!this.cordialStockManager.HasStock()) { this.effectiveCordialType = CordialType.None; this.logger.RegeneratingCordialUseDisabledNoStock(); } // Turn off cordial when node is not ephemeral in TnG strategies if (this.gatherStrategy == GatherStrategy.TouchAndGo && !node.IsEphemeral()) { this.effectiveCordialType = CordialType.None; } } else { this.effectiveCordialType = this.requestedCordialType; } // Set node lifespan parameters this.NodeLifespan = new EffectiveNodeLifespan(NodeHelper.GetNodeLifespan(node), this.gatherRotation.Attributes.RequiredTimeInSeconds); if (this.gatherStrategy == GatherStrategy.TouchAndGo) { this.NodeLifespan.Clamp(TimeSpan.Zero, TimeSpan.FromSeconds(MAX_TOUCHANDGO_WAIT)); } this.EffectiveTimeTillGather = this.NodeLifespan.DeSpawn; // Set GP parameters this.StartingGp = this.CurrentGp; this.MaxGp = ExProfileBehavior.Me.MaxGP; this.EffectiveGp = CharacterResource.GetEffectiveGp(this.NodeLifespan.DeSpawnTicks); // Set breakpoint and cordial parameters this.CalculateTargetAndCordialSelection(); // Calculate regeneration parameters this.RegeneratedGp = (ushort)(this.TargetGp - this.CordialGp - this.StartingGp); if (this.RegeneratedGp < 0) { this.RegeneratedGp = 0; } this.EffectiveTimeToRegenerate = CharacterResource.EstimateExpectedRegenerationTime(this.RegeneratedGp); }
private async Task<bool> UseCordial(CordialType cordialType, int maxTimeoutSeconds = 5) { if (CordialSpellData.Cooldown.TotalSeconds < maxTimeoutSeconds) { var cordial = InventoryManager.FilledSlots.FirstOrDefault(slot => slot.RawItemId == (uint)cordialType); if (cordial != null) { StatusText = "Using cordial when it becomes available"; Logger.Info( "Using Cordial -> Waiting (sec): {0}, CurrentGP: {1}", (int)CordialSpellData.Cooldown.TotalSeconds, Me.CurrentGP); if (await Coroutine.Wait( TimeSpan.FromSeconds(maxTimeoutSeconds), () => { if (Me.IsMounted && CordialSpellData.Cooldown.TotalSeconds < 2) { Actionmanager.Dismount(); return false; } return cordial.CanUse(Me); })) { await Coroutine.Sleep(500); Logger.Info("Using " + cordialType); cordial.UseItem(Me); await Coroutine.Sleep(1500); return true; } } else { Logger.Warn("No Cordial avilable, buy more " + cordialType); } } return false; }
public int? GetAdjustedWaitForGp(int gpBeforeGather, int secondsToStartGathering, CordialType cordialType) { if (CordialTime.HasFlag(CordialTime.BeforeGather) && cordialType > CordialType.None && CordialSpellData.Cooldown.TotalSeconds + 2 <= secondsToStartGathering) { switch (cordialType) { case CordialType.Cordial: gpBeforeGather += 300; break; case CordialType.HiCordial: gpBeforeGather += 400; break; case CordialType.Auto: if (DataManager.GetItem((uint)CordialType.HiCordial).ItemCount() > 0) { gpBeforeGather += 400; } else { gpBeforeGather += 300; } break; } } foreach (var gp in gatherRotation.Attributes.RequiredGpBreakpoints) { if (gp <= gpBeforeGather) { return Math.Min(Me.MaxGP - (Me.MaxGP % 50), gp); } } return null; }
private async Task<bool> UseCordial(CordialType cordialType, int maxTimeoutSeconds = 5) { if (CordialSpellData.Cooldown.TotalSeconds < maxTimeoutSeconds) { var cordial = InventoryManager.FilledSlots.FirstOrDefault(slot => slot.RawItemId == (uint) cordialType); if (cordial != null) { StatusText = Localization.Localization.ExFish_UseCordialWhenAvailable; Logger.Info( Localization.Localization.ExFish_UseCordial, (int) CordialSpellData.Cooldown.TotalSeconds, ExProfileBehavior.Me.CurrentGP); if (await Coroutine.Wait( TimeSpan.FromSeconds(maxTimeoutSeconds), () => { if (ExProfileBehavior.Me.IsMounted && CordialSpellData.Cooldown.TotalSeconds < 2) { Actionmanager.Dismount(); return false; } return cordial.CanUse(ExProfileBehavior.Me); })) { await Coroutine.Sleep(500); Logger.Info("Using " + cordialType); cordial.UseItem(ExProfileBehavior.Me); await Coroutine.Sleep(1500); return true; } } else { Logger.Warn(Localization.Localization.ExFish_NoCordial + cordialType); } } return false; }
private async Task<bool> UseCordial(CordialType cordialType, int maxTimeoutSeconds = 5) { maxTimeoutSeconds -= 2; if (GatherStrategy == GatherStrategy.TouchAndGo) { Logger.Verbose(Localization.Localization.ExGather_TnGOverride); maxTimeoutSeconds = maxTimeoutSeconds.Clamp(2, 16); } else { maxTimeoutSeconds = maxTimeoutSeconds.Clamp(2, 180); } if (CordialSpellData.Cooldown.TotalSeconds < maxTimeoutSeconds) { var cordial = InventoryManager.FilledSlots.FirstOrDefault(slot => slot.RawItemId == (uint) cordialType); if (cordial != null) { StatusText = Localization.Localization.ExGather_Cordial; Logger.Info( Localization.Localization.ExGather_CordialUse, (int) CordialSpellData.Cooldown.TotalSeconds, ExProfileBehavior.Me.CurrentGP); if (await Coroutine.Wait( TimeSpan.FromSeconds(maxTimeoutSeconds), () => { if (ExProfileBehavior.Me.IsMounted && CordialSpellData.Cooldown.TotalSeconds < 2) { Actionmanager.Dismount(); return false; } return cordial.CanUse(ExProfileBehavior.Me) || Core.Player.IsDead; })) { await Coroutine.Sleep(500); Logger.Info(Localization.Localization.ExGather_CordialUsing + cordialType); cordial.UseItem(ExProfileBehavior.Me); await Coroutine.Sleep(1500); return true; } } else { Logger.Warn(Localization.Localization.ExGather_CordialNotAvailable + cordialType); } } return false; }