Imports P3D.BattleSystem.Battle Namespace BattleSystem Public Class TrainerAI 'Trainer AI Levels:--------------------------------------------------------------------------------------------------------------------- 'Normal Trainers: 0-20 (0 being not very smart trainers like Bugcatchers, 20 being Cooltrainers, get higher levels when rematches occur) '(Johto) Gym Leaders: 10-40 (10 for Falkner, 40 for Clair) '(Kanto) Gym Leaders: All 60 'Elite 4: 60 'Lance: 100 'Elder Li: 10 'Rival: 40 'Team Rocket Grunts: 5 'Team Rocket Admins: 20 Public Shared Function GetAIMove(ByVal BattleScreen As BattleScreen, ByVal OwnStep As Battle.RoundConst) As Battle.RoundConst Dim p As Pokemon = BattleScreen.OppPokemon Dim op As Pokemon = BattleScreen.OwnPokemon Dim m As List(Of Attack) = p.Attacks.ToList() For i = m.Count - 1 To 0 Step -1 If m(i).CurrentPP <= 0 Then m.RemoveAt(i) End If Next If m.Count = 0 Then Return New Battle.RoundConst With {.StepType = Battle.RoundConst.StepTypes.Move, .Argument = Attack.GetAttackByID(165)} End If 'Switching: ' - check for opponent moves: if super effective: 1.5x: 25%, 2x: 50%, 4x: 75%: check for pokemon in party that reacts to every move with less the detected effectiveness k ' - check for own moves: if only 0x: check for other pokemon in party (best fitting) and switch in k ' - check for own moves: if all moves below 1x: 50%: check for other pokemon in party that has at least one move above or equal 1x ' - own pokemon got cursed: 75% k ' - own pokemon got confused: 50% k ' - if has pokemon in team that can stand the attack coming in better than the current one: 25%: switch into that pokemon reflecting that move 'Use Item: '(Useable items: Potion,Super Point,Hyper Potion,Full Heal,Full Restore,Burn Heal,Antidote,Paralyze heal,Awakening,Ice Heal,Revive,Max Revive,Max Potion) ' - Use potions if fills to at least half + own hp is below 40% (chance 60% + (40 - ownhp%)), always use best potion (normal->super->hyper->max) k ' - Use Full Heal when: Confused, Burned, Frozen, Asleep, Paralyzed, Poisoned and HP is above 25% (100%), use above status restore items. k ' - ^ same with Full Restore but without HP check, use above everything k ' - Use Status restore items if own HP is above 25%, chance: 60% k ' - Use revive when at least 50% of team is beaten, use on highest leveled pokemon (max over normal) (50%) k 'Definite move: ' - If own pokemon is asleep, try to use Snore (100%) k ' - If own pokemon is frozen and has a move to thraw out -> use that move (100%) k ' - Fake Out if first turn -> try to inflict flinch (100%) k ' - use high priority move if opponent is nearly defeated (<= 15%) (100%) k ' - use attacking move if speed is higher than opp speed and opponent has low health (<= 30%) (75%) k ' - use recover moves when HP lower than 50% (75%) k ' - try to paralyse (75%) k ' - try to confuse (75%) k ' - try to burn (75%) k ' - try to sleep (75%) k ' - try to freeze (75%) k ' - try to poison (50%) k ' - try to set up leech seed (75%) k ' - try to use FocusEnergy (50%) k ' - Set up spikes (50%) ' - setup safeguard (20%) ' - setup sandstorm, when at least half of the team is immune (50%) ' - setup hailstorm, when at least half of the team is immune (50%) ' - higher sp atk than atk, not boosted stat, higher spatk than spdef: use sp atk boost (50%) k ' - higher atk than sp atk, not boosted stat, higher atk than def: use atk boost (50%) k ' - not lowered opp def stat, higher atk than spatk, higher def than atk: use def lowering move (50%) k ' - not lowered opp sp def stat, higher sp atk than spdef, higher sp def than sp atk: use sp def lowering move (50%) k ' - when opp has lower atk than def/lower spatk than spdef and can heal stat: use stat healing move (50%) k ' - if entry hazards are on the field and more than one pokemon left: use Rapid Spin (100%) ' - if not done before, boost own evasion (50%) k ' - if not done before, lower opp accuracy (75%) k ' - use Psych up when the opponent total stat change compared to own is at least +2 (50%) ' - has Reflect/Light Screen: Uses the one that fits better for the own stat (75%) k ' - when having a move with accuracy lower than 60 and Mind Reader/Lock On -> Use Mind Reader/Lock On (50%) ' - Use fascade, if burned, paralysed or poisoned (50%) ' - use smelling salt if opponent is paralysed (100%) 'Special Moveset combos: ' - Defense Curl + Rollout k ' - Sunny Day + Solar Beam / Sunny weather + Solar Beam ' - Raindance + Thunder / Rain weather + Thunder / Sunny weather + Thunder ' - Sleep inducting move + Dream Eater / Use Dream Eater if target is asleep ' - Flash + Ride ' - Ghost Pokemon and Curse ' - Use Flail/Reversal when HP is really low ' - Conversion2/Conversion ' - Protect/Detect: when opp used a strong move ' - use Uproar if not set up and detect opponent with sleep moves ' - Stockpile + Swallow/SpitUp ' - Thunderwave + Smelling Salt 'After choosing attacking moves: ' - not use belly drum/substitute with too low HP ' - not use any move that doesnt work due to type disadventage (ghost-normal, normal-ghost, fighting-ghost, dragon-fairy) 'Choose attack move: ' - look for abilities that absorb move types ' - base power, accuracy, effectiveness, STAB, PP Left, attack stats (atk/spatk), EV, IV, defense stat (def/spdef) ' - never use splash ' - use never-miss attack when own accuracy is low/opp evasion is high '-------------------------------------AI BEGIN------------------------------------------------------------------------------------' '-------------------------------------Encore Move if an encore is in effect-------------------------------------------------------' If BattleScreen.FieldEffects.OppEncore > 0 Then Dim attackIndex As Integer = -1 For a = 0 To p.Attacks.Count - 1 If p.Attacks(a).ID = BattleScreen.FieldEffects.OppEncoreMove.ID Then attackIndex = a End If Next If attackIndex <> -1 AndAlso p.Attacks(attackIndex).CurrentPP > 0 Then Return New RoundConst() With {.StepType = RoundConst.StepTypes.Move, .Argument = BattleScreen.FieldEffects.OppEncoreMove} Else BattleScreen.FieldEffects.OppEncoreMove = Nothing BattleScreen.FieldEffects.OppEncore = 0 BattleScreen.BattleQuery.Add(New TextQueryObject(p.GetDisplayName() & "'s encore stopped.")) End If End If '-------------------------------------Random move depending on difficulty---------------------------------------------------------' 'Only applies if trainer has an AI level below 20: If BattleScreen.Trainer.AILevel < 20 Then Dim AvailableAttacks As List(Of Integer) = New List(Of Integer) For i = 0 To m.Count - 1 AvailableAttacks.Add(i) Next Dim OppAttackChoice As Integer = Core.Random.Next(0, AvailableAttacks.Count) Dim Ready As Boolean = False While Ready = False If m(OppAttackChoice) Is BattleScreen.FieldEffects.OppTormentMove OrElse m(OppAttackChoice).Disabled > 0 OrElse BattleScreen.FieldEffects.OppTaunt > 0 AndAlso BattleScreen.OppPokemon.Attacks(OppAttackChoice).Category = Attack.Categories.Status Then AvailableAttacks.Remove(OppAttackChoice) If AvailableAttacks.Count > 0 Then OppAttackChoice = AvailableAttacks(Core.Random.Next(0, AvailableAttacks.Count)) Else Return New RoundConst() With {.StepType = RoundConst.StepTypes.Move, .Argument = Attack.GetAttackByID(165)} End If Else Ready = True End If End While If Core.Player.DifficultyMode = 0 Then 'Chance of 35% that the trainer is using a random move: If Core.Random.Next(0, 100) < 35 Then Return ProduceOppStep(m, OppAttackChoice) End If ElseIf Core.Player.DifficultyMode = 1 Then 'Chance of 18% that the trainer is using a random move: If Core.Random.Next(0, 100) < 18 Then Return ProduceOppStep(m, OppAttackChoice) End If End If End If '-------------------------------------Switching-----------------------------------------------------------------------------------' 'Only applies if trainer has an AI level above or equal 40: 'If BattleScreen.Trainer.AILevel >= 40 Then ' If BattleCalculation.CanSwitch(BattleScreen, False) = True Then ' If BattleScreen.Trainer.Pokemons.Count > 0 Then ' Dim living As Integer = 0 ' For Each cP As Pokemon In BattleScreen.Trainer.Pokemons ' If cP.HP > 0 And cP.Status <> Pokemon.StatusProblems.Fainted Then ' living += 1 ' End If ' Next ' If living > 1 Then ' 'check for opponent moves: if super effective: 1.5x: 25%, 2x: 50%, 4x: 75%: check for pokemon in party that reacts to every move with less the detected effectiveness ' Dim maxOpponentEff As Single = 0.0F ' For Each Attack As BattleSystem.Attack In op.Attacks ' Dim effectiveness As Single = BattleCalculation.CalculateEffectiveness(Attack.GetAttackByID(Attack.ID), BattleScreen, op, p, True) ' If effectiveness > maxOpponentEff Then ' maxOpponentEff = effectiveness ' End If ' Next ' If maxOpponentEff > 1.0F Then ' Dim chance As Integer = 0 ' Select Case maxOpponentEff ' Case 1.25F ' chance = 10 ' Case 1.5F ' chance = 25 ' Case 2.0F ' chance = 35 ' Case 4.0F ' chance = 50 ' End Select ' If RPercent(chance) = True Then ' Dim lessTeamPs As New List(Of Integer) ' For i = 0 To BattleScreen.Trainer.Pokemons.Count - 1 ' If i <> BattleScreen.OppPokemonIndex Then ' Dim TeamP As Pokemon = BattleScreen.Trainer.Pokemons(i) ' If TeamP.HP > 0 And TeamP.Status <> Pokemon.StatusProblems.Fainted Then ' Dim alwaysLess As Boolean = True ' For Each Attack As BattleSystem.Attack In op.Attacks ' Dim effectiveness As Single = BattleCalculation.CalculateEffectiveness(Attack.GetAttackByID(Attack.ID), BattleScreen, op, TeamP, True) ' If effectiveness >= maxOpponentEff Then ' alwaysLess = False ' Exit For ' End If ' Next ' If alwaysLess = True Then ' lessTeamPs.Add(i) ' End If ' End If ' End If ' Next ' If lessTeamPs.Count > 0 Then ' Return ProduceOppStep(lessTeamPs(Core.Random.Next(0, lessTeamPs.Count))) ' End If ' End If ' End If ' 'check for own moves: if only 0x: check for other pokemon in party (best fitting) and switch in ' Dim only0 As Boolean = True ' For Each Attack As BattleSystem.Attack In p.Attacks ' Dim effectiveness As Single = BattleCalculation.CalculateEffectiveness(Attack.GetAttackByID(Attack.ID), BattleScreen, p, op, False) ' If effectiveness <> 0.0F Then ' only0 = False ' Exit For ' End If ' Next ' If only0 = True Then ' Dim switchList As New List(Of Integer) ' For i = 0 To BattleScreen.Trainer.Pokemons.Count - 1 ' If i <> BattleScreen.OppPokemonIndex Then ' Dim TeamP As Pokemon = BattleScreen.Trainer.Pokemons(i) ' If TeamP.HP > 0 And TeamP.Status <> Pokemon.StatusProblems.Fainted Then ' switchList.Add(i) ' End If ' End If ' Next ' If switchList.Count > 0 Then ' Return ProduceOppStep(switchList(Core.Random.Next(0, switchList.Count))) ' End If ' End If ' 'own pokemon got cursed: 75% ' If BattleScreen.FieldEffects.OppCurse > 0 Then ' If RPercent(75) = True Then ' Dim newSwitchIndex As Integer = 0 ' Dim canSwitchTo As New List(Of Integer) ' For i = 0 To BattleScreen.Trainer.Pokemons.Count - 1 ' Dim TeamP As Pokemon = BattleScreen.Trainer.Pokemons(i) ' If TeamP.HP > 0 And TeamP.Status <> Pokemon.StatusProblems.Fainted And i <> BattleScreen.OppPokemonIndex Then ' canSwitchTo.Add(i) ' End If ' Next ' If canSwitchTo.Count > 0 Then ' newSwitchIndex = canSwitchTo(Core.Random.Next(0, canSwitchTo.Count)) ' Return ProduceOppStep(newSwitchIndex) ' End If ' End If ' End If ' 'own pokemon got confused: 50% ' If p.HasVolatileStatus(Pokemon.VolatileStatus.Confusion) = True Then ' If RPercent(50) = True Then ' Dim newSwitchIndex As Integer = 0 ' Dim canSwitchTo As New List(Of Integer) ' For i = 0 To BattleScreen.Trainer.Pokemons.Count - 1 ' Dim TeamP As Pokemon = BattleScreen.Trainer.Pokemons(i) ' If TeamP.HP > 0 And TeamP.Status <> Pokemon.StatusProblems.Fainted And i <> BattleScreen.OppPokemonIndex Then ' canSwitchTo.Add(i) ' End If ' Next ' If canSwitchTo.Count > 0 Then ' newSwitchIndex = canSwitchTo(Core.Random.Next(0, canSwitchTo.Count)) ' Return ProduceOppStep(newSwitchIndex) ' End If ' End If ' End If ' End If ' End If ' End If 'End If '-------------------------------------Items---------------------------------------------------------------------------------------' 'same with Full Restore but without HP check, use above everything If p.HasVolatileStatus(Pokemon.VolatileStatus.Confusion) = True Or p.Status <> Pokemon.StatusProblems.None And p.Status <> Pokemon.StatusProblems.Fainted Then If TrainerHasItem(14, BattleScreen) = True Then If Not (TrainerHasItem(38, BattleScreen) = True And p.HP = p.MaxHP) = True Then Return ProduceOppStep(14, -1) End If End If End If 'Use potions if fills to at least half + own hp is below 40% (chance 60% + (40 - ownhp%)), always use best potion (normal->super->hyper->max) If p.HP <= CInt((p.MaxHP / 100) * 40) Then Dim potion As Integer = GetBestPotion(BattleScreen) If potion > -1 Then If TrainerHasItem(potion, BattleScreen) = True Then Dim chance As Integer = GetPokemonValue(BattleScreen, p) + (40 - CInt((p.HP / p.MaxHP) * 100)) If RPercent(chance) = True Then Dim HP As Integer = GetPotionHealHP(p, potion) If HP >= CInt(Math.Ceiling(p.MaxHP / 2)) Then Return ProduceOppStep(potion, -1) End If End If End If End If End If 'Use Full Heal when: Confused, Burned, Frozen, Asleep, Paralyzed, Poisoned and HP is above 25% (100%), use above status restore items. If p.HasVolatileStatus(Pokemon.VolatileStatus.Confusion) = True Or p.Status <> Pokemon.StatusProblems.None And p.Status <> Pokemon.StatusProblems.Fainted Then If p.HP >= CInt((p.MaxHP / 100) * 25) Then If TrainerHasItem(38, BattleScreen) = True Then Return ProduceOppStep(38, -1) End If End If End If 'Use Status restore items if own HP is above 25%, chance: 60% If p.HP >= CInt((p.MaxHP / 100) * 25) Then If p.Status <> Pokemon.StatusProblems.None And p.Status <> Pokemon.StatusProblems.Fainted Then If RPercent(60) = True Then Select Case p.Status Case Pokemon.StatusProblems.Poison, Pokemon.StatusProblems.BadPoison If TrainerHasItem(9, BattleScreen) = True Then Return ProduceOppStep(9, -1) End If Case Pokemon.StatusProblems.Burn If TrainerHasItem(10, BattleScreen) = True Then Return ProduceOppStep(10, -1) End If Case Pokemon.StatusProblems.Freeze If TrainerHasItem(11, BattleScreen) = True Then Return ProduceOppStep(11, -1) End If Case Pokemon.StatusProblems.Sleep If TrainerHasItem(12, BattleScreen) = True Then Return ProduceOppStep(12, -1) End If Case Pokemon.StatusProblems.Paralyzed If TrainerHasItem(13, BattleScreen) = True Then Return ProduceOppStep(13, -1) End If End Select End If End If End If 'Use revive when at least 50% of team is beaten, use on highest leveled pokemon (max over normal) (50%) If RPercent(50) = True And (TrainerHasItem(39, BattleScreen) = True Or TrainerHasItem(40, BattleScreen) = True) = True Then Dim beaten As Integer = 0 For Each TeamP As Pokemon In BattleScreen.Trainer.Pokemons If TeamP.HP <= 0 Or TeamP.Status = Pokemon.StatusProblems.Fainted Or TeamP.IsEgg() = True Then beaten += 1 End If Next If beaten >= CInt(Math.Floor(BattleScreen.Trainer.Pokemons.Count / 2)) Then Dim highestLevel As Integer = -1 For i = 0 To BattleScreen.Trainer.Pokemons.Count - 1 Dim TeamP As Pokemon = BattleScreen.Trainer.Pokemons(i) If TeamP.IsEgg() = False Then If TeamP.HP <= 0 Or TeamP.Status = Pokemon.StatusProblems.Fainted Then If highestLevel = -1 OrElse BattleScreen.Trainer.Pokemons(highestLevel).Level < TeamP.Level Then highestLevel = i End If End If End If Next If highestLevel > -1 Then Dim bestRevive As Integer = GetBestRevive(BattleScreen) Return ProduceOppStep(bestRevive, highestLevel) End If End If End If '-------------------------------------Moves---------------------------------------------------------------------------------------' 'If own pokemon is asleep, try to use Sleep Talk (100%) If p.Status = Pokemon.StatusProblems.Sleep And BattleScreen.FieldEffects.OppSleepTurns > 1 And HasMove(m, 214) = True AndAlso m(IDtoMoveIndex(m, 214)).Disabled = 0 AndAlso m(IDtoMoveIndex(m, 214)) IsNot BattleScreen.FieldEffects.OppTormentMove Then If BattleScreen.FieldEffects.OppTaunt = 0 OrElse m(IDtoMoveIndex(m, 214)).Category <> Attack.Categories.Status Then Return ProduceOppStep(m, IDtoMoveIndex(m, 214)) End If End If 'If own pokemon is asleep, try to use Snore (100%) If p.Status = Pokemon.StatusProblems.Sleep And BattleScreen.FieldEffects.OppSleepTurns > 1 And HasMove(m, 173) = True AndAlso m(IDtoMoveIndex(m, 173)).Disabled = 0 AndAlso m(IDtoMoveIndex(m, 173)) IsNot BattleScreen.FieldEffects.OppTormentMove Then If BattleScreen.FieldEffects.OppTaunt = 0 OrElse m(IDtoMoveIndex(m, 173)).Category <> Attack.Categories.Status Then Return ProduceOppStep(m, IDtoMoveIndex(m, 173)) End If End If 'If own pokemon is frozen and has a move to thraw out -> use that move If p.Status = Pokemon.StatusProblems.Freeze Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.ThrawOut) If chosenMove > -1 Then Return ProduceOppStep(m, chosenMove) End If End If 'Fake Out if first turn -> try to inflict flinch (100%) If HasMove(m, 252) = True AndAlso m(IDtoMoveIndex(m, 252)).Disabled = 0 AndAlso m(IDtoMoveIndex(m, 252)) IsNot BattleScreen.FieldEffects.OppTormentMove Then If op.Ability.Name.ToLower() <> "inner focus" Then Dim turns As Integer = BattleScreen.FieldEffects.OppPokemonTurns If turns = 0 Then Return ProduceOppStep(m, IDtoMoveIndex(m, 252)) End If End If End If 'use high priority move if opponent is nearly defeated (<= 15%) (100%) If op.HP <= CInt((op.MaxHP / 100) * 15) Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.HighPriority) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If 'use attacking move if speed is higher than opp speed and opponent has low health (<= 30%) (75%) If p.Speed > op.Speed And op.HP <= CInt((op.MaxHP / 100) * 30) Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.Damage) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If 'use recover moves when HP lower than 50% (50%): If p.HP <= CInt(p.MaxHP / 2) Then Dim chance As Integer = 50 'make chance higher when opp has a status condition: If op.Status = Pokemon.StatusProblems.Freeze Or op.Status = Pokemon.StatusProblems.Paralyzed Or op.HasVolatileStatus(Pokemon.VolatileStatus.Confusion) = True Then chance = 75 End If If op.Status = Pokemon.StatusProblems.Sleep Then chance = 100 End If If RPercent(chance) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.Healing) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If 'Try to use Brick Break move if opponent has LightScreen/Reflect up: If op.IsType(Element.Types.Ghost) = False Then If BattleScreen.FieldEffects.OwnReflect > 0 Or BattleScreen.FieldEffects.OwnLightScreen > 0 Then If RPercent(80) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.RemoveReflectLightscreen) If chosenMove > -1 Then Return ProduceOppStep(m, chosenMove) End If End If End If End If 'try to inflict status: 'check if substitute is up: If BattleScreen.FieldEffects.OwnSubstitute = 0 Then 'check no status already applies: If op.Status = Pokemon.StatusProblems.None Then 'try to paralyse (75%) If op.Status <> Pokemon.StatusProblems.Paralyzed Then If op.Type1.Type <> Element.Types.Electric And op.Type2.Type <> Element.Types.Electric Then If op.Ability.Name.ToLower() <> "limber" Then If RPercent(75) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.Paralysis) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If End If End If 'try to burn (75%) If op.Status <> Pokemon.StatusProblems.Burn Then If op.Type1.Type <> Element.Types.Fire And op.Type2.Type <> Element.Types.Fire Then If op.Ability.Name.ToLower() <> "water veil" Then If RPercent(75) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.Burn) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If End If End If 'try to sleep (75%) If op.Status <> Pokemon.StatusProblems.Sleep Then If op.Ability.Name.ToLower() <> "vital spirit" Then If op.Ability.Name.ToLower() <> "insomnia" Then If RPercent(75) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.Sleep) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If End If End If 'try to poison (50%) If op.Status <> Pokemon.StatusProblems.BadPoison And op.Status <> Pokemon.StatusProblems.Poison Then If op.Type1.Type <> Element.Types.Steel And op.Type1.Type <> Element.Types.Poison And op.Type2.Type <> Element.Types.Steel And op.Type2.Type <> Element.Types.Poison Then If op.Ability.Name.ToLower() <> "immunity" Then If RPercent(50) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.Poison) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If End If End If End If End If 'try to confuse (75%) 'check if opp isnt confused already: If op.HasVolatileStatus(Pokemon.VolatileStatus.Confusion) = False Then If op.Ability.Name.ToLower() <> "own tempo" Then If RPercent(75) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.Confusion) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If End If 'try to set up leech seed (75%) If op.IsType(Element.Types.Grass) = False Then If BattleScreen.FieldEffects.OwnLeechSeed = 0 Then If HasMove(m, 73) = True AndAlso m(IDtoMoveIndex(m, 73)).Disabled = 0 AndAlso m(IDtoMoveIndex(m, 73)) IsNot BattleScreen.FieldEffects.OppTormentMove Then If BattleScreen.FieldEffects.OppTaunt = 0 OrElse m(IDtoMoveIndex(m, 75)).Category <> Attack.Categories.Status Then If RPercent(75) = True Then Return ProduceOppStep(m, IDtoMoveIndex(m, 73)) End If End If End If End If End If 'try to use FocusEnergy (50%) If BattleScreen.FieldEffects.OppFocusEnergy = 0 Then If HasMove(m, 116) = True AndAlso m(IDtoMoveIndex(m, 116)).Disabled = 0 AndAlso m(IDtoMoveIndex(m, 116)) IsNot BattleScreen.FieldEffects.OppTormentMove Then If BattleScreen.FieldEffects.OppTaunt = 0 OrElse m(IDtoMoveIndex(m, 116)).Category <> Attack.Categories.Status Then If RPercent(50) = True Then Return ProduceOppStep(m, IDtoMoveIndex(m, 116)) End If End If End If End If 'higher sp atk than atk, not boosted stat, higher spatk than spdef: use sp atk boost (50%) If p.SpAttack > p.Attack And p.StatSpAttack <= 0 And p.SpAttack > p.SpDefense Then If RPercent(50) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.RaiseSpAttack) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If 'higher atk than sp atk, not boosted stat, higher atk than def: use atk boost (50%) If p.Attack > p.SpAttack And p.StatAttack <= 0 And p.Attack > p.Defense Then If RPercent(50) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.RaiseAttack) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If 'not lowered opp def stat, higher atk than spatk, higher def than atk: use def lowering move (50%) If p.Attack > p.SpAttack And p.Defense > p.Attack And op.StatDefense >= 0 Then If RPercent(50) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.LowerDefense) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If 'not lowered opp spdef stat, higher spatk than atk, higher spdef than spatk: use spdef lowering move (50%) If p.SpAttack > p.Attack And p.SpDefense > p.SpAttack And op.StatSpDefense >= 0 Then If RPercent(50) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.LowerSpDefense) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If 'when opp has lower atk than def/lower spatk than spdef and can heal stat: use stat healing move (50%) If op.SpAttack > op.Attack And op.SpAttack < op.SpDefense Or op.Attack > op.SpAttack And op.Attack < op.Defense Then If p.Status = Pokemon.StatusProblems.BadPoison Or p.Status = Pokemon.StatusProblems.Burn Or p.Status = Pokemon.StatusProblems.Freeze Or p.Status = Pokemon.StatusProblems.Paralyzed Or p.Status = Pokemon.StatusProblems.Poison Or p.Status = Pokemon.StatusProblems.Sleep Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.CureStatus) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If 'if not done before, boost own evasion (50%) If p.Evasion <= 0 Then If RPercent(50) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.RaiseEvasion) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If 'if not done before, boost own accuracy (75%) If p.Evasion <= 0 Then If RPercent(75) = True Then Dim chosenMove As Integer = MoveAI(m, Attack.AIField.RaiseEvasion) If chosenMove > -1 Then If CheckForTypeIneffectiveness(BattleScreen, m, chosenMove) = True Then Return ProduceOppStep(m, chosenMove) End If End If End If End If 'Use LightScreen/Reflect (75%): If RPercent(75) = True Then If HasMove(m, 113) = True And op.SpAttack > op.Attack And BattleScreen.FieldEffects.OppLightScreen = 0 AndAlso m(IDtoMoveIndex(m, 113)).Disabled = 0 AndAlso m(IDtoMoveIndex(m, 113)) IsNot BattleScreen.FieldEffects.OppTormentMove Then If BattleScreen.FieldEffects.OppTaunt = 0 OrElse m(IDtoMoveIndex(m, 113)).Category <> Attack.Categories.Status Then Return ProduceOppStep(m, IDtoMoveIndex(m, 113)) End If End If If HasMove(m, 115) = True And op.Attack > op.SpAttack And BattleScreen.FieldEffects.OppReflect = 0 AndAlso m(IDtoMoveIndex(m, 115)).Disabled = 0 AndAlso m(IDtoMoveIndex(m, 115)) IsNot BattleScreen.FieldEffects.OppTormentMove Then If BattleScreen.FieldEffects.OppTaunt = 0 OrElse m(IDtoMoveIndex(m, 115)).Category <> Attack.Categories.Status Then Return ProduceOppStep(m, IDtoMoveIndex(m, 115)) End If End If End If 'Special Moveset combos: ' - Defense Curl + Rollout If HasMove(m, 205) = True And HasMove(m, 111) = True Then If BattleScreen.FieldEffects.OppDefenseCurl = 0 AndAlso m(IDtoMoveIndex(m, 111)).Disabled = 0 AndAlso m(IDtoMoveIndex(m, 111)) IsNot BattleScreen.FieldEffects.OppTormentMove Then If BattleScreen.FieldEffects.OppTaunt = 0 OrElse m(IDtoMoveIndex(m, 111)).Category <> Attack.Categories.Status Then Return ProduceOppStep(m, IDtoMoveIndex(m, 111)) End If Else If BattleScreen.FieldEffects.OppTaunt = 0 OrElse m(IDtoMoveIndex(m, 205)).Category <> Attack.Categories.Status Then If m(IDtoMoveIndex(m, 205)).Disabled = 0 Then Return ProduceOppStep(m, IDtoMoveIndex(m, 205)) End If End If End If End If 'Determine best attacking move: Dim attackDic As New Dictionary(Of Integer, Integer) For i = 0 To m.Count - 1 If MoveHasAIField(m(i), Attack.AIField.Damage) = True AndAlso m(i).Disabled = 0 AndAlso m(i) IsNot BattleScreen.FieldEffects.OppTormentMove Then If BattleScreen.FieldEffects.OppTaunt = 0 OrElse m(IDtoMoveIndex(m, 214)).Category <> Attack.Categories.Status Then attackDic.Add(i, 0) End If End If Next 'If has more than 0 attacking moves: If attackDic.Count > 0 Then For i = 0 To attackDic.Count - 1 Dim key As Integer = attackDic.Keys(i) Dim cMove As Attack = m(key) Dim value As Integer = 0 Dim effectiveness As Single = BattleCalculation.CalculateEffectiveness(False, cMove, BattleScreen) 'Base power If effectiveness <> 0.0F Then value += CInt(cMove.GetBasePower(False, BattleScreen) * effectiveness) End If 'Accuracy value += cMove.GetAccuracy(False, BattleScreen) 'STAB If p.IsType(cMove.Type.Type) = True Then value += 35 End If 'Ignore PP left for now... 'Attack stats: If cMove.Category = Attack.Categories.Physical Then value += p.StatAttack * 15 Else 'Special value += p.StatSpAttack * 15 End If If cMove.UseOppDefense = True Then If cMove.Category = Attack.Categories.Physical Then value -= op.StatDefense * 15 Else 'Special value -= p.StatSpDefense * 15 End If End If 'Dry skin: +fire If cMove.GetAttackType(False, BattleScreen).Type = Element.Types.Fire And op.Ability.Name.ToLower() = "dry skin" Then value += 25 End If 'Use never-miss attack when own accuracy is low/opp evasion is high If cMove.Accuracy = 0 Or cMove.GetUseAccEvasion(False, BattleScreen) = False Then If p.Accuracy < 0 Then value += CInt(Math.Abs(p.Accuracy * 15)) End If If op.Evasion > 0 Then value += op.Evasion * 15 End If End If 'If the pokemon has other options, dont use selfdestruct or explosion too often: If cMove.ID = 120 Or cMove.ID = 153 Then If Core.Random.Next(0, 8) <> 0 Then value = Core.Random.Next(50, 100) End If End If 'Add randomness value: value += Core.Random.Next(-35, 35) If value < 0 Then value = 0 End If 'Effectiveness: If effectiveness = 0.0F Then value = 0 End If 'Don't use moves that get absorbed by abilities: If cMove.GetAttackType(False, BattleScreen).Type = Element.Types.Water And op.Ability.Name.ToLower() = "water absorb" Then value = 0 End If If cMove.GetAttackType(False, BattleScreen).Type = Element.Types.Electric And op.Ability.Name.ToLower() = "volt absorb" Then value = 0 End If If cMove.GetAttackType(False, BattleScreen).Type = Element.Types.Electric And op.Ability.Name.ToLower() = "motor drive" Then value = 0 End If If cMove.GetAttackType(False, BattleScreen).Type = Element.Types.Grass And op.Ability.Name.ToLower() = "sap sipper" Then value = 0 End If If cMove.GetAttackType(False, BattleScreen).Type = Element.Types.Fire And op.Ability.Name.ToLower() = "flash fire" Then value = 0 End If If cMove.GetAttackType(False, BattleScreen).Type = Element.Types.Water And op.Ability.Name.ToLower() = "dry skin" Then value = 0 End If 'Special moves to not use: If cMove.ID = 150 Then 'Never use splash value = 0 End If If cMove.ID = 214 And p.Status <> Pokemon.StatusProblems.Sleep Then 'Never use Sleep Talk when user is not sleeping. value = 0 End If If cMove.ID = 171 And op.Status <> Pokemon.StatusProblems.Sleep Then 'Never use nightmare when opponent is not sleeping. value = 0 End If If cMove.ID = 138 And op.Status <> Pokemon.StatusProblems.Sleep Then 'Never use Dream eater when opponent is not sleeping value = 0 End If attackDic(key) = value Next 'Debug feature: Enable if not sure 'Logger.Debug("RESULTS:") 'For t = 0 To attackDic.Count - 1 ' Logger.Debug(t.ToString() & ": " & m(attackDic.Keys(t)).Name & "; VALUE: " & attackDic.Values(t)) 'Next Dim index As Integer = 0 If attackDic.Count > 1 Then If attackDic.Values(1) > attackDic.Values(index) Then index = 1 End If End If If attackDic.Count > 2 Then If attackDic.Values(2) > attackDic.Values(index) Then index = 2 End If End If If attackDic.Count > 3 Then If attackDic.Values(3) > attackDic.Values(index) Then index = 3 End If End If 'Dis too: 'Logger.Debug("CHOSEN: " & m(attackDic.Keys(index)).Name & "; VALUE: " & attackDic.Values(index)) Return ProduceOppStep(m, attackDic.Keys(index)) End If 'once everything else failed, choose one of the attacking moves: Dim chosenAttackMove As Integer = MoveAI(m, Attack.AIField.Damage) If chosenAttackMove > -1 Then Return ProduceOppStep(m, chosenAttackMove) End If 'if no attacking moves, return random move: If BattleScreen.Trainer.AILevel >= 0 Then Dim AvailableAttacks As List(Of Integer) = New List(Of Integer) For i = 0 To m.Count - 1 AvailableAttacks.Add(i) Next Dim OppAttackChoice As Integer = Core.Random.Next(0, AvailableAttacks.Count) Dim Ready As Boolean = False While Ready = False If m(OppAttackChoice) Is BattleScreen.FieldEffects.OppTormentMove OrElse m(OppAttackChoice).Disabled > 0 OrElse BattleScreen.FieldEffects.OppTaunt > 0 AndAlso BattleScreen.OppPokemon.Attacks(OppAttackChoice).Category = Attack.Categories.Status Then AvailableAttacks.Remove(OppAttackChoice) If AvailableAttacks.Count > 0 Then OppAttackChoice = AvailableAttacks(Core.Random.Next(0, AvailableAttacks.Count)) Else Return New RoundConst() With {.StepType = RoundConst.StepTypes.Move, .Argument = Attack.GetAttackByID(165)} End If Else Ready = True End If End While Return ProduceOppStep(m, OppAttackChoice) End If 'catch crash: return struggle Return New RoundConst() With {.StepType = RoundConst.StepTypes.Move, .Argument = Attack.GetAttackByID(165)} End Function Private Shared Function HasOtherAttackingMoveThanExplosion(ByVal m As List(Of Attack), ByVal leaveOutIndex As Integer) As Boolean For i = 0 To m.Count - 1 If i <> leaveOutIndex Then If m(i).ID <> 121 And m(i).ID <> 153 Then Return True End If End If Next Return False End Function Private Shared Function GetAttackingMove(ByVal BattleScreen As BattleScreen, ByVal m As List(Of Attack)) As Integer Return 0 End Function Private Shared Function CheckForTypeIneffectiveness(ByVal BattleScreen As BattleScreen, ByVal m As List(Of Attack), ByVal i As Integer) As Boolean Dim move As Attack = m(i) If move.ImmunityAffected = True Then Dim effectiveness As Single = BattleCalculation.CalculateEffectiveness(False, move, BattleScreen) If effectiveness = 0.0F Then Return False End If End If Return True End Function Private Shared Function RPercent(ByVal p As Integer) As Boolean If p >= 100 Then Return True End If If Core.Random.Next(0, 100) < p Then Return True End If Return False End Function Private Shared Function MoveAI(ByVal m As List(Of Attack), ByVal AIType As Attack.AIField) As Integer Dim validMoves As New List(Of Integer) Dim _battleScreen As Screen = Core.CurrentScreen While _battleScreen.Identification <> Screen.Identifications.BattleScreen _battleScreen = _battleScreen.PreScreen End While For i = 0 To m.Count - 1 If m(i).Disabled = 0 AndAlso m(i) IsNot CType(_battleScreen, BattleScreen).FieldEffects.OppTormentMove Then If CType(_battleScreen, BattleScreen).FieldEffects.OppTaunt = 0 OrElse m(i).Category <> Attack.Categories.Status Then If m(i).AIField1 = AIType Or m(i).AIField2 = AIType Or m(i).AIField3 = AIType Then validMoves.Add(i) End If End If End If Next If validMoves.Count > 0 Then Return validMoves(Core.Random.Next(0, validMoves.Count)) End If Return -1 End Function Private Shared Function MoveHasAIField(ByVal m As Attack, ByVal AIType As Attack.AIField) As Boolean Return m.AIField1 = AIType Or m.AIField2 = AIType Or m.AIField3 = AIType End Function Private Shared Function HasMove(ByVal m As List(Of Attack), ByVal ID As Integer) As Boolean For Each move As Attack In m If move.ID = ID Then Return True End If Next Return False End Function Private Shared Function IDtoMoveIndex(ByVal m As List(Of Attack), ByVal ID As Integer) As Integer For i = 0 To m.Count - 1 If m(i).ID = ID Then Return i End If Next Return -1 End Function #Region "ProduceSteps" Private Shared Function ProduceOppStep(ByVal m As List(Of Attack), ByVal i As Integer) As Battle.RoundConst While i > m.Count - 1 i -= 1 End While If m.Count = 0 Then Throw New Exception("An empty move array got passed in!") End If Return New Battle.RoundConst With {.StepType = Battle.RoundConst.StepTypes.Move, .Argument = m(i)} End Function Private Shared Function ProduceOppStep(ByVal ItemID As Integer, ByVal target As Integer) As Battle.RoundConst Return New Battle.RoundConst With {.StepType = Battle.RoundConst.StepTypes.Item, .Argument = ItemID.ToString() & "," & target.ToString()} End Function Private Shared Function ProduceOppStep(ByVal SwitchID As Integer) As Battle.RoundConst Return New Battle.RoundConst With {.StepType = Battle.RoundConst.StepTypes.Switch, .Argument = SwitchID.ToString()} End Function #End Region #Region "Item" Private Shared Function TrainerHasItem(ByVal ItemID As Integer, ByVal BattleScreen As BattleScreen) As Boolean For Each Item As Item In BattleScreen.Trainer.Items If Item.ID = ItemID Then Return True End If Next Return False End Function Private Shared Function GetBestPotion(ByVal BattleScreen As BattleScreen) As Integer Dim potionRange As List(Of Integer) = {18, 17, 16, 15, 14}.ToList() Dim bestPotion As Integer = -1 For Each I As Item In BattleScreen.Trainer.Items If potionRange.Contains(I.ID) = True Then If potionRange.IndexOf(I.ID) > bestPotion Then bestPotion = potionRange.IndexOf(I.ID) End If End If Next If bestPotion = -1 Then Return -1 Else Return potionRange(bestPotion) End If End Function Private Shared Function GetBestRevive(ByVal BattleScreen As BattleScreen) As Integer For Each Item As Item In BattleScreen.Trainer.Items If Item.ID = 40 Then Return 40 End If Next Return 39 End Function Private Shared Function GetPotionHealHP(ByVal p As Pokemon, ByVal ItemID As Integer) As Integer Select Case ItemID Case 18 Return 20 Case 17 Return 50 Case 16 Return 200 Case 15 Return p.MaxHP Case 14 Return p.MaxHP End Select Return 0 End Function #End Region Private Shared Function GetPokemonValue(ByVal BattleScreen As BattleScreen, ByVal p As Pokemon) As Integer Dim total As Integer = 0 For Each TeamP As Pokemon In BattleScreen.Trainer.Pokemons total += TeamP.BaseHP + TeamP.BaseAttack + TeamP.BaseDefense + TeamP.BaseSpAttack + TeamP.BaseSpDefense + TeamP.BaseSpeed Next Dim pTotal As Integer = p.BaseHP + p.BaseAttack + p.BaseDefense + p.BaseSpAttack + p.BaseSpDefense + p.BaseSpeed Dim percent As Integer = CInt((pTotal / total) * 100) Return percent End Function End Class End Namespace