Advertisement
aizakkuadoman

Untitled

May 3rd, 2025
19
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.90 KB | None | 0 0
  1. ################################################################################
  2. # Choose a move to use.
  3. ################################################################################
  4. def pbChooseMoves(index)
  5. attacker=@battlers[index]
  6. scores=[0,0,0,0]
  7. targets=nil
  8. myChoices=[]
  9. totalscore=0
  10. target=-1
  11. skill=0
  12. wildbattle=!@opponent && pbIsOpposing?(index)
  13.  
  14. #if wildbattle (commented out by JZ)
  15. if false==true # Nightmare Conquer score selection by JZ, which i made useless, #by low
  16. skill=100
  17. baseDamageArray=[]
  18. opponent=attacker.pbPartner
  19. for j in 0...attacker.moves.length
  20. next if attacker.moves[j].id < 1
  21. # check attacker.moves[j].basedamage and if this is 0 instead check the status method
  22. dmgValue = pbRoughDamage(attacker.moves[j],attacker,opponent,skill,attacker.moves[j].basedamage)
  23. if attacker.moves[j].basedamage!=0
  24. if opponent.hp==0
  25. dmgPercent = 0
  26. else
  27. dmgPercent = (dmgValue*100)/(opponent.hp)
  28. dmgPercent = 110 if dmgPercent > 110
  29. end
  30. else
  31. dmgPercent = pbStatusDamage(attacker.moves[j])
  32. end
  33. #~ File.open("AI_final_log.txt", "a") do |line|
  34. #~ line.puts "Conquered vs Partner: Move " + PBMoves.getName(attacker.moves[j].id).to_s + " has rough damage " + dmgValue.to_s + " and damage % " +dmgPercent.to_s
  35. #~ end
  36. baseDamageArray.push(dmgPercent)
  37. end
  38.  
  39. for i in 0...attacker.moves.length
  40. if pbCanChooseMove?(index,i,false)
  41. scores[i]=pbGetMoveScore(attacker.moves[i],attacker,opponent,skill,baseDamageArray[i])
  42. # added by JZ to make them not target partner
  43. if attacker.moves[i].target==PBTargets::Partner
  44. scores[i]=-1
  45. end
  46. myChoices.push(i)
  47. else
  48. scores[i] = -1
  49. end
  50. end
  51.  
  52. # JZ note: ok so if the conquered mon ends up having 0 effective moves against its partner,
  53. # example: Arcanine with Surf + Water Gun next to partner Water Absorb mon
  54. # it'll just use a random move and this is so improbable I'm too lazy to account for it
  55.  
  56. # commented out by JZ
  57. #for i in 0...4
  58. # if pbCanChooseMove?(index,i,false)
  59. # #scores[i]=100 # by SH MARK
  60. # myChoices.push(i)
  61. # totalscore+=100
  62. # end
  63. #end
  64.  
  65. else
  66. skill=100 if wildbattle # added by JZ to make bosses harder
  67. skill=(pbGetOwner(attacker.index).skill || 0) rescue 100
  68. opponent=attacker.pbOppositeOpposing
  69. if @doublebattle && ((!opponent.isFainted? && !opponent.pbPartner.isFainted?) || !attacker.pbPartner.isFainted?)
  70. # Choose a target and move. Also care about partner.
  71. otheropp=opponent.pbPartner
  72. notopp=attacker.pbPartner ###
  73. scoresAndTargets=[]
  74. targets=[-1,-1,-1,-1]
  75. maxscore1=0
  76. maxscore2=0
  77. totalscore1=0
  78. totalscore2=0
  79. baseDamageArray=[]
  80. baseDamageArray2=[]
  81. baseDamageArray3=[] ###
  82. for j in 0...attacker.moves.length
  83. next if attacker.moves[j].id < 1
  84. # check attacker.moves[j].basedamage and if this is 0 instead check the status method
  85. dmgValue = pbRoughDamage(attacker.moves[j],attacker,opponent,skill,attacker.moves[j].basedamage)
  86. if attacker.moves[j].basedamage!=0
  87. if opponent.hp==0
  88. dmgPercent = 0
  89. else
  90. dmgPercent = (dmgValue*100)/(opponent.hp)
  91. dmgPercent = 110 if dmgPercent > 110
  92. end
  93. else
  94. dmgPercent = pbStatusDamage(attacker.moves[j])
  95. end
  96. baseDamageArray.push(dmgPercent)
  97. #~ File.open("AI_final_log.txt", "a") do |line|
  98. #~ line.puts "Vs Opp 1: Move " + PBMoves.getName(attacker.moves[j].id).to_s + " has rough damage " + dmgValue.to_s + " and damage % " +dmgPercent.to_s
  99. #~ end
  100. #Second opponent
  101. dmgValue2 = pbRoughDamage(attacker.moves[j],attacker,otheropp,skill,attacker.moves[j].basedamage)
  102. if attacker.moves[j].basedamage!=0
  103. if otheropp.hp==0
  104. dmgPercent2=0
  105. else
  106. dmgPercent2 = (dmgValue2*100)/(otheropp.hp)
  107. dmgPercent2 = 110 if dmgPercent2 > 110
  108. end
  109. else
  110. dmgPercent2 = pbStatusDamage(attacker.moves[j])
  111. end
  112. baseDamageArray2.push(dmgPercent2)
  113. #~ File.open("AI_final_log.txt", "a") do |line|
  114. #~ line.puts "Vs Opp 2: Move " + PBMoves.getName(attacker.moves[j].id).to_s + " has rough damage " + dmgValue2.to_s + " and damage % " +dmgPercent2.to_s
  115. #~ end
  116. #Partner ###
  117. dmgValue3 = pbRoughDamage(attacker.moves[j],attacker,notopp,skill,attacker.moves[j].basedamage)
  118. if attacker.moves[j].basedamage!=0
  119. if notopp.hp==0
  120. dmgPercent3=0
  121. else
  122. dmgPercent3 = (dmgValue3*100)/(notopp.hp)
  123. dmgPercent3 = 110 if dmgPercent3 > 110
  124. end
  125. else
  126. dmgPercent3 = pbStatusDamage(attacker.moves[j])
  127. end
  128. baseDamageArray3.push(dmgPercent3)
  129. #~ File.open("AI_final_log.txt", "a") do |line|
  130. #~ line.puts "Vs Partner: Move " + PBMoves.getName(attacker.moves[j].id).to_s + " has rough damage " + dmgValue3.to_s + " and damage % " +dmgPercent3.to_s
  131. #~ end
  132. end
  133. for i in 0...attacker.moves.length
  134. if pbCanChooseMove?(index,i,false)
  135. score1=pbGetMoveScore(attacker.moves[i],attacker,opponent,skill,baseDamageArray[i],baseDamageArray,i)
  136. score2=pbGetMoveScore(attacker.moves[i],attacker,otheropp,skill,baseDamageArray2[i],baseDamageArray2,i)
  137. totalscore = score1+score2
  138. if (attacker.moves[i].target&0x08)!=0 # Targets all users
  139. score1=totalscore # Consider both scores as it will hit BOTH targets
  140. score2=totalscore
  141. if attacker.pbPartner.isFainted? || attacker.pbPartner.hasWorkingAbility(:TELEPATHY) # No partner
  142. score1*=1.66
  143. score2*=1.66
  144. else
  145. # If this move can also target the partner, get the partner's
  146. # score too
  147. v=pbRoughDamage(attacker.moves[j],attacker,attacker.pbPartner,skill,attacker.moves[j].basedamage)
  148.  
  149. # TENTATIVE fix 0 division error by JZ
  150. #p=(v*100)/(attacker.pbPartner.hp)
  151. if attacker.pbPartner.hp==0
  152. p=1
  153. else
  154. p=(v*100)/(attacker.pbPartner.hp)
  155. end
  156. # end block
  157.  
  158. s=pbGetMoveScore(attacker.moves[i],attacker,attacker.pbPartner,skill,p)
  159. if (isConst?(attacker.moves[i],PBTypes,:FIRE) &&
  160. attacker.pbPartner.hasWorkingAbility(:FLASHFIRE)) ||
  161. # Wind Force #by low
  162. (isConst?(attacker.moves[i],PBTypes,:FLYING) &&
  163. attacker.pbPartner.hasWorkingAbility(:WINDFORCE)) ||
  164. (isConst?(attacker.moves[i],PBTypes,:FAIRY) &&
  165. attacker.pbPartner.hasWorkingAbility(:DISENCHANT)) ||
  166. (isConst?(attacker.moves[i],PBTypes,:WATER) &&
  167. (attacker.pbPartner.hasWorkingAbility(:WATERABSORB) ||
  168. attacker.pbPartner.hasWorkingAbility(:STORMDRAIN) ||
  169. attacker.pbPartner.hasWorkingAbility(:DRYSKIN))) ||
  170. (isConst?(attacker.moves[i],PBTypes,:GRASS) &&
  171. attacker.pbPartner.hasWorkingAbility(:SAPSIPPER)) ||
  172. (isConst?(attacker.moves[i],PBTypes,:ELECTRIC) &&
  173. (attacker.pbPartner.hasWorkingAbility(:VOLTABSORB) ||
  174. attacker.pbPartner.hasWorkingAbility(:LIGHTNINGROD) ||
  175. attacker.pbPartner.hasWorkingAbility(:MOTORDRIVE)))
  176. score1*=2.00
  177. score2*=2.00
  178. else
  179. if (attacker.pbPartner.hp.to_f)/attacker.pbPartner.totalhp>0.10 || ((attacker.pbPartner.pbSpeed<attacker.pbSpeed) ^ (@field.effects[PBEffects::TrickRoom]!=0))
  180. s = 100-s
  181. s=0 if s<0
  182. s/=100.0
  183. s *= 0.5 # multiplier to control how much to arbitrarily care about hitting partner; lower cares more
  184. if (attacker.pbPartner.pbSpeed<attacker.pbSpeed) ^ (@field.effects[PBEffects::TrickRoom]!=0)
  185. s *= 0.5 # care more if we're faster and would knock it out before it attacks
  186. end
  187. score1*=s
  188. score2*=s
  189. end
  190. end
  191. end
  192. score1=score1.to_i
  193. score2=score2.to_i
  194. PBDebug.log(sprintf("%s: Final Score after Multi-Target Adjustment: %d",PBMoves.getName(attacker.moves[i].id),score1))
  195. PBDebug.log(sprintf(""))
  196. end
  197. if attacker.moves[i].target==PBTargets::AllOpposing # Consider both scores as it will hit BOTH targets
  198. totalscore = score1+score2
  199. score1=totalscore
  200. score2=totalscore
  201. PBDebug.log(sprintf("%s: Final Score after Multi-Target Adjustment: %d",PBMoves.getName(attacker.moves[i].id),score1))
  202. PBDebug.log(sprintf(""))
  203. end
  204. myChoices.push(i)
  205. scoresAndTargets.push([i*2,i,score1,opponent.index])
  206. scoresAndTargets.push([i*2+1,i,score2,otheropp.index])
  207. else
  208. scoresAndTargets.push([i*2,i,-1,opponent.index])
  209. scoresAndTargets.push([i*2+1,i,-1,otheropp.index])
  210. end
  211. end
  212. for i in 0...attacker.moves.length ### This whole bit
  213. if pbCanChooseMove?(index,i,false)
  214. if attacker.moves[i].function == 0xDF || attacker.moves[i].function == 0x63 || attacker.moves[i].function == 0x67 ||
  215. attacker.moves[i].function == 0xA0 || attacker.moves[i].function == 0xC1 || attacker.moves[i].function == 0x141 ||
  216. attacker.moves[i].function == 0x40 || attacker.moves[i].function == 0x41 || attacker.moves[i].function == 0x66
  217. # Heal Pulse, Simple Beam, Skill Swap, Frost Breath, Beat Up, Topsy-Turvy, Psych Up, Swagger, Flatter, Entrainment
  218. partnerscore=pbGetMoveScore(attacker.moves[i],attacker,notopp,skill,baseDamageArray3[i],baseDamageArray3,i)
  219. PBDebug.log(sprintf("%s: Score for using on partner: %d",PBMoves.getName(attacker.moves[i].id),partnerscore))
  220. PBDebug.log(sprintf(""))
  221. scoresAndTargets.push([i*10,i,partnerscore,notopp.index])
  222. end
  223. end
  224. end
  225. scoresAndTargets.sort!{|a,b|
  226. if a[2]==b[2] # if scores are equal
  227. a[0]<=>b[0] # sort by index (for stable comparison)
  228. else
  229. b[2]<=>a[2]
  230. end
  231. }
  232. for i in 0...scoresAndTargets.length
  233. idx=scoresAndTargets[i][1]
  234. thisScore=scoresAndTargets[i][2]
  235. if thisScore>0 || thisScore==-1
  236. if scores[idx]==0 || ((scores[idx]==thisScore && pbAIRandom(10)<5) ||
  237. (scores[idx] < thisScore))
  238. # (scores[idx]!=thisScore && pbAIRandom(10)<3))
  239. scores[idx]=thisScore
  240. targets[idx]=scoresAndTargets[i][3]
  241. end
  242. end
  243. end
  244. else
  245. # Choose a move. There is only 1 opposing Pokémon.
  246. if @doublebattle && opponent.isFainted?
  247. opponent=opponent.pbPartner
  248. end
  249. baseDamageArray=[]
  250. baseDamageArrayAdj=[]
  251. for j in 0...attacker.moves.length
  252. next if attacker.moves[j].id < 1
  253. # check attacker.moves[j].basedamage and if this is 0 instead check the status method
  254. dmgValue = pbRoughDamage(attacker.moves[j],attacker,opponent,skill,attacker.moves[j].basedamage)
  255. if attacker.moves[j].basedamage!=0
  256.  
  257. # TENTATIVE fix 0 division error by JZ?
  258. #dmgPercent = (dmgValue*100)/(opponent.hp)
  259. if opponent.hp==0
  260. dmgPercent=1
  261. else
  262. dmgPercent = (dmgValue*100)/(opponent.hp)
  263. end
  264. # end block
  265.  
  266. dmgPercent = 110 if dmgPercent > 110
  267. if attacker.moves[j].function == 0x115 || attacker.moves[j].function == 0xC3 ||
  268. attacker.moves[j].function == 0xC4 || attacker.moves[j].function == 0xC5 ||
  269. attacker.moves[j].function == 0xC6 || attacker.moves[j].function == 0xC7 ||
  270. attacker.moves[j].function == 0xC8
  271. dmgPercentAdj = (dmgPercent * 0.5)
  272. else
  273. dmgPercentAdj = dmgPercent
  274. end
  275. else
  276. dmgPercent = pbStatusDamage(attacker.moves[j])
  277. dmgPercentAdj = dmgPercent
  278. end
  279. #~ File.open("AI_final_log.txt", "a") do |line|
  280. #~ line.puts "Vs Only Opponent: Move " + PBMoves.getName(attacker.moves[j].id).to_s + " has rough damage " + dmgValue.to_s + " and damage % " +dmgPercent.to_s
  281. #~ end
  282. baseDamageArray.push(dmgPercent)
  283. baseDamageArrayAdj.push(dmgPercentAdj)
  284. end
  285. for i in 0...attacker.moves.length
  286. if pbCanChooseMove?(index,i,false)
  287. scores[i]=pbGetMoveScore(attacker.moves[i],attacker,opponent,skill,baseDamageArray[i],baseDamageArrayAdj,i)
  288. myChoices.push(i)
  289. else
  290. scores[i] = -1
  291. end
  292. end
  293. end
  294. end
  295. maxscore=0
  296. for i in 0...attacker.moves.length
  297. scores[i]=0 if scores[i]<0
  298. maxscore=scores[i] if scores[i]>maxscore
  299. totalscore+=scores[i]
  300. end
  301. #~ for i in 0...attacker.moves.length
  302. #~ File.open("AI_final_log.txt", "a") do |line|
  303. #~ line.puts "Move " + PBMoves.getName(attacker.moves[i].id).to_s + " has final score " + scores[i].to_s
  304. #~ end
  305. #~ end
  306. #~ File.open("AI_final_log.txt", "a") do |line|
  307. #~ line.puts "============================================"
  308. #~ end
  309.  
  310. # added for master debug by JZ
  311. # this takes all the moves and finds their scores, seeing if any of them break
  312. # does not however check for validity of scores
  313. # also only tests said moves a given user/opponent pair of abilities and items
  314. # a comprehensive test would be infeasible in terms of time so only one test was run on one given combo
  315. #for i in 1..300
  316. #for i in 301..621
  317. #~ for i in 1..687
  318. #~ for i in 900..PBMoves.maxValue
  319. #~ mirrored = PBMove.new(i)
  320. #~ mirrmove = PokeBattle_Move.pbFromPBMove(self,mirrored)
  321. #~ next if mirrored==nil
  322. #~ dmgValue = pbRoughDamage(mirrmove,attacker,opponent,skill,mirrmove.basedamage)
  323. #~ if mirrmove.basedamage!=0
  324. #~ dmgPercent = (dmgValue*100)/(opponent.hp)
  325. #~ dmgPercent = 110 if dmgPercent > 110
  326. #~ else
  327. #~ dmgPercent=pbStatusDamage(mirrmove)
  328. #~ end
  329. #~ File.open("AI_master_log.txt", "a") do |line|
  330. #~ line.puts "Move " + i.to_s + " aka " + PBMoves.getName(mirrored.id).to_s + " has rough damage " + dmgValue.to_s + " and damage % " + dmgPercent.to_s
  331. #~ end
  332. #~ score=pbGetMoveScore(mirrmove,attacker,opponent,skill,dmgPercent)
  333. #~ File.open("AI_master_log.txt", "a") do |line|
  334. #~ line.puts "Move " + i.to_s + " aka " + PBMoves.getName(mirrored.id).to_s + " has final score " + score.to_s
  335. #~ end
  336. #~ end
  337. # end master debug
  338.  
  339. # Minmax choices depending on AI
  340. #if !wildbattle && skill>=PBTrainerAI.mediumSkill (commented out by JZ)
  341. if true
  342. threshold=(skill>=PBTrainerAI.bestSkill) ? 1.5 : (skill>=PBTrainerAI.highSkill) ? 2 : 3
  343. newscore=(skill>=PBTrainerAI.bestSkill) ? 5 : (skill>=PBTrainerAI.highSkill) ? 10 : 15
  344. for i in 0...scores.length
  345. if scores[i]>newscore && scores[i]*threshold<maxscore
  346. totalscore-=(scores[i]-newscore)
  347. scores[i]=newscore
  348. end
  349. end
  350. maxscore=0
  351. for i in 0...attacker.moves.length
  352. maxscore=scores[i] if scores[i] && scores[i]>maxscore
  353. end
  354. end
  355. if true #!wildbattle && maxscore>100 (commented out by JZ)
  356. stdev=pbStdDev(scores)
  357. preferredMoves=[]
  358. for i in 0...attacker.moves.length
  359. if attacker.moves[i].id!=0 && (scores[i]>=(maxscore*0.8)) && pbCanChooseMove?(index,i,false)
  360. preferredMoves.push(i)
  361. preferredMoves.push(i) if scores[i]==maxscore # Doubly prefer the best move
  362. end
  363. end
  364. if preferredMoves.length>0
  365. i=preferredMoves[pbAIRandom(preferredMoves.length)]
  366. PBDebug.log("[AI] Prefer #{PBMoves.getName(attacker.moves[i].id)}")
  367. pbRegisterMove(index,i,false)
  368. target=targets[i] if targets
  369. if @doublebattle && target>=0
  370. pbRegisterTarget(index,target)
  371. end
  372. return
  373. end
  374. end
  375. #if !wildbattle && attacker.turncount (commented out by JZ)
  376. if attacker.turncount
  377. badmoves=false
  378. if ((maxscore<=20 && attacker.turncount>2) ||
  379. (maxscore<=30 && attacker.turncount>5)) && pbAIRandom(10)<8
  380. badmoves=true
  381. end
  382. if totalscore<100 && attacker.turncount>1
  383. badmoves=true
  384. movecount=0
  385. for i in 0...attacker.moves.length
  386. if attacker.moves[i].id!=0
  387. if scores[i]>0 && attacker.moves[i].basedamage>0
  388. badmoves=false
  389. end
  390. movecount+=1
  391. end
  392. end
  393. badmoves=badmoves && pbAIRandom(10)!=0
  394. end
  395. if badmoves
  396. # Attacker has terrible moves, try switching instead
  397. if pbEnemyShouldWithdrawEx?(index,true)
  398. if $INTERNAL
  399. PBDebug.log("[AI] Switching due to terrible moves")
  400. PBDebug.log([index,@choices[index][0],@choices[index][1],
  401. pbCanChooseNonActive?(index),
  402. @battlers[index].pbNonActivePokemonCount()].inspect)
  403. end
  404. return
  405. end
  406. end
  407. end
  408. if maxscore<=0
  409. # If all scores are 0 or less, choose a move at random
  410. if myChoices.length>0
  411. pbRegisterMove(index,myChoices[pbAIRandom(myChoices.length)],false)
  412. else
  413. pbAutoChooseMove(index)
  414. end
  415. else
  416. randnum=pbAIRandom(totalscore)
  417. cumtotal=0
  418. for i in 0...attacker.moves.length
  419. if scores[i]>0
  420. cumtotal+=scores[i]
  421. if randnum<cumtotal
  422. pbRegisterMove(index,i,false)
  423. target=targets[i] if targets
  424. break
  425. end
  426. end
  427. end
  428. end
  429. PBDebug.log("[AI] Will use #{@choices[index][2].name}") if @choices[index][2]
  430. if @doublebattle && target>=0
  431. pbRegisterTarget(index,target)
  432. end
  433. end
  434.  
  435. ################################################################################
  436. # Decide whether the opponent should Mega Evolve their Pokémon.
  437. ################################################################################
  438. def pbEnemyShouldMegaEvolve?(index)
  439. # Simple "always should if possible"
  440. return pbCanMegaEvolve?(index)
  441. end
  442.  
  443. ################################################################################
  444. # Decide whether the opponent should use an item on the Pokémon.
  445. ################################################################################
  446. def pbEnemyShouldUseItem?(index)
  447. return false #by low
  448. item=pbEnemyItemToUse(index)
  449. if item>0
  450. pbRegisterItem(index,item,nil)
  451. return true
  452. end
  453. return false
  454. end
  455.  
  456. def pbEnemyItemAlreadyUsed?(index,item,items)
  457. if @choices[1][0]==3 && @choices[1][1]==item
  458. qty=0
  459. for i in items
  460. qty+=1 if i==item
  461. end
  462. return true if qty<=1
  463. end
  464. return false
  465. end
  466.  
  467. def pbEnemyItemToUse(index)
  468. return 0 if !@internalbattle
  469. items=pbGetOwnerItems(index)
  470. return 0 if !items
  471. battler=@battlers[index]
  472. return 0 if battler.fainted? ||
  473. battler.effects[PBEffects::Embargo]>0
  474. hashpitem=false
  475. for i in items
  476. next if pbEnemyItemAlreadyUsed?(index,i,items)
  477. if isConst?(i,PBItems,:POTION) ||
  478. isConst?(i,PBItems,:SUPERPOTION) ||
  479. isConst?(i,PBItems,:HYPERPOTION) ||
  480. isConst?(i,PBItems,:MAXPOTION) ||
  481. isConst?(i,PBItems,:FULLRESTORE)
  482. hashpitem=true
  483. end
  484. end
  485. for i in items
  486. next if pbEnemyItemAlreadyUsed?(index,i,items)
  487. if isConst?(i,PBItems,:FULLRESTORE)
  488. return i if battler.hp<=battler.totalhp/4
  489. return i if battler.hp<=battler.totalhp/2 && pbAIRandom(10)<3
  490. return i if battler.hp<=battler.totalhp*2/3 &&
  491. (battler.status>0 || battler.effects[PBEffects::Confusion]>0) &&
  492. pbAIRandom(10)<3
  493. elsif isConst?(i,PBItems,:POTION) ||
  494. isConst?(i,PBItems,:SUPERPOTION) ||
  495. isConst?(i,PBItems,:HYPERPOTION) ||
  496. isConst?(i,PBItems,:MAXPOTION)
  497. return i if battler.hp<=battler.totalhp/4
  498. return i if battler.hp<=battler.totalhp/2 && pbAIRandom(10)<3
  499. elsif isConst?(i,PBItems,:FULLHEAL)
  500. return i if !hashpitem &&
  501. (battler.status>0 || battler.effects[PBEffects::Confusion]>0)
  502. elsif isConst?(i,PBItems,:XATTACK) ||
  503. isConst?(i,PBItems,:XDEFEND) ||
  504. isConst?(i,PBItems,:XDEFENSE) ||
  505. isConst?(i,PBItems,:XSPEED) ||
  506. isConst?(i,PBItems,:XSPECIAL) ||
  507. isConst?(i,PBItems,:XSPATK) ||
  508. isConst?(i,PBItems,:XSPDEF) ||
  509. isConst?(i,PBItems,:XACCURACY)
  510. stat=0
  511. stat=PBStats::ATTACK if isConst?(i,PBItems,:XATTACK)
  512. stat=PBStats::DEFENSE if isConst?(i,PBItems,:XDEFEND)
  513. stat=PBStats::DEFENSE if isConst?(i,PBItems,:XDEFENSE)
  514. stat=PBStats::SPEED if isConst?(i,PBItems,:XSPEED)
  515. stat=PBStats::SPATK if isConst?(i,PBItems,:XSPECIAL)
  516. stat=PBStats::SPATK if isConst?(i,PBItems,:XSPATK)
  517. stat=PBStats::SPDEF if isConst?(i,PBItems,:XSPDEF)
  518. stat=PBStats::ACCURACY if isConst?(i,PBItems,:XACCURACY)
  519. if stat>0 && !battler.pbTooHigh?(stat)
  520. return i if pbAIRandom(10)<3-battler.stages[stat]
  521. end
  522. end
  523. end
  524. return 0
  525. end
  526.  
  527. ################################################################################
  528. # Decide whether the opponent should switch Pokémon.
  529. ################################################################################
  530. def pbEnemyShouldWithdraw?(index)
  531. # if $INTERNAL && !pbIsOpposing?(index)
  532. # return pbEnemyShouldWithdrawOld?(index)
  533. # end
  534. return pbEnemyShouldWithdrawEx?(index,false)
  535. end
  536.  
  537. def pbEnemyShouldWithdrawEx?(index,alwaysSwitch)
  538. return false if !@opponent
  539. shouldswitch=alwaysSwitch
  540. typecheck=false
  541. batonpass=-1
  542. movetype=-1
  543. skill=pbGetOwner(index).skill || 0
  544. if @opponent && !shouldswitch && @battlers[index].turncount>0
  545. if skill>=PBTrainerAI.highSkill
  546. opponent=@battlers[index].pbOppositeOpposing
  547. opponent=opponent.pbPartner if opponent.fainted?
  548. if !opponent.fainted? && opponent.lastMoveUsed>0 &&
  549. (opponent.level-@battlers[index].level).abs<=6
  550. move=PBMoveData.new(opponent.lastMoveUsed)
  551. typemod=pbTypeModifier(move.type,@battlers[index],@battlers[index])
  552. movetype=move.type
  553. if move.basedamage>70 && typemod>8
  554. shouldswitch=(pbAIRandom(100)<30)
  555. elsif move.basedamage>50 && typemod>8
  556. shouldswitch=(pbAIRandom(100)<20)
  557. end
  558. end
  559. end
  560. end
  561. if !pbCanChooseMove?(index,0,false) &&
  562. !pbCanChooseMove?(index,1,false) &&
  563. !pbCanChooseMove?(index,2,false) &&
  564. !pbCanChooseMove?(index,3,false) &&
  565. @battlers[index].turncount &&
  566. @battlers[index].turncount>5
  567. shouldswitch=true
  568. end
  569. if skill>=PBTrainerAI.highSkill && @battlers[index].effects[PBEffects::PerishSong]!=1
  570. for i in 0...4
  571. move=@battlers[index].moves[i]
  572. if move.id!=0 && pbCanChooseMove?(index,i,false) &&
  573. move.function==0xED # Baton Pass
  574. batonpass=i
  575. break
  576. end
  577. end
  578. end
  579. if skill>=PBTrainerAI.highSkill
  580. if @battlers[index].status==PBStatuses::POISON &&
  581. @battlers[index].statusCount>0
  582. toxicHP=(@battlers[index].totalhp/16)
  583. nextToxicHP=toxicHP*(@battlers[index].effects[PBEffects::Toxic]+1)
  584. if nextToxicHP>=@battlers[index].hp &&
  585. toxicHP<@battlers[index].hp && pbAIRandom(100)<80
  586. shouldswitch=true
  587. end
  588. end
  589. end
  590. if skill>=PBTrainerAI.mediumSkill
  591. if @battlers[index].effects[PBEffects::Encore]>0
  592. scoreSum=0
  593. scoreCount=0
  594. attacker=@battlers[index]
  595. encoreIndex=@battlers[index].effects[PBEffects::EncoreIndex]
  596. if !attacker.pbOpposing1.fainted?
  597. scoreSum+=pbGetMoveScore(attacker.moves[encoreIndex],
  598. attacker,attacker.pbOpposing1,skill)
  599. scoreCount+=1
  600. end
  601. if !attacker.pbOpposing2.fainted?
  602. scoreSum+=pbGetMoveScore(attacker.moves[encoreIndex],
  603. attacker,attacker.pbOpposing2,skill)
  604. scoreCount+=1
  605. end
  606. if scoreCount>0 && scoreSum/scoreCount<=20 && pbAIRandom(10)<8
  607. shouldswitch=true
  608. end
  609. end
  610. end
  611. if skill>=PBTrainerAI.highSkill
  612. if !@doublebattle && !@battlers[index].pbOppositeOpposing.fainted?
  613. opp=@battlers[index].pbOppositeOpposing
  614. if (opp.effects[PBEffects::HyperBeam]>0 ||
  615. (opp.hasWorkingAbility(:TRUANT) &&
  616. opp.effects[PBEffects::Truant])) && pbAIRandom(100)<80
  617. shouldswitch=false
  618. end
  619. end
  620. end
  621. if @rules["suddendeath"]
  622. if @battlers[index].hp<=(@battlers[index].totalhp/4) && pbAIRandom(10)<3 &&
  623. @battlers[index].turncount>0
  624. shouldswitch=true
  625. elsif @battlers[index].hp<=(@battlers[index].totalhp/2) && pbAIRandom(10)<8 &&
  626. @battlers[index].turncount>0
  627. shouldswitch=true
  628. end
  629. end
  630. if @battlers[index].effects[PBEffects::PerishSong]==1
  631. shouldswitch=true
  632. end
  633. if shouldswitch
  634. list=[]
  635. party=pbParty(index)
  636. for i in 0...party.length
  637. if pbCanSwitch?(index,i,false)
  638. # If perish count is 1, it may be worth it to switch
  639. # even with Spikes, since Perish Song's effect will end
  640. if @battlers[index].effects[PBEffects::PerishSong]!=1
  641. # Will contain effects that recommend against switching
  642. spikes=@battlers[index].pbOwnSide.effects[PBEffects::Spikes]
  643. if (spikes==1 && party[i].hp<=(party[i].totalhp/8)) ||
  644. (spikes==2 && party[i].hp<=(party[i].totalhp/6)) ||
  645. (spikes==3 && party[i].hp<=(party[i].totalhp/4))
  646. if !party[i].hasType?(:FLYING) &&
  647. !party[i].hasWorkingAbility(:LEVITATE)
  648. # Don't switch to this if too little HP
  649. next
  650. end
  651. end
  652. end
  653. if movetype>=0 && pbTypeModifier(movetype,@battlers[index],@battlers[index])==0
  654. weight=65
  655. if pbTypeModifier2(party[i],@battlers[index].pbOppositeOpposing)>8
  656. # Greater weight if new Pokemon's type is effective against opponent
  657. weight=85
  658. end
  659. if pbAIRandom(100)<weight
  660. list.unshift(i) # put this Pokemon first
  661. end
  662. elsif movetype>=0 && pbTypeModifier(movetype,@battlers[index],@battlers[index])<8
  663. weight=40
  664. if pbTypeModifier2(party[i],@battlers[index].pbOppositeOpposing)>8
  665. # Greater weight if new Pokemon's type is effective against opponent
  666. weight=60
  667. end
  668. if pbAIRandom(100)<weight
  669. list.unshift(i) # put this Pokemon first
  670. end
  671. else
  672. list.push(i) # put this Pokemon last
  673. end
  674. end
  675. end
  676. if list.length>0
  677. if batonpass!=-1
  678. if !pbRegisterMove(index,batonpass,false)
  679. return pbRegisterSwitch(index,list[0])
  680. end
  681. return true
  682. else
  683. return pbRegisterSwitch(index,list[0])
  684. end
  685. end
  686. end
  687. return false
  688. end
  689.  
  690. def pbDefaultChooseNewEnemy(index,party)
  691. enemies=[]
  692. for i in 0..party.length-1
  693. if pbCanSwitchLax?(index,i,false)
  694. enemies.push(i)
  695. end
  696. end
  697. if enemies.length>0
  698. return pbChooseBestNewEnemy(index,party,enemies)
  699. end
  700. return -1
  701. end
  702.  
  703. def pbChooseBestNewEnemy(index, party, enemies)
  704. return -1 if !enemies || enemies.length == 0
  705. $PokemonTemp = PokemonTemp.new if !$PokemonTemp
  706. o1 = @battlers[index].pbOpposing1
  707. o2 = @battlers[index].pbOpposing2
  708. o1 = nil if o1 && o1.fainted?
  709. o2 = nil if o2 && o2.fainted?
  710. best = -1
  711. bestSum = 0
  712. for e in enemies
  713. pkmn = party[e]
  714. sum = 0
  715. for move in pkmn.moves
  716. next if move.id == 0
  717. md = PBMoveData.new(move.id)
  718. next if md.basedamage == 0
  719. if o1
  720. sum += PBTypes.getCombinedEffectiveness(md.type, o1.type1, o1.type2)
  721. end
  722. if o2
  723. sum += PBTypes.getCombinedEffectiveness(md.type, o2.type1, o2.type2)
  724. end
  725. end
  726. if best == -1 || sum > bestSum
  727. best = e
  728. bestSum = sum
  729. end
  730. end
  731. return best
  732. end
  733.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement