public EngineAction Run(PLConfig Config) { // FIRST IF YOU ARE SILENCED OR DOOMED ATTEMPT REMOVAL NOW if (PL.HasStatus(StatusEffect.Silence) && Config.PLSilenceItemEnabled) { var plSilenceItem = Items.SilenceRemoval[Config.PLSilenceItem]; // Check to make sure we have echo drops if (PL.GetInventoryItemCount(PL.GetItemId(plSilenceItem)) > 0 || PL.GetTempItemCount(PL.GetItemId(plSilenceItem)) > 0) { return(new EngineAction { Item = plSilenceItem }); } } else if (PL.HasStatus(StatusEffect.Doom) && Config.PLDoomItemEnabled) { var plDoomItem = Items.DoomRemoval[Config.PLDoomItem]; // Check to make sure we have holy water if (PL.GetInventoryItemCount(PL.GetItemId(plDoomItem)) > 0 || PL.GetTempItemCount(PL.GetItemId(plDoomItem)) > 0) { return(new EngineAction { Item = plDoomItem }); } } else if (Config.DivineSeal && PL.Player.MPP <= 11 && PL.AbilityAvailable(Ability.DivineSeal) && !PL.Player.Buffs.Contains((short)StatusEffect.Weakness)) { return(new EngineAction { Target = Target.Me, JobAbility = Ability.DivineSeal }); } else if (Config.Convert && (PL.Player.MP <= Config.ConvertMP) && PL.AbilityAvailable(Ability.Convert) && !PL.Player.Buffs.Contains((short)StatusEffect.Weakness)) { return(new EngineAction { Target = Target.Me, JobAbility = Ability.Convert }); } if (PL.Player.MP <= Config.MinCastingMP && PL.Player.MP != 0) { if (Config.LowMPEnabled && !LowMP && !Config.HealLowMPEnabled) { PL.ThirdParty.SendString("/tell " + Monitored.Player.Name + " MP is low!"); } LowMP = true; } if (PL.Player.MP > Config.MinCastingMP && PL.Player.MP != 0) { if (Config.LowMPEnabled && LowMP && !Config.HealLowMPEnabled) { PL.ThirdParty.SendString("/tell " + Monitored.Player.Name + " MP OK!"); } LowMP = false; } if (Config.HealLowMPEnabled && PL.Player.MP <= Config.HealMPThreshold && PL.Player.Status == 0) { if (Config.LowMPEnabled && !LowMP) { PL.ThirdParty.SendString("/tell " + Monitored.Player.Name + " MP is seriously low, /healing."); } LowMP = true; return(new EngineAction { CustomAction = "/heal" }); } else if (Config.StandMPEnabled && PL.Player.MPP >= Config.StandMPThreshold && PL.Player.Status == 33) { if (Config.LowMPEnabled && !LowMP) { PL.ThirdParty.SendString("/tell " + Monitored.Player.Name + " MP has recovered."); } LowMP = false; return(new EngineAction { CustomAction = "/heal" }); } if (Config.AfflatusSolaceEnabled && (!PL.HasStatus(StatusEffect.Afflatus_Solace)) && PL.AbilityAvailable(Ability.AfflatusSolace)) { return(new EngineAction { JobAbility = Ability.AfflatusSolace }); } if (Config.AfflatusMiseryEnabled && (!PL.HasStatus(StatusEffect.Afflatus_Misery)) && PL.AbilityAvailable(Ability.AfflatusMisery)) { return(new EngineAction { JobAbility = Ability.AfflatusMisery }); } if (Config.Composure && (!PL.HasStatus(StatusEffect.Composure)) && PL.AbilityAvailable(Ability.Composure)) { return(new EngineAction { JobAbility = Ability.Composure }); } if (Config.LightArts && (!PL.HasStatus(StatusEffect.Light_Arts)) && (!PL.HasStatus(StatusEffect.Addendum_White)) && PL.AbilityAvailable(Ability.LightArts)) { return(new EngineAction { JobAbility = Ability.LightArts }); } if (Config.AddendumWhite && (!PL.HasStatus(StatusEffect.Addendum_White)) && PL.HasStatus(StatusEffect.Light_Arts) && PL.CurrentSCHCharges() > 0) { return(new EngineAction { JobAbility = Ability.AddendumWhite }); } if (Config.DarkArts && (!PL.HasStatus(StatusEffect.Dark_Arts)) && (!PL.HasStatus(StatusEffect.Addendum_Black)) && PL.AbilityAvailable(Ability.DarkArts)) { return(new EngineAction { JobAbility = Ability.DarkArts }); } if (Config.AddendumBlack && PL.HasStatus(StatusEffect.Dark_Arts) && (!PL.HasStatus(StatusEffect.Addendum_Black)) && PL.CurrentSCHCharges() > 0) { return(new EngineAction { JobAbility = Ability.AddendumBlack }); } if (Config.SublimationEnabled && (!PL.HasStatus(StatusEffect.Sublimation_Activated)) && (!PL.HasStatus(StatusEffect.Sublimation_Complete)) && (!PL.HasStatus(StatusEffect.Refresh)) && PL.AbilityAvailable(Ability.Sublimation)) { return(new EngineAction { JobAbility = Ability.Sublimation }); } if (Config.SublimationEnabled && ((PL.Player.MPMax - PL.Player.MP) > Config.SublimationMPLossThreshold) && PL.HasStatus(StatusEffect.Sublimation_Complete) && PL.AbilityAvailable(Ability.Sublimation)) { return(new EngineAction { JobAbility = Ability.Sublimation }); } if (Config.DivineCaressEnabled && Config.DebuffsEnabled && PL.AbilityAvailable(Ability.DivineCaress)) { return(new EngineAction { JobAbility = Ability.DivineCaress }); } if (Config.DevotionEnabled && PL.AbilityAvailable(Ability.Devotion) && PL.Player.HPP > 80 && (!Config.DevotionWhenEngaged || (Monitored.Player.Status == 1))) { int plParty = PL.GetPartyRelativeTo(Monitored); // Get all active members who are in the PLs party. IEnumerable <PartyMember> cParty = Monitored.GetActivePartyMembers().Where(member => member.InParty(plParty) && member.Name != PL.Player.Name); // If we're set to only devotion a specific target, filter the list for that target. if (Config.DevotionSpecifiedTarget) { cParty = cParty.Where(member => member.Name == Config.DevotionTargetName); } // Get the first member who's within range, and has enough missing MP to meet our config criteria. var devotionTarget = cParty.FirstOrDefault(member => member.CurrentMP <= Config.DevotionMPThreshold && PL.EntityWithin(10, member.TargetIndex)); if (devotionTarget != default) { return(new EngineAction { Target = devotionTarget.Name, JobAbility = Ability.Devotion }); } } if (Config.ShellraEnabled && (!PL.HasStatus(StatusEffect.Shell))) { var shellraSpell = Data.ShellraTiers[Config.ShellraLevel - 1]; if (PL.SpellAvailable(shellraSpell)) { return(new EngineAction { Spell = shellraSpell }); } } if (Config.ProtectraEnabled && (!PL.HasStatus(StatusEffect.Protect))) { var protectraSpell = Data.ProtectraTiers[Config.ProtectraLevel - 1]; if (PL.SpellAvailable(protectraSpell)) { return(new EngineAction { Spell = protectraSpell }); } } if (Config.BarElementEnabled && !PL.HasStatus(Data.SpellEffects[Config.BarElementSpell]) && PL.SpellAvailable(Config.BarElementSpell)) { // TODO: Make this work properly, so it can figure out if there's 2 charges and return // an action that says: Do Accession + Perpetuance + Barspell. var result = new EngineAction { Spell = Config.BarElementSpell }; if (Config.AccessionEnabled && Config.BarElementAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !Config.AOEBarElementEnabled && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.BarElemenetPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } return(result); } if (Config.BarStatusEnabled && !PL.HasStatus(Data.SpellEffects[Config.BarStatusSpell]) && PL.SpellAvailable(Config.BarStatusSpell)) { var result = new EngineAction { Spell = Config.BarStatusSpell }; if (Config.AccessionEnabled && Config.BarStatusAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !Config.AOEBarStatusEnabled && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.BarStatusPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } return(result); } if (Config.GainBoostSpellEnabled && !PL.HasStatus(Data.SpellEffects[Config.GainBoostSpell]) && PL.SpellAvailable(Config.GainBoostSpell)) { return(new EngineAction { Spell = Config.GainBoostSpell }); } if (Config.StormSpellEnabled && !PL.HasStatus(Data.SpellEffects[Config.StormSpell]) && PL.SpellAvailable(Config.StormSpell)) { var result = new EngineAction { Spell = Config.StormSpell }; if (Config.AccessionEnabled && Config.StormspellAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.StormspellPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } return(result); } if (Config.ProtectEnabled && (!PL.HasStatus(StatusEffect.Protect))) { var result = new EngineAction { Spell = Config.ProtectSpell }; if (Config.AccessionEnabled && Config.AccessionProtectShell && PL.Party.GetPartyMembers().Count() > 2 && PL.AbilityAvailable(Ability.Accession) && PL.CurrentSCHCharges() > 0) { if (!PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } } return(result); } if (Config.ShellEnabled && (!PL.HasStatus(StatusEffect.Shell))) { var result = new EngineAction { Spell = Config.ShellSpell }; if (Config.AccessionEnabled && Config.AccessionProtectShell && PL.Party.GetPartyMembers().Count() > 2 && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession)) { if (!PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } } return(result); } if (Config.ReraiseEnabled && (!PL.HasStatus(StatusEffect.Reraise))) { var result = new EngineAction { Spell = Config.ReraiseSpell }; if (Config.EnlightenmentReraise && !PL.HasStatus(StatusEffect.Addendum_White) && PL.AbilityAvailable(Ability.Enlightenment)) { result.JobAbility = Ability.Enlightenment; } return(result); } if (Config.UtsusemiEnabled && PL.ShadowsRemaining() < 2) { if (PL.GetInventoryItemCount(PL.GetItemId(Items.Shihei)) > 0) { if (PL.SpellAvailable(Spells.Utsusemi_Ni)) { return(new EngineAction { Spell = Spells.Utsusemi_Ni }); } else if (PL.SpellAvailable(Spells.Utsusemi_Ichi) && (PL.ShadowsRemaining() == 0)) { return(new EngineAction { Spell = Spells.Utsusemi_Ichi }); } } } if (Config.BlinkEnabled && (!PL.HasStatus(StatusEffect.Blink)) && PL.SpellAvailable(Spells.Blink)) { var result = new EngineAction { Spell = Spells.Blink }; if (Config.AccessionEnabled && Config.BlinkAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.BlinkPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } return(result); } if (Config.PhalanxEnabled && (!PL.HasStatus(StatusEffect.Phalanx)) && PL.SpellAvailable(Spells.Phalanx)) { var result = new EngineAction { Spell = Spells.Phalanx }; if (Config.AccessionEnabled && Config.PhalanxAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.PhalanxPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } return(result); } if (Config.RefreshEnabled && (!PL.HasStatus(StatusEffect.Refresh))) { var result = new EngineAction { Spell = Config.RefreshSpell }; if (Config.AccessionEnabled && Config.RefreshAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.RefreshPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } return(result); } if (Config.RegenEnabled && (!PL.HasStatus(StatusEffect.Regen))) { var result = new EngineAction { Spell = Config.RegenSpell }; if (Config.AccessionEnabled && Config.RegenAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.RegenPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } return(result); } if (Config.AdloquiumEnabled && (!PL.HasStatus(StatusEffect.Regain)) && PL.SpellAvailable(Spells.Adloquium)) { var result = new EngineAction { Spell = Spells.Adloquium }; if (Config.AccessionEnabled && Config.AdloquiumAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.AdloquiumPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } return(result); } if (Config.StoneskinEnabled && (!PL.HasStatus(StatusEffect.Stoneskin)) && PL.SpellAvailable(Spells.Stoneskin)) { var result = new EngineAction { Spell = Spells.Stoneskin }; if (Config.AccessionEnabled && Config.StoneskinAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.StoneskinPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } return(result); } if (Config.AquaveilEnabled && (!PL.HasStatus(StatusEffect.Aquaveil)) && PL.SpellAvailable(Spells.Aquaveil)) { var result = new EngineAction { Spell = Spells.Aquaveil }; if (Config.AccessionEnabled && Config.AquaveilAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.AquaveilPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } return(result); } if (Config.KlimaformEnabled && !PL.HasStatus(StatusEffect.Klimaform)) { return(new EngineAction { Spell = Spells.Klimaform }); } if (Config.TemperEnabled && (!PL.HasStatus(StatusEffect.Multi_Strikes))) { return(new EngineAction { Spell = Config.TemperSpell }); } if (Config.HasteEnabled && (!PL.HasStatus(StatusEffect.Haste))) { return(new EngineAction { Spell = Config.HasteSpell }); } if (Config.SpikesEnabled && !PL.HasStatus(Data.SpellEffects[Config.SpikesSpell])) { return(new EngineAction { Spell = Config.SpikesSpell }); } if (Config.EnSpellEnabled && !PL.HasStatus(Data.SpellEffects[Config.EnSpell]) && PL.SpellAvailable(Config.EnSpell)) { var result = new EngineAction { Spell = Config.EnSpell }; // Don't want to try and accession/perpetuance tier II. if (!Config.EnSpell.Contains("II")) { if (Config.AccessionEnabled && Config.EnspellAccession && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Accession) && !PL.HasStatus(StatusEffect.Accession)) { result.JobAbility = Ability.Accession; } else if (Config.PerpetuanceEnabled && Config.EnspellPerpetuance && PL.CurrentSCHCharges() > 0 && PL.AbilityAvailable(Ability.Perpetuance) && !PL.HasStatus(StatusEffect.Perpetuance)) { result.JobAbility = Ability.Perpetuance; } } return(result); } if (Config.AuspiceEnabled && (!PL.HasStatus(StatusEffect.Auspice)) && PL.SpellAvailable(Spells.Auspice)) { return(new EngineAction { Spell = Spells.Auspice }); } // TODO: Rethink this whole logic. // Probably doesn't work at all right now, and need to figure out a better way // to find entities than iterating 2048 things... if (Config.AutoTargetEnabled && PL.SpellAvailable(Config.AutoTargetSpell)) { if (Config.PartyBasedHateSpell) { // PARTY BASED HATE SPELL int enemyID = CheckEngagedStatus_Hate(Config); if (enemyID != 0 && enemyID != lastKnownEstablisherTarget) { lastKnownEstablisherTarget = enemyID; return(new EngineAction { Target = Config.AutoTargetTarget, Spell = Config.AutoTargetSpell }); } } else { // ENEMY BASED TARGET int enemyID = CheckEngagedStatus_Hate(Config); if (enemyID != 0 && enemyID != lastKnownEstablisherTarget) { PL.Target.SetTarget(enemyID); lastKnownEstablisherTarget = enemyID; return(new EngineAction { Target = "<t>", Spell = Config.AutoTargetSpell }); //if (ConfigForm.config.DisableTargettingCancel == false) //{ // await Task.Delay(TimeSpan.FromSeconds((double)ConfigForm.config.TargetRemoval_Delay)); // PL.Target.SetTarget(0); //} } } } return(null); }
public EngineAction Run(CureConfig Config, bool[] enabledMembers, bool[] highPriorityMembers) { _config = Config; IEnumerable <PartyMember> partyByHP = Monitored.GetActivePartyMembers().OrderBy(member => member.CurrentHPP); /////////////////////////// PL CURE ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: Test this! Pretty sure your own character is always party member index 0. if (PL.Player.HP > 0 && (PL.Player.HPP <= Config.MonitoredCurePercentage) && Config.EnableOutOfPartyHealing && !PL.SamePartyAs(Monitored)) { var plAsPartyMember = PL.Party.GetPartyMember(0); return(CureCalculator(plAsPartyMember)); } /////////////////////////// CURAGA ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (Config.EnabledCuragaTiers.Any()) { int plParty = PL.GetPartyRelativeTo(Monitored); // Order parties that qualify for AOE cures by average missing HP. var partyNeedsAoe = Monitored.PartyNeedsAoeCure(Config.CuragaMinPlayers, Config.CuragaHealthPercent).OrderBy(partyNumber => Monitored.AverageHpLossForParty(partyNumber)); // If PL is in same alliance, and there's at least 1 party that needs an AOE cure. // Parties are ordered by most average missing HP. if (plParty > 0 && partyNeedsAoe.Any()) { int targetParty = 0; // We can accession if we have light arts/addendum white, and either we already have the status or we have the ability available, // and have the charges to use it. bool plCanAccession = (PL.HasStatus(StatusEffect.Light_Arts) || PL.HasStatus(StatusEffect.Addendum_White)) && (PL.HasStatus(StatusEffect.Accession) || (PL.AbilityAvailable(Ability.Accession) && PL.CurrentSCHCharges() > 0)); foreach (int party in partyNeedsAoe) { // We check whether we can accession here, so that if we can't accession we don't skip a chance to curaga our own party. if (party != plParty && !plCanAccession) { continue; } // We get the first party with at least 1 person who's in it and checked. // As well as 1 person who's both under the cure threshold AND in casting range. // This way we won't AOE parties we haven't got anyone checked in, and we won't attempt // to AOE a party where we can't reach any of the injured members. if (partyByHP.Count(pm => pm.InParty(party) && enabledMembers[pm.MemberNumber]) > 0) { if (partyByHP.Count(pm => pm.InParty(party) && pm.CurrentHPP < Config.CuragaHealthPercent && PL.CanCastOn(pm)) > 0) { targetParty = party; } } } if (targetParty > 0) { // The target is the first person we can cast on, since they're already ordered by HPP. var target = partyByHP.FirstOrDefault(pm => pm.InParty(targetParty) && PL.CanCastOn(pm)); if (target != default) { // If same party as PL, curaga. Otherwise we try to accession cure. if (targetParty == plParty) { // TODO: Don't do this if we have no curagas enabled, prevents curing! return(CuragaCalculator(target)); } else { var actionResult = CureCalculator(target); // We've already determined we can accession, or already have the status. if (actionResult != null && !PL.HasStatus(StatusEffect.Accession)) { actionResult.JobAbility = Ability.Accession; } return(actionResult); } } } } } /////////////////////////// CURE ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // First run a check on the monitored target if (Config.MonitoredPriorityEnabled && Monitored.Player.HP > 0 && (Monitored.Player.HPP <= Config.MonitoredCurePercentage)) { // Need to get monitored player as a PartyMember PartyMember monitoredPlayer = partyByHP.FirstOrDefault(p => p.Name == Monitored.Player.Name); if (monitoredPlayer != default) { return(CureCalculator(monitoredPlayer)); } } // Calculate who needs a cure, and is a valid target. // Anyone who's: Enabled + Active + Alive + Under cure threshold var validCures = partyByHP.Where(pm => enabledMembers[pm.MemberNumber] && (pm.CurrentHPP <= Config.CureHealthPercent) && PL.CanCastOn(pm)); // Now run a scan to check all targets in the High Priority Threshold if (validCures != null && validCures.Any()) { var highPriorityCures = validCures.Where(pm => highPriorityMembers[pm.MemberNumber]); if (highPriorityCures != null && highPriorityCures.Any()) { return(CureCalculator(highPriorityCures.First())); } else { return(CureCalculator(validCures.First())); } } return(null); }