Advertisement
Guest User

BG Reroller (Modified)

a guest
Mar 24th, 2013
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 42.31 KB | None | 0 0
  1. ; Perfect Roll v2 (written by idle in its leisure time)
  2. ; Roll abilities for Baldur's Gate character generation
  3.  
  4. ; v1.0.0 - initial release
  5. ; v1.0.1 - removed increment of max_iter (useless feature)
  6. ; v1.0.2 - replaced for-loop delay with Sleep()
  7. ; v1.0.3 - added support for "Baldur's Gate II - Shadows of Amn"
  8.  
  9. ; name of ini file
  10. global const $ini = "proll2.ini"
  11.  
  12. ; detect missing ini values
  13. global const $defaultIniValue = -100000000
  14.  
  15. Opt ("MustDeclareVars", 1)
  16. Opt ("MouseCoordMode", 0)
  17. Opt ("PixelCoordMode", 0)
  18. Opt ("GUICoordMode", 2)
  19. Opt ("MouseClickDelay", ReadIniValue ("Common", "mouse_click_delay", 20, 5, 500))
  20. Opt ("MouseClickDownDelay", ReadIniValue ("Common", "mouse_click_down", 10, 5, 500))
  21.  
  22. ; title of baldur's gate window
  23. global const $bgTitle = ReadIniString ("Common", "window_title", "Tales of the Sword Coast")
  24.  
  25. ; title of trash dialog to catch trash keyboard events
  26. global const $trashTitle = "BG trash can"
  27.  
  28. ; primary mouse button ("left", "right" or something else)
  29. global const $primaryMouseButton = ReadIniString ("Common", "primary_mouse_button", "left")
  30.  
  31. ; number of clicks, when it is impossible to test result of clicking
  32. global $numClicks = 30
  33.  
  34. ; delay after mouse click (to wait for update after reroll or '+'/'-')
  35. global $zeroUpdateDelay = 10
  36. global $firstUpdateDelay = 1
  37. global $secondUpdateDelay = 10
  38. global $tuneEvery = 1
  39.  
  40. global $mouseSpeed = 10
  41.  
  42. ; how often to update statistics (number of iterations)
  43. global $updateEvery = 1
  44.  
  45. ; learning strength values (fill cache)
  46. global $learnStrength = 0
  47.  
  48. ; limit allowed strength by this value
  49. global $strengthLimit = 0
  50.  
  51. ; limit allowed badness by this value
  52. global $badnessLimit = 100
  53.  
  54. ; number of rolls in a row
  55. global $rollsNum = 0
  56.  
  57. ; delay between different batches of rolls
  58. global $restTime = 0
  59.  
  60. ; maximum ability index
  61. global const $maxAbility = 5
  62.  
  63. ; index of strength ability
  64. global const $strIndex = 0
  65.  
  66. ; coordinates of ability increment buttons
  67. global $incButton[$maxAbility+1][2]
  68.  
  69. ; coordinates of ability decrement buttons
  70. global $decButton[$maxAbility+1][2]
  71.  
  72. ; coordinates of "store", "recall", "reroll" buttons
  73. global $storeButton[2]
  74. global $recallButton[2]
  75. global $rerollButton[2]
  76.  
  77. ; coordinates of ability value
  78. global $abilityRect[$maxAbility+1][4]
  79.  
  80. ; coordinates of description text
  81. global $textRect[4]
  82.  
  83. ; coordinates of reserve points value
  84. global $reserveRect[4]
  85.  
  86. ; coordinate of right edge - safe place to play with mouse
  87. global $rightEdge
  88.  
  89. ; priorities of abilities when incrementing
  90. global const $incAbilityPriority[$maxAbility+1] = [0, 1, 2, 4, 3, 5]
  91.  
  92. ; hash of "can not inc/dec" images
  93. global $canNotInc = -1;
  94. global $canNotDec = -1;
  95.  
  96. ; hash of "0" reserve points
  97. global $zeroReserve = -1;
  98.  
  99. ; hashes of all ability values for all abilities
  100. global const $maxAbilityValue = 30
  101. global $abilityChecksum[$maxAbility+1][$maxAbilityValue+1]
  102. global $abilityChecksumMax[$maxAbility+1] = [-1, -1, -1, -1, -1, -1]
  103.  
  104. ; maximum strength is complex value (18/xx)
  105. global $strIsComplex = 0
  106.  
  107. ; control IDs
  108. global $ctrlMinBadnessLabel
  109. global $ctrlMinBadnessValue
  110. global $ctrlMaxStrengthLabel
  111. global $ctrlMaxStrengthValue
  112. global $ctrlAvgBadnessLabel
  113. global $ctrlAvgBadnessValue
  114. global $ctrlCurBadnessLabel
  115. global $ctrlCurBadnessValue
  116. global $ctrlItersNumLabel
  117. global $ctrlItersNumValue
  118. global $ctrlIterTimeLabel
  119. global $ctrlIterTimeValue
  120. global $ctrlDelaysNumLabel
  121. global $ctrlDelaysNumValue
  122. global $ctrlProfilerLabel
  123. global $ctrlProfilerValue
  124. global $ctrlHelpValue
  125.  
  126. ; current results
  127. global $minBadness = 1000000
  128. global $maxStrength = -1000000
  129. global $totalBadness = 0
  130. global $curBadness = 1000000
  131. global $curStrength = -1000000
  132. global $curAbility[$maxAbility+1]
  133. global $otherStrength = ""
  134. global $maxIter = 0
  135. global $maxTime = 0
  136. global $curIter = 0
  137. global $curTime = 0
  138. global $totalIter = 0
  139. global $totalTime = 0
  140. global $bestTime = "never"
  141. global $begTime
  142. global $loopBegTime
  143.  
  144. global $firstDelaysNum = 0
  145. global $secondDelaysNum = 0
  146.  
  147. HotKeySet ("{PAUSE}")
  148. HotKeySet ("{PAUSE}", "PauseScript")
  149.  
  150. global $paused = 0
  151. global $recursionDepth = 0
  152.  
  153. global $goodWin = 1
  154. if ((@OSType = "WIN32_NT") and (@OSVersion <> "WIN_NT4")) then
  155. $goodWin = 1
  156. else
  157. $goodWin = 0
  158. endif
  159.  
  160. global $initialized = 0
  161.  
  162. ; pause script execution
  163. func PauseScript ()
  164. if ($paused) then
  165. return 0
  166. endif
  167.  
  168. ; avoid nested pause
  169. $paused = 1
  170.  
  171. ; ask user what to do
  172. local $res
  173. if ($goodWin) then
  174. $res = ShowMsgBox (512+32+6, "Script is paused", "Continue running, cancel script or restart reroll process?")
  175. else
  176. $res = ShowMsgBox (512+32+2, "Script is paused", "Continue running (ignore), cancel script (abort) or restart reroll process (retry)?")
  177. endif
  178.  
  179. if (($res = 2) or ($res = 3)) then
  180. ; cancel or abort
  181. Exit (10)
  182. elseif (($res = 10) or ($res = 4)) then
  183. ; try again or retry
  184. if ($recursionDepth > 30) then
  185. ShowMsgBox (0, "Warning", "Can not restart due to recursion limit")
  186. else
  187. $recursionDepth = $recursionDepth + 1
  188. ; restore best combination
  189. Recall ()
  190.  
  191. ; recurse deeper
  192. $paused = 0
  193. Init ()
  194. Main ()
  195. endif
  196. else
  197. ; continue or ignore (11 or 5)
  198. ReadIniFile ()
  199. endif
  200.  
  201. $paused = 0
  202. endfunc
  203.  
  204. global $aborted = 0
  205.  
  206. func OnAutoItExit ()
  207. if ((@ExitMethod = 1) and not ($aborted)) then
  208. ; exiting by Exit
  209. Recall ()
  210. endif
  211. endfunc
  212.  
  213. ; abort execution without cleanup
  214. func Abort (const $ret)
  215. $aborted = 1
  216. Exit ($ret)
  217. endfunc
  218.  
  219. ; fill coordinates
  220. func FillCoordinates ()
  221. local $delta
  222.  
  223. ; set default coordinates for "Baldur's Gate"
  224. $incButton[0][0] = 434
  225. $incButton[0][1] = 142
  226. $decButton[0][0] = 456
  227. $decButton[0][1] = 142
  228. $abilityRect[0][0] = 380
  229. $abilityRect[0][1] = 135
  230. $abilityRect[0][2] = 410
  231. $abilityRect[0][3] = 148
  232.  
  233. $delta = 31
  234. local $i
  235. for $i = 1 to $maxAbility
  236. $incButton[$i][0] = $incButton[$i-1][0]
  237. $incButton[$i][1] = $incButton[$i-1][1] + $delta
  238. $decButton[$i][0] = $decButton[$i-1][0]
  239. $decButton[$i][1] = $decButton[$i-1][1] + $delta
  240. $abilityRect[$i][0] = $abilityRect[$i-1][0]
  241. $abilityRect[$i][1] = $abilityRect[$i-1][1] + $delta
  242. $abilityRect[$i][2] = $abilityRect[$i-1][2]
  243. $abilityRect[$i][3] = $abilityRect[$i-1][3] + $delta
  244. next
  245.  
  246. $storeButton[0] = 230
  247. $storeButton[1] = 332
  248. $recallButton[0] = 324
  249. $recallButton[1] = 332
  250. $rerollButton[0] = 418
  251. $rerollButton[1] = 332
  252.  
  253. $reserveRect[0] = 431
  254. $reserveRect[1] = 107
  255. $reserveRect[2] = 465
  256. $reserveRect[3] = 122
  257.  
  258. $textRect[0] = 180
  259. $textRect[1] = 356
  260. $textRect[2] = 400
  261. $textRect[3] = 362
  262.  
  263. $rightEdge = 490
  264.  
  265. ; set coordinates for different versions of the game
  266. switch ($bgTitle)
  267.  
  268. case "Baldur's Gate"
  269. ; coordinates for "Baldur's Gate" were already set
  270.  
  271. case "Baldur's Gate II - Shadows of Amn"
  272. ; override coordinates for "Baldur's Gate II - Shadows of Amn"
  273. $incButton[0][0] = 291
  274. $incButton[0][1] = 235
  275. $decButton[0][0] = 312
  276. $decButton[0][1] = 235
  277. $abilityRect[0][0] = 222
  278. $abilityRect[0][1] = 226
  279. $abilityRect[0][2] = 262
  280. $abilityRect[0][3] = 245
  281.  
  282. $delta = 31
  283. local $i
  284. for $i = 1 to $maxAbility
  285. $incButton[$i][0] = $incButton[$i-1][0]
  286. $incButton[$i][1] = $incButton[$i-1][1] + 31 + (1 - Mod ($i, 2)) * 3
  287. $decButton[$i][0] = $decButton[$i-1][0]
  288. $decButton[$i][1] = $decButton[$i-1][1] + 31 + (1 - Mod ($i, 2)) * 3
  289. $abilityRect[$i][0] = $abilityRect[$i-1][0]
  290. $abilityRect[$i][1] = $abilityRect[$i-1][1] + 31 + (1 - Mod ($i, 2)) * 3
  291. $abilityRect[$i][2] = $abilityRect[$i-1][2]
  292. $abilityRect[$i][3] = $abilityRect[$i-1][3] + 31 + (1 - Mod ($i, 2)) * 3
  293. next
  294.  
  295. $storeButton[0] = 82
  296. $storeButton[1] = 435
  297. $recallButton[0] = 186
  298. $recallButton[1] = 435
  299. $rerollButton[0] = 284
  300. $rerollButton[1] = 435
  301.  
  302. $reserveRect[0] = 276
  303. $reserveRect[1] = 177
  304. $reserveRect[2] = 313
  305. $reserveRect[3] = 194
  306.  
  307. $textRect[0] = 371
  308. $textRect[1] = 180
  309. $textRect[2] = 590
  310. $textRect[3] = 200
  311.  
  312. $rightEdge = 345
  313.  
  314. case else
  315. endswitch
  316. endfunc
  317.  
  318. ; profiling support
  319. global $useProfiler = 0
  320. global const $profilerPointsMax = 100
  321. global $profilerPoint[$profilerPointsMax+1]
  322. global $profilerText[$profilerPointsMax+1]
  323. global $profilerPointNext = 0
  324. global $profilerTimer
  325.  
  326. func ProfilerStart ()
  327. if ($useProfiler) then
  328. $profilerTimer = TimerInit ()
  329. $profilerPointNext = 0
  330. endif
  331. endfunc
  332.  
  333. func ProfilerAddPoint (const $text)
  334. if ($useProfiler and ($profilerPointNext < $profilerPointsMax)) then
  335. $profilerPoint[$profilerPointNext] = TimerDiff ($profilerTimer)
  336. $profilerText[$profilerPointNext] = $text
  337. $profilerPointNext = $profilerPointNext + 1
  338. endif
  339. endfunc
  340.  
  341. func ProfilerGetPoints ()
  342. return $profilerPointNext
  343. endfunc
  344.  
  345. func ProfilerGetPoint (const $index)
  346. return $profilerPoint[$index]
  347. endfunc
  348.  
  349. func ProfilerGetDiff (const $index)
  350. if ($index > 0) then
  351. return ($profilerPoint[$index] - $profilerPoint[$index-1])
  352. else
  353. return $profilerPoint[$index]
  354. endif
  355. endfunc
  356.  
  357. func ProfilerGetText (const $index)
  358. return $profilerText[$index]
  359. endfunc
  360.  
  361. func ProfilerToString (const $value)
  362. return String (Int ($value * 100) / 100)
  363. endfunc
  364.  
  365. func ProfilerGetString (const $index)
  366. return ProfilerGetText ($index) & "=" & ProfilerToString (ProfilerGetDiff ($index))
  367. endfunc
  368.  
  369. ; save statistics to file
  370. global $saveStatistics = 0
  371. global $statsFilename = ""
  372. global $statsFile = -1
  373.  
  374. func StatsOpen (const $prefix)
  375. if (not ($saveStatistics)) then
  376. return 0
  377. endif
  378.  
  379. local $filename = $prefix
  380. local $i
  381.  
  382. for $i = 0 to $maxAbility
  383. if ($filename <> "") then
  384. $filename = $filename & "-"
  385. endif
  386. $filename = $filename & String ($abilityChecksumMax[$i] + 1)
  387. next
  388.  
  389. $filename = $filename & ".log"
  390.  
  391. if ($statsFile <> -1) then
  392. if ($filename = $statsFilename) then
  393. return
  394. endif
  395.  
  396. FileClose ($statsFile)
  397. endif
  398.  
  399. $statsFile = FileOpen ($filename, 1)
  400. $statsFilename = $filename
  401. endfunc
  402.  
  403. func StatsWrite ()
  404. if ($statsFile <> -1) then
  405. local $str = ""
  406. local $i
  407.  
  408. for $i = 0 to $maxAbility
  409. if ($i > 0) then
  410. $str = $str & " "
  411. endif
  412. $str = $str & String ($curAbility[$i])
  413. next
  414. $str = $str & " " & String ($curBadness)
  415. if ($curStrength <> -1) then
  416. $str = $str & " " & String ($curStrength)
  417. endif
  418.  
  419. if (not (FileWriteLine ($statsFile, $str))) then
  420. FileClose ($statsFile)
  421. $statsFile = -1
  422. endif
  423. endif
  424. endfunc
  425.  
  426. ; small delay in a loop
  427. func SmallDelay (const $delay)
  428. Sleep ($delay)
  429. return $delay
  430. ;local $i
  431. ;local $j = 0
  432. ;for $i = 0 to $delay
  433. ; $j = $j + $i
  434. ;next
  435. ;return $j
  436. endfunc
  437.  
  438. ; click mouse without delay
  439. func MouseClickNoDelay (const $x, const $y)
  440. MouseClick ($primaryMouseButton, $x, $y, 1, $mouseSpeed)
  441. endfunc
  442.  
  443. ; click mouse with delay
  444. ;func MouseClickDelay (const $x, const $y)
  445. ; MouseClick ($primaryMouseButton, $x, $y, 1, $mouseSpeed)
  446. ; SmallDelay ($zeroUpdateDelay + $firstUpdateDelay)
  447. ; Sleep ($secondUpdateDelay)
  448. ;endfunc
  449.  
  450. ; store combination
  451. func Store ()
  452. MouseClickNoDelay ($storeButton[0], $storeButton[1])
  453. MouseClickNoDelay ($storeButton[0], $storeButton[1])
  454. endfunc
  455.  
  456. ; recall combination
  457. func Recall ()
  458. MouseClickNoDelay ($recallButton[0], $recallButton[1])
  459. MouseClickNoDelay ($recallButton[0], $recallButton[1])
  460.  
  461. ; try to make better combination
  462. DecAll ()
  463. IncAll ()
  464. endfunc
  465.  
  466. ; reroll combination
  467. func Reroll ()
  468. ProfilerAddPoint ("1")
  469. local $checksum = PixelChecksum ($abilityRect[0][0], $abilityRect[0][1], $abilityRect[$maxAbility][2], $abilityRect[$maxAbility][3])
  470. ProfilerAddPoint ("2")
  471. MouseClickNoDelay ($rerollButton[0], $rerollButton[1])
  472. ProfilerAddPoint ("3")
  473. SmallDelay ($zeroUpdateDelay)
  474. if (PixelChecksum ($abilityRect[0][0], $abilityRect[0][1], $abilityRect[$maxAbility][2], $abilityRect[$maxAbility][3]) = $checksum) then
  475. ; wait a little and hope that values will be updated
  476. SmallDelay ($firstUpdateDelay)
  477. $firstDelaysNum = $firstDelaysNum + 1
  478. if (PixelChecksum ($abilityRect[0][0], $abilityRect[0][1], $abilityRect[$maxAbility][2], $abilityRect[$maxAbility][3]) = $checksum) then
  479. ; wait some more to make sure that values are updated
  480. Sleep ($secondUpdateDelay)
  481. $secondDelaysNum = $secondDelaysNum + 1
  482. endif
  483. endif
  484. ProfilerAddPoint ("4")
  485. endfunc
  486.  
  487. ; increase one ability once
  488. func IncOnce (const $index)
  489. MouseClickNoDelay ($incButton[$index][0], $incButton[$index][1])
  490. endfunc
  491.  
  492. ; increase one ability to the max
  493. func IncOne (const $index)
  494. if (GetReserveChecksum () = $zeroReserve) then
  495. return
  496. endif
  497. local $checksum = GetAbilityChecksum ($index)
  498. if (GetTextChecksum () = $canNotInc) then
  499. IncOnce ($index)
  500. Sleep ($secondUpdateDelay)
  501. endif
  502. IncOnce ($index)
  503. SmallDelay ($zeroUpdateDelay)
  504. if (GetAbilityChecksum ($index) = $checksum) then
  505. SmallDelay ($firstUpdateDelay)
  506. if (GetAbilityChecksum ($index) = $checksum) then
  507. Sleep ($secondUpdateDelay)
  508. endif
  509. endif
  510. local $i
  511. for $i = 0 to $numClicks
  512. if (GetReserveChecksum () = $zeroReserve) then
  513. exitloop
  514. endif
  515. if ($abilityChecksumMax[$index] < 0) then
  516. if (GetTextChecksum () = $canNotInc) then
  517. exitloop
  518. endif
  519. else
  520. if (GetAbilityBadness ($index) = 0) then
  521. exitloop
  522. endif
  523. endif
  524. IncOnce ($index)
  525. next
  526. endfunc
  527.  
  528. ; increase all abilities
  529. func IncAll ()
  530. local $a
  531. for $a = 0 to $maxAbility
  532. IncOne ($incAbilityPriority[$a])
  533. next
  534. endfunc
  535.  
  536. ; decrease one ability once
  537. func DecOnce (const $index)
  538. MouseClickNoDelay ($decButton[$index][0], $decButton[$index][1])
  539. endfunc
  540.  
  541. ; decrease one ability to the min
  542. func DecOne (const $index)
  543. if (($abilityChecksumMax[$index] >= 0) and (GetAbilityChecksum ($index) = $abilityChecksum[$index][$abilityChecksumMax[$index]])) then
  544. return
  545. endif
  546. local $checksum = GetAbilityChecksum ($index)
  547. if (GetTextChecksum () = $canNotDec) then
  548. DecOnce ($index)
  549. Sleep ($secondUpdateDelay)
  550. endif
  551. DecOnce ($index)
  552. SmallDelay ($zeroUpdateDelay)
  553. if (GetAbilityChecksum ($index) = $checksum) then
  554. SmallDelay ($firstUpdateDelay)
  555. if (GetAbilityChecksum ($index) = $checksum) then
  556. Sleep ($secondUpdateDelay)
  557. endif
  558. endif
  559. local $i
  560. for $i = 0 to $numClicks
  561. if ($abilityChecksumMax[$index] < 0) then
  562. if (GetTextChecksum () = $canNotDec) then
  563. exitloop
  564. endif
  565. else
  566. if (GetAbilityChecksum ($index) = $abilityChecksum[$index][$abilityChecksumMax[$index]]) then
  567. exitloop
  568. endif
  569. endif
  570. DecOnce ($index)
  571. next
  572. endfunc
  573.  
  574. ; decrease all abilities
  575. func DecAll ()
  576. local $a
  577. for $a = 0 to $maxAbility
  578. DecOne ($a)
  579. next
  580. endfunc
  581.  
  582. ; decrease all abilities except strength
  583. func DecAllButStr ()
  584. local $a
  585. for $a = $maxAbility to 1 step -1
  586. DecOne ($a)
  587. next
  588. endfunc
  589.  
  590. ; get checksum for selected ability points
  591. func GetAbilityChecksum (const $index)
  592. return PixelChecksum ($abilityRect[$index][0], $abilityRect[$index][1], $abilityRect[$index][2], $abilityRect[$index][3])
  593. endfunc
  594.  
  595. ; get checksum for description text
  596. func GetTextChecksum ()
  597. return PixelChecksum ($textRect[0], $textRect[1], $textRect[2], $textRect[3])
  598. endfunc
  599.  
  600. ; get checksum for reserve points
  601. func GetReserveChecksum ()
  602. return PixelChecksum ($reserveRect[0], $reserveRect[1], $reserveRect[2], $reserveRect[3])
  603. endfunc
  604.  
  605. global $bgNotFound = 0
  606. global $guiDelay = 500
  607.  
  608. ; show baldur's gate window
  609. func ShowBG ()
  610. while (not (WinActive ($bgTitle)))
  611. if ($bgNotFound) then
  612. exitloop
  613. endif
  614. if (not (WinExists ($bgTitle))) then
  615. $bgNotFound = 1
  616. ShowMsgBox (0, "Fatal Error", "Window '" & $bgTitle & "' is not active")
  617. Abort (1)
  618. endif
  619. WinActivate ($bgTitle)
  620. wend
  621. Sleep ($guiDelay)
  622. endfunc
  623.  
  624. func CaptureTrashEvent ()
  625. endfunc
  626.  
  627. ; save baldur's gate window from receiving unwanted keyboard events, by making trash window active
  628. func SaveBG (const $useDelay)
  629. if ($useDelay) then
  630. ; after message box is shown - avoid enter/esc/space events
  631. HotKeySet ("{ENTER}", "CaptureTrashEvent")
  632. HotKeySet ("{ESC}", "CaptureTrashEvent")
  633. HotKeySet ("{SPACE}", "CaptureTrashEvent")
  634. endif
  635. GUISetState (@SW_SHOW)
  636. while (not (WinActive ($trashTitle)))
  637. if (not (WinExists ($trashTitle))) then
  638. Abort (20)
  639. endif
  640. WinActivate ($trashTitle)
  641. wend
  642. if ($useDelay) then
  643. Sleep ($guiDelay)
  644. endif
  645. if (not ($useDelay)) then
  646. ; before message box - allow enter/esc/space events
  647. HotKeySet ("{ENTER}")
  648. HotKeySet ("{ESC}")
  649. HotKeySet ("{SPACE}")
  650. endif
  651. endfunc
  652.  
  653. global $badHashes = ""
  654.  
  655. ; get checksums for common images (that does not change for different character)
  656. func GetCommonChecksums ()
  657. local $tmp[2]
  658.  
  659. ; invalidate hash tables
  660. InvalidateAbilityChecksumHashes ()
  661. InvalidateStrengthHash ()
  662.  
  663. ; reset to allow default DecOne behaviour
  664. for $a = 0 to $maxAbility
  665. $abilityChecksumMax[$a] = -1
  666. next
  667.  
  668. ; get checksum for 'can not decrease'
  669. while (1)
  670. DecOne ($maxAbility-1)
  671. $tmp[0] = GetTextChecksum ()
  672. DecOne ($maxAbility)
  673. $tmp[1] = GetTextChecksum ()
  674. if ($tmp[0] = $tmp[1]) then
  675. $canNotDec = $tmp[0]
  676. exitloop
  677. endif
  678. wend
  679.  
  680. ; reserve all points
  681. DecAllButStr ()
  682.  
  683. ; get checksum for 'can not increase'
  684. while (1)
  685. IncOne (0)
  686. $tmp[0] = GetTextChecksum ()
  687. DecOne (0)
  688. IncOne (1)
  689. $tmp[1] = GetTextChecksum ()
  690. DecOne (1)
  691. if ($tmp[0] = $tmp[1]) then
  692. $canNotInc = $tmp[0]
  693. exitloop
  694. endif
  695. wend
  696.  
  697. ; get checksum for reserve = 0
  698. IncAll ()
  699. ; just wait enough time
  700. SmallDelay ($zeroUpdateDelay + $firstUpdateDelay)
  701. Sleep ($secondUpdateDelay)
  702. $zeroReserve = GetReserveChecksum ()
  703. endfunc
  704.  
  705. global const $abiHashMaxSize = 200
  706. global $abiHash[$maxAbility+1][$abiHashMaxSize]
  707. global $abiHashSize[$maxAbility+1]
  708.  
  709. global $useHashTable = 1
  710.  
  711. ; invalidate ability checksum hashes
  712. func InvalidateAbilityChecksumHashes ()
  713. local $a
  714. for $a = 0 to $maxAbility
  715. $abiHashSize[$a] = 0
  716. next
  717. endfunc
  718.  
  719. ; rehash one ability checksum table, using specified hash table size
  720. func RehashAbilityChecksum (const $index, const $size)
  721. local $i
  722.  
  723. ; clear hash table
  724. for $i = 0 to ($size - 1)
  725. $abiHash[$index][$i] = -1
  726. next
  727. $abiHashSize[$index] = 0
  728.  
  729. ; fill hash with all checksums
  730. for $i = 0 to $abilityChecksumMax[$index]
  731. local $hash = Mod ($abilityChecksum[$index][$i], $size)
  732. if ($abiHash[$index][$hash] <> -1) then
  733. return 0
  734. endif
  735. $abiHash[$index][$hash] = $i
  736. next
  737.  
  738. $abiHashSize[$index] = $size
  739.  
  740. return 1
  741. endfunc
  742.  
  743. ; rehash ability checksums
  744. func RehashAbilityChecksums ()
  745. if (not ($useHashTable)) then
  746. return
  747. endif
  748.  
  749. local $a
  750. for $a = 0 to $maxAbility
  751. ; invalidate hash table
  752. $abiHashSize[$a] = 0
  753. if ($abilityChecksumMax[$a] >= 0) then
  754. ; try to fill checksums into hash tables with different sizes
  755. local $size
  756. for $size = 1 to $abiHashMaxSize
  757. if (RehashAbilityChecksum ($a, $size) = 1) then
  758. ; hash table is valid
  759. exitloop
  760. endif
  761. next
  762. endif
  763. next
  764. endfunc
  765.  
  766. ; get ability badness using hash table
  767. func GetAbilityBadnessByHash (const $index, const $checksum)
  768. local $i
  769.  
  770. if ($abiHashSize[$index] > 0) then
  771. ; hash table is valid
  772. $i = $abiHash[$index][Mod ($checksum, $abiHashSize[$index])]
  773. if ($i >= 0) then
  774. if ($abilityChecksum[$index][$i] = $checksum) then
  775. return $i
  776. endif
  777. endif
  778. endif
  779.  
  780. ; not found
  781. return -1
  782. endfunc
  783.  
  784. ; cache of complex strength values
  785. global $strengthCacheSize = 1000
  786. global $strengthCacheNext = 0
  787. global $strengthCache[$strengthCacheSize+1][2]
  788.  
  789. ; load strength checksums from ini file
  790. func LoadStrengthCache ()
  791. $strengthCacheNext = ReadIniValue ("Cache", "size", 0, 0, $strengthCacheSize + 1)
  792. local $i = 0
  793. while ($i < $strengthCacheNext)
  794. $strengthCache[$i][0] = ReadIniValue ("Cache", "str" & String ($i), -1, -1, -1)
  795. $strengthCache[$i][1] = ReadIniValue ("Cache", "val" & String ($i), -1, 0, 100)
  796. $i = $i + 1
  797. wend
  798. endfunc
  799.  
  800. ; hash table for strength checksums
  801. global const $strHashMaxSize = 4 * $strengthCacheSize
  802. global $strHash[$strHashMaxSize]
  803. global $strHashSize
  804.  
  805. func InvalidateStrengthHash ()
  806. $strHashSize = 0
  807. endfunc
  808.  
  809. ; rehash strength hash table for specified size
  810. func RehashStrengthSize (const $size)
  811. local $i
  812.  
  813. ; invalidate strength hash
  814. for $i = 0 to ($size - 1)
  815. $strHash[$i] = -1
  816. next
  817. $strHashSize = 0
  818.  
  819. ; fill strength hash
  820. $i = 0
  821. while ($i < $strengthCacheNext)
  822. local $hash = Mod ($strengthCache[$i][0], $size)
  823. if ($strHash[$hash] >= 0) then
  824. ; two hashes collide
  825. return 0
  826. endif
  827.  
  828. $strHash[$hash] = $i
  829. $i = $i + 1
  830. wend
  831.  
  832. ; hash table is valid
  833. $strHashSize = $size
  834. return 1
  835. endfunc
  836.  
  837. ; rehash strength hash table
  838. func RehashStrength ()
  839. if (not ($useHashTable)) then
  840. return
  841. endif
  842. for $size = $strengthCacheNext to $strHashMaxSize
  843. if (RehashStrengthSize ($size) = 1) then
  844. ; this hash table is valid
  845. exitloop
  846. endif
  847. next
  848. endfunc
  849.  
  850. ; get strength by checksum using hash table
  851. func GetStrengthByHash (const $checksum)
  852. local $i
  853.  
  854. if ($strHashSize > 0) then
  855. ; hash table is valid
  856. $i = $strHash[Mod ($checksum, $strHashSize)]
  857. if ($i >= 0) then
  858. if ($strengthCache[$i][0] = $checksum) then
  859. return $strengthCache[$i][1]
  860. endif
  861. endif
  862. endif
  863.  
  864. ; not found
  865. return -1
  866. endfunc
  867.  
  868. ; get checksums for everything that matters
  869. func GetAllChecksums ()
  870. local $a
  871. local $i
  872.  
  873. ; invalidate hash tables
  874. InvalidateAbilityChecksumHashes ()
  875. InvalidateStrengthHash ()
  876.  
  877. DecAllButStr ()
  878.  
  879. ; get checksums for all values of each ability
  880.  
  881. for $a = 0 to $maxAbility
  882. ; increase current ability to max
  883. IncOne ($a)
  884.  
  885. ; scan all values from max to min
  886. local $checksum = GetAbilityChecksum ($a)
  887. $i = 0
  888. while (1)
  889. ; save checksum for current ability value
  890. $abilityChecksum[$a][$i] = $checksum
  891.  
  892. DecOnce ($a)
  893.  
  894. if (GetTextChecksum () = $canNotDec) then
  895. ; no more abilities (if text did not change yet, we'll get there on next iteration)
  896. exitloop
  897. endif
  898.  
  899. SmallDelay ($zeroUpdateDelay)
  900. if (GetAbilityChecksum ($a) = $checksum) then
  901. ; wait just a moment
  902. SmallDelay ($firstUpdateDelay)
  903. if (GetAbilityChecksum ($a) = $checksum) then
  904. ; ability value did not change - try to wait some more
  905. Sleep ($secondUpdateDelay)
  906. endif
  907. endif
  908.  
  909. $checksum = GetAbilityChecksum ($a)
  910. if ($abilityChecksum[$a][$i] = $checksum) then
  911. ; ability value still did not change, probably button did not work
  912. continueloop
  913. endif
  914.  
  915. ; go to the next value
  916. $i = $i + 1
  917. wend
  918.  
  919. ; number of distinct ability values
  920. $abilityChecksumMax[$a] = $i
  921. next
  922.  
  923. if ($learnStrength) then
  924. if (ShowMsgBox (1, "Warning", "Running in learning mode (without optimization of abilities). " _
  925. & "Set 'learn_strength=0' in '" & $ini & "' file if you want to run in normal mode.") <> 1) then
  926. Abort (20)
  927. endif
  928. $strIsComplex = 1
  929. else
  930. ; ask user if strength is a complex value, i.e. 18/xx
  931. IncOne ($strIndex)
  932. if (ShowMsgBox (4, "Answer me", "Is STRength complex value, like 18/xx? You can always say NO if you don't care about strength") = 6) then
  933. $strIsComplex = 1
  934. else
  935. $strIsComplex = 0
  936. endif
  937. endif
  938.  
  939. ; calculate hash tables
  940. RehashAbilityChecksums ()
  941. RehashStrength ()
  942.  
  943. ; calculate hash tables status
  944. $badHashes = ""
  945. for $i = 0 to $maxAbility
  946. if (StringLen ($badHashes) > 0) then
  947. $badHashes = $badHashes & ","
  948. endif
  949. if ($abiHashSize[$i] > 0) then
  950. $badHashes = $badHashes & "-"
  951. else
  952. $badHashes = $badHashes & String ($i)
  953. endif
  954. next
  955. if ($strHashSize > 0) then
  956. $badHashes = $badHashes & ",-"
  957. else
  958. $badHashes = $badHashes & ",s"
  959. endif
  960. endfunc
  961.  
  962. ; find current ability value badness (how far is it from maximum)
  963. func GetAbilityBadness (const $index)
  964. local $checksum = GetAbilityChecksum ($index)
  965. local $i
  966.  
  967. ; get badness using hash table
  968. $i = GetAbilityBadnessByHash ($index, $checksum)
  969. if ($i >= 0) then
  970. return $i
  971. endif
  972.  
  973. ; use linear search
  974. for $i = 0 to $abilityChecksumMax[$index]
  975. if ($abilityChecksum[$index][$i] = $checksum) then
  976. return $i
  977. endif
  978. next
  979.  
  980. if ($index = $strIndex) then
  981. ; we probably have unknown strength value - this is goodness
  982. ; treat strength in this way even if user said it is not complex
  983. return 0
  984. endif
  985.  
  986. ; probably something has obscured BG window
  987. ShowMsgBox (0, "Fatal Error", "Can not parse ability value")
  988. Exit (2)
  989. endfunc
  990.  
  991. ; read string from ini file
  992. func ReadIniString (const $section, const $name, const $def)
  993. local $tmp = "abrakadabra default value (don't use it)"
  994. local $str = IniRead ($ini, $section, $name, $tmp)
  995. if ($str = $tmp) then
  996. IniWrite ($ini, $section, $name, $def)
  997. return $def
  998. endif
  999. return $str
  1000. endfunc
  1001.  
  1002. ; read integer value from ini file
  1003. func ReadIniValue (const $section, const $name, const $def, const $min, const $max)
  1004. local $val = Int (IniRead ($ini, $section, $name, String ($defaultIniValue)))
  1005. local $ret = $val
  1006. if ($val = $defaultIniValue) then
  1007. $ret = $def
  1008. endif
  1009. if (($min <> -1) and ($ret < $min)) then
  1010. $ret = $min
  1011. endif
  1012. if (($max <> -1) and ($ret > $max)) then
  1013. $ret = $max
  1014. endif
  1015. if ($ret <> $val) then
  1016. IniWrite ($ini, $section, $name, String ($ret))
  1017. endif
  1018. return $ret
  1019. endfunc
  1020.  
  1021. ; get current strength from cache or user
  1022. func GetCurrentStrength ()
  1023. local $str = GetAbilityChecksum ($strIndex)
  1024. local $val
  1025. local $i = 0
  1026.  
  1027. $val = GetStrengthByHash ($str)
  1028. if ($val >= 0) then
  1029. return $val
  1030. endif
  1031.  
  1032. while ($i < $strengthCacheNext)
  1033. if ($strengthCache[$i][0] = $str) then
  1034. return $strengthCache[$i][1]
  1035. endif
  1036. $i = $i + 1
  1037. wend
  1038.  
  1039. while (1)
  1040. ; ask user for the value
  1041. $val = ShowInputBox ("Answer me", "Enter current strength value", "", 0, 100)
  1042. if ($val = 0) then
  1043. $val = 100
  1044. endif
  1045.  
  1046. ; test that entered value is not used already
  1047. $i = 0
  1048. while ($i < $strengthCacheNext)
  1049. if ($strengthCache[$i][1] = $val) then
  1050. exitloop
  1051. endif
  1052. $i = $i + 1
  1053. wend
  1054.  
  1055. if ($i <> $strengthCacheNext) then
  1056. if (ShowMsgBox (4, "Warning", "Strength value " & String ($val) & " is already cached. Would you like to reenter strength value?") = 6) then
  1057. continueloop
  1058. endif
  1059. endif
  1060.  
  1061. exitloop
  1062. wend
  1063.  
  1064. ; add value to the cache
  1065. if ($strengthCacheNext <= $strengthCacheSize) then
  1066. $strengthCache[$strengthCacheNext][0] = $str
  1067. $strengthCache[$strengthCacheNext][1] = $val
  1068.  
  1069. ; save value in ini file
  1070. IniWrite ($ini, "Cache", "str" & String ($strengthCacheNext), String ($str))
  1071. IniWrite ($ini, "Cache", "val" & String ($strengthCacheNext), String ($val))
  1072.  
  1073. ; save cache size
  1074. $strengthCacheNext = $strengthCacheNext + 1
  1075. IniWrite ($ini, "Cache", "size", String ($strengthCacheNext))
  1076.  
  1077. ; note: don't rehash strength on the fly, wait until user restarts the process
  1078. endif
  1079.  
  1080. return $val
  1081. endfunc
  1082.  
  1083. ; maximize strength with minimum movements
  1084. func MaximizeStrength ()
  1085. local $pointsNeeded = GetAbilityBadness ($strIndex)
  1086. local $i
  1087.  
  1088. if ($pointsNeeded <> 0) then
  1089. ; minimize mouse movements
  1090. local $bestv = 1000000
  1091. local $besti = -1
  1092. for $i = 0 to $maxAbility
  1093. if ($i = $strIndex) then
  1094. continueloop
  1095. endif
  1096. local $tempv = $abilityChecksumMax[$i] - GetAbilityBadness ($i)
  1097. if ($tempv = $pointsNeeded) then
  1098. $bestv = $tempv
  1099. $besti = $i
  1100. exitloop
  1101. endif
  1102. if (($tempv > $pointsNeeded) and ($tempv < $bestv)) then
  1103. $bestv = $tempv
  1104. $besti = $i
  1105. endif
  1106. next
  1107.  
  1108. if ($besti >= 0) then
  1109. ; found ability with minimum difference from needed amount
  1110. DecOne ($besti)
  1111. IncOne ($strIndex)
  1112. endif
  1113. endif
  1114.  
  1115. if (GetAbilityBadness ($strIndex) <> 0) then
  1116. ; just minimize all abilities in turn
  1117. for $i = 0 to $maxAbility
  1118. if ($i = $strIndex) then
  1119. continueloop
  1120. endif
  1121. DecOne ($i)
  1122. IncOne ($strIndex)
  1123. if (GetAbilityBadness ($strIndex) = 0) then
  1124. exitloop
  1125. endif
  1126. next
  1127. if (GetAbilityBadness ($strIndex) <> 0) then
  1128. ShowMsgBox (0, "Fatal Error", "Can not maximize strength")
  1129. Abort (4)
  1130. endif
  1131. endif
  1132. endfunc
  1133.  
  1134. ; number of strength lookups after last good combination
  1135. global $strengthLookups = 0
  1136.  
  1137. ; test current combination
  1138. func TestCurrentCombination ()
  1139. local $i
  1140.  
  1141. ; make sure that all points are distributed (this is not necessary now)
  1142. ;for $i = 0 to 3
  1143. ; if (GetReserveChecksum () = $zeroReserve) then
  1144. ; exitloop
  1145. ; endif
  1146. ;
  1147. ; if ($i = 3) then
  1148. ; ShowMsgBox (0, "Fatal Error", "Can not distribute all points")
  1149. ; Exit (3)
  1150. ; endif
  1151. ;
  1152. ; IncAll ()
  1153. ;next
  1154.  
  1155. ; get badness for all abilities
  1156. $curBadness = 0
  1157. $curStrength = -1
  1158.  
  1159. for $i = 0 to $maxAbility
  1160. $curAbility[$i] = GetAbilityBadness ($i)
  1161. $curBadness = $curBadness + $curAbility[$i]
  1162. next
  1163.  
  1164. if ($curBadness > $minBadness) then
  1165. ; badness is worse
  1166. return 0
  1167. endif
  1168.  
  1169. if (not ($strIsComplex)) then
  1170. if ($curBadness = $minBadness) then
  1171. ; badness is the same and strength does not matter
  1172. return 0
  1173. endif
  1174.  
  1175. ; badness is not as bad
  1176. $minBadness = $curBadness
  1177.  
  1178. ; save time of best combination
  1179. $bestTime = String (@MDAY) & "/" & String (@MON) & " " & String (@HOUR) & ":" & String (@MIN) & ":" & String (@SEC)
  1180.  
  1181. return 1
  1182. endif
  1183.  
  1184. if (not ($learnStrength)) then
  1185. if ($curBadness > $badnessLimit) then
  1186. ; badness is not good enough
  1187. return 0
  1188. endif
  1189.  
  1190. if (($curBadness = $minBadness) and $strIsComplex and ($maxStrength >= 100)) then
  1191. ; don't look for strength if strength is at the maximum for this badness already
  1192. return 0
  1193. endif
  1194. endif
  1195.  
  1196. ; test that strength is better
  1197. $strengthLookups = $strengthLookups + 1
  1198.  
  1199. ; increment strength to the maximum
  1200. MaximizeStrength ()
  1201.  
  1202. $curStrength = GetCurrentStrength ()
  1203. if (($curBadness = $minBadness) or $learnStrength) then
  1204. ; badness is the same, or we are learning strength checksums
  1205.  
  1206. ; add strength to the list
  1207. ; (I'd like to see all other combinations with current badness)
  1208. if (StringLen ($otherStrength) >= 18) then
  1209. $i = StringInStr ($otherStrength, ",", 1, 1)
  1210. if ($i > 0) then
  1211. $otherStrength = StringMid ($otherStrength, $i + 1)
  1212. endif
  1213. endif
  1214.  
  1215. if (StringLen ($otherStrength) > 0) then
  1216. $otherStrength = $otherStrength & ","
  1217. endif
  1218. $otherStrength = $otherStrength & String ($curStrength)
  1219.  
  1220. if ($learnStrength) then
  1221. ; just show current strength
  1222. $maxStrength = $curStrength
  1223. return 0
  1224. endif
  1225.  
  1226. if ($curStrength <= $maxStrength) then
  1227. ; strength is not better
  1228. return 0
  1229. endif
  1230. endif
  1231.  
  1232. if (($curStrength < $strengthLimit) and ($curBadness < $badnessLimit)) then
  1233. ; current strength is not good enough
  1234. ; throw away, even if badness is not bad
  1235. return 0
  1236. endif
  1237.  
  1238. ; got better combination
  1239.  
  1240. if ($curBadness < $minBadness) then
  1241. ; set list of strengths for new badness
  1242. $otherStrength = String ($curStrength)
  1243. endif
  1244.  
  1245. ; save time of best combination
  1246. $bestTime = String (@MDAY) & "/" & String (@MON) & " " & String (@HOUR) & ":" & String (@MIN) & ":" & String (@SEC)
  1247.  
  1248. $minBadness = $curBadness
  1249. $maxStrength = $curStrength
  1250. return 1
  1251. endfunc
  1252.  
  1253. ; reset loop variables
  1254. func ResetLoop ()
  1255. $minBadness = 1000000
  1256. $maxStrength = -1000000
  1257. $totalBadness = 0
  1258.  
  1259. $curBadness = 1000000
  1260. $curStrength = -1000000
  1261.  
  1262. $otherStrength = ""
  1263. $strengthLookups = 0
  1264.  
  1265. $bestTime = "never"
  1266.  
  1267. $curIter = 0
  1268. $totalIter = 0
  1269. $curTime = 0
  1270.  
  1271. $begTime = TimerInit ()
  1272. $loopBegTime = $begTime
  1273.  
  1274. $firstDelaysNum = 0
  1275. $secondDelaysNum = 0
  1276.  
  1277. StatsOpen (ReadIniString ("Common", "stats_prefix", "stats"))
  1278. endfunc
  1279.  
  1280. ; main loop
  1281. func MainLoop ()
  1282. local $accFirstDelaysNum = 0
  1283. local $accSecondDelaysNum = 0
  1284. local $updated = 0
  1285.  
  1286. ; increase all abilities (to avoid bad average interval on start)
  1287. IncAll ()
  1288.  
  1289. ; reset loop variables
  1290. ResetLoop ()
  1291.  
  1292. while (1)
  1293. ProfilerStart ()
  1294.  
  1295. $updated = 0
  1296.  
  1297. if (TestCurrentCombination () <> 0) then
  1298. ; have some improvement - reset number of iterations
  1299. $curIter = 0
  1300.  
  1301. ; note: don't reset timer
  1302.  
  1303. ; store current combination
  1304. Store ()
  1305. $updated = 1
  1306.  
  1307. $strengthLookups = 0
  1308. endif
  1309.  
  1310. ; save statistics
  1311. StatsWrite ()
  1312.  
  1313. ;ProfilerAddPoint ("t")
  1314.  
  1315. ; accumulate statistics
  1316. $totalBadness = $totalBadness + $curBadness
  1317. $curIter = $curIter + 1
  1318. $totalIter = $totalIter + 1
  1319. $curTime = TimerDiff ($begTime)
  1320. $totalTime = TimerDiff ($loopBegTime)
  1321.  
  1322. if ($updated or (Mod ($totalIter, $updateEvery) = 0)) then
  1323. ; output current progress
  1324. UpdateStatisticsData ()
  1325. endif
  1326.  
  1327. ; test that best combination was reached
  1328. if ($minBadness = 0) then
  1329. if (not ($strIsComplex)) then
  1330. return 1
  1331. endif
  1332. if ($maxStrength >= 100) then
  1333. return 1
  1334. endif
  1335. endif
  1336.  
  1337. ; test for limit by iterations
  1338. if (($maxIter > 0) and ($curIter >= $maxIter)) then
  1339. ; ask for more
  1340. switch (ShowMsgBox (3, "Answer me", "No improvements in last " & String ($curIter) & " iterations, stop now?"))
  1341. case 6
  1342. ; stop
  1343. return 0
  1344. case 7
  1345. ; don't stop
  1346. case else
  1347. ; cancel script
  1348. Exit (0)
  1349. endswitch
  1350.  
  1351. ; restart limited iterations
  1352. $curIter = 0
  1353. $curTime = 0
  1354.  
  1355. ; restart timer
  1356. $begTime = TimerInit ()
  1357. endif
  1358.  
  1359. ; test for limit by time
  1360. if (($maxTime > 0) and ($curTime >= ($maxTime * 1000))) then
  1361. ; ask for more
  1362. switch (ShowMsgBox (3, "Answer me", "More than " & String ($maxTime) & " seconds passed, stop now?"))
  1363. case 6
  1364. ; stop
  1365. return 0
  1366. case 7
  1367. ; don't stop
  1368. case else
  1369. ; cancel script
  1370. Exit (0)
  1371. endswitch
  1372.  
  1373. ; restart limited iterations
  1374. $curIter = 0
  1375. $curTime = 0
  1376.  
  1377. ; restart timer
  1378. $begTime = TimerInit ()
  1379. endif
  1380.  
  1381. ;ProfilerAddPoint ("n")
  1382.  
  1383. ; reroll combination
  1384. Reroll ()
  1385.  
  1386. ;ProfilerAddPoint ("e")
  1387.  
  1388. ; tune delays
  1389.  
  1390. ; try to increase delays every iteration
  1391. if ($secondDelaysNum > 0) then
  1392. $firstUpdateDelay = $firstUpdateDelay + 1
  1393. $accSecondDelaysNum = $accSecondDelaysNum + $secondDelaysNum
  1394. $secondDelaysNum = 0
  1395. endif
  1396. if ($firstDelaysNum > 0) then
  1397. $zeroUpdateDelay = $zeroUpdateDelay + 1
  1398. $accFirstDelaysNum = $accFirstDelaysNum + $firstDelaysNum
  1399. $firstDelaysNum = 0
  1400. endif
  1401.  
  1402. ; try to decrease delays every N-th iteration
  1403. if (Mod ($totalIter, $tuneEvery) = 0) then
  1404. ; try to tune delays quickly, if every iteration end up with delay
  1405. if ($accFirstDelaysNum = $tuneEvery) then
  1406. $zeroUpdateDelay = $zeroUpdateDelay + 2 * $tuneEvery
  1407. endif
  1408. if ($accSecondDelaysNum = $tuneEvery) then
  1409. $firstUpdateDelay = $firstUpdateDelay + 2 * $tuneEvery
  1410. endif
  1411.  
  1412. if (($accFirstDelaysNum > 0) and ($accSecondDelaysNum = 0) and ($firstUpdateDelay > 0)) then
  1413. ; there were first delays, but no second delays - can decrease first delay
  1414. $firstUpdateDelay = $firstUpdateDelay - 1
  1415. endif
  1416. if (($accFirstDelaysNum = 0) and ($zeroUpdateDelay > 0)) then
  1417. ; there were no first delays - can decrease zero delay
  1418. $zeroUpdateDelay = $zeroUpdateDelay - 1
  1419. endif
  1420.  
  1421. ; reset accumulated delay hits
  1422. $accFirstDelaysNum = 0
  1423. $accSecondDelaysNum = 0
  1424. endif
  1425.  
  1426. UpdateProfilerData ()
  1427.  
  1428. if (($rollsNum > 0) and (Mod ($totalIter, $rollsNum) = 0)) then
  1429. ; have some rest after specified number of rolls
  1430. local $timer = TimerInit ()
  1431. local $x = $rightEdge
  1432. local $y = $rerollButton[1]
  1433. MouseMove ($x, $y)
  1434. while (TimerDiff ($timer) < $restTime)
  1435. $x = $x + Random (-10, 10, 1)
  1436. $y = $y + Random (-10, 10, 1)
  1437. if ($x < $rightEdge) then
  1438. $x = $rightEdge
  1439. endif
  1440. MouseMove ($x, $y)
  1441. wend
  1442. endif
  1443. wend
  1444. endfunc
  1445.  
  1446. ; create dialog with label controls
  1447. func CreateGui ()
  1448. GUICreate ($trashTitle)
  1449. local $cellW = 140
  1450. local $cellH = 20
  1451. $ctrlMinBadnessLabel = GUICtrlCreateLabel ("Minimum impurity: ", 20, 20, $cellW, $cellH)
  1452. $ctrlMinBadnessValue = GUICtrlCreateLabel ("", 0, -1)
  1453. $ctrlMaxStrengthLabel = GUICtrlCreateLabel ("Maximum strength: ", -2 * $cellW, 0)
  1454. $ctrlMaxStrengthValue = GUICtrlCreateLabel ("", 0, -1, $cellW * 2, $cellH)
  1455. $ctrlCurBadnessLabel = GUICtrlCreateLabel ("Current impurity: ", -3 * $cellW, 10, $cellW, $cellH)
  1456. $ctrlCurBadnessValue = GUICtrlCreateLabel ("", 0, -1)
  1457. $ctrlAvgBadnessLabel = GUICtrlCreateLabel ("Average impurity: ", -2 * $cellW, 0)
  1458. $ctrlAvgBadnessValue = GUICtrlCreateLabel ("", 0, -1)
  1459. $ctrlItersNumLabel = GUICtrlCreateLabel ("Iterations num: ", -2 * $cellW, 10)
  1460. $ctrlItersNumValue = GUICtrlCreateLabel ("", 0, -1)
  1461. $ctrlIterTimeLabel = GUICtrlCreateLabel ("Avg iter. time: ", -2 * $cellW, 0)
  1462. $ctrlIterTimeValue = GUICtrlCreateLabel ("", 0, -1)
  1463. $ctrlDelaysNumLabel = GUICtrlCreateLabel ("Update delays: ", -2 * $cellW, 10)
  1464. $ctrlDelaysNumValue = GUICtrlCreateLabel ("", 0, -1)
  1465. $ctrlProfilerLabel = GUICtrlCreateLabel ("Profiler: ", -2 * $cellW, 10, $cellW / 2, $cellH)
  1466. $ctrlProfilerValue = GUICtrlCreateLabel ("", 0, -1, $cellW * 2, $cellH)
  1467. $ctrlHelpValue = GUICtrlCreateLabel ("Press 'PAUSE/BREAK' to pause script", -2 * $cellW - $cellW / 2, 20, 3 * $cellW, $cellH)
  1468. GUISetState (@SW_SHOW)
  1469. endfunc
  1470.  
  1471. ; update statistical information
  1472. func UpdateStatisticsData ()
  1473. GUICtrlSetData ($ctrlMinBadnessValue, String ($minBadness) & " at " & String ($bestTime))
  1474. local $str
  1475. if ($strIsComplex) then
  1476. if (StringLen ($otherStrength) > 0) then
  1477. $str = " (" & $otherStrength & ")"
  1478. else
  1479. $str = ""
  1480. endif
  1481. GUICtrlSetData ($ctrlMaxStrengthValue, String ($maxStrength) & $str & " / " & String ($strengthLookups))
  1482. else
  1483. GUICtrlSetData ($ctrlMaxStrengthValue, "")
  1484. endif
  1485. GUICtrlSetData ($ctrlCurBadnessValue, String ($curBadness))
  1486. if ($totalIter <> 0) then
  1487. local $avg = Int ($totalBadness / $totalIter * 100)
  1488. GUICtrlSetData ($ctrlAvgBadnessValue, String ($avg / 100))
  1489. $avg = Int ($totalTime)
  1490. GUICtrlSetData ($ctrlItersNumValue, String ($totalIter) & " in " & String ($avg / 1000))
  1491. $avg = Int ($totalTime / $totalIter)
  1492. GUICtrlSetData ($ctrlIterTimeValue, String ($avg / 1000))
  1493. endif
  1494. GUICtrlSetData ($ctrlDelaysNumValue, String ($zeroUpdateDelay) & "+" & String ($firstUpdateDelay) & " | " & $badHashes)
  1495. endfunc
  1496.  
  1497. ; update profiler information
  1498. func UpdateProfilerData ()
  1499. if ($useProfiler) then
  1500. local $i = 0
  1501. local $str = ""
  1502. while ($i < ProfilerGetPoints ())
  1503. if (StringLen ($str) > 0) then
  1504. $str = $str & ","
  1505. endif
  1506. $str = $str & ProfilerGetString ($i)
  1507. $i = $i + 1
  1508. wend
  1509. GUICtrlSetData ($ctrlProfilerValue, $str)
  1510. endif
  1511. endfunc
  1512.  
  1513. ; ask something from user
  1514. func ShowMsgBox (const $type, const $title, const $text)
  1515. SaveBG (0)
  1516. local $ret = MsgBox ($type, $title, $text)
  1517. SaveBG (1)
  1518. ShowBG ()
  1519. return $ret
  1520. endfunc
  1521.  
  1522. ; ask integer value from user
  1523. func ShowInputBox (const $title, const $text, const $def, const $min, const $max)
  1524. local $ret
  1525. SaveBG (0)
  1526. while (1)
  1527. local $str = InputBox ($title, $text, $def)
  1528. $ret = Int ($str)
  1529. if (($str = "") or ($str <> String ($ret))) then
  1530. ; not a valid integer
  1531. continueloop
  1532. endif
  1533. if (($min <> -1) and ($ret < $min)) then
  1534. ; less than minimum
  1535. continueloop
  1536. endif
  1537. if (($max <> -1) and ($ret > $max)) then
  1538. ; greater than maximum
  1539. continueloop
  1540. endif
  1541. ; value is good
  1542. exitloop
  1543. wend
  1544. SaveBG (1)
  1545. ShowBG ()
  1546. return $ret
  1547. endfunc
  1548.  
  1549. ; read most values from ini file
  1550. func ReadIniFile ()
  1551. $numClicks = ReadIniValue ("Common", "number_of_clicks", 30, 25, 100)
  1552.  
  1553. $zeroUpdateDelay = ReadIniValue ("Common", "zero_update_delay", 20, 0, 10000000)
  1554. $firstUpdateDelay = ReadIniValue ("Common", "first_update_delay", 1, 0, 10000000)
  1555. $secondUpdateDelay = ReadIniValue ("Common", "second_update_delay", 100, 10, 2000)
  1556.  
  1557. $mouseSpeed = ReadIniValue ("Common", "mouse_speed", 5, 0, 100)
  1558.  
  1559. $updateEvery = ReadIniValue ("Common", "update_every", 1, 1, 1000)
  1560. $tuneEvery = ReadIniValue ("Common", "tune_every", 10, 5, 1000000)
  1561.  
  1562. $learnStrength = ReadIniValue ("Common", "learn_strength", 0, 0, 1)
  1563.  
  1564. $strengthLimit = ReadIniValue ("Common", "strength_limit", 0, 0, 100)
  1565. $badnessLimit = ReadIniValue ("Common", "impurity_limit", 100, 0, 1000)
  1566.  
  1567. $rollsNum = ReadIniValue ("Common", "rolls_num", 0, 0, 1000000000)
  1568. $restTime = ReadIniValue ("Common", "rest_time", 0, 0, 60*60)
  1569.  
  1570. $guiDelay = ReadIniValue ("Common", "gui_delay", 1000, 500, 5000)
  1571.  
  1572. $maxIter = ReadIniValue ("Common", "max_iter", 10, 0, 1000000000)
  1573. $maxTime = ReadIniValue ("Common", "max_time", 24*60*60, 0, 400*30*24*60*60)
  1574.  
  1575. $useHashTable = ReadIniValue ("Common", "use_hash_table", 0, 0, 1)
  1576. $useProfiler = ReadIniValue ("Common", "use_profiler", 0, 0, 1)
  1577. $saveStatistics = ReadIniValue ("Common", "save_stats", 0, 0, 1)
  1578.  
  1579. Opt ("MouseClickDelay", ReadIniValue ("Common", "mouse_click_delay", 20, 5, 500))
  1580. Opt ("MouseClickDownDelay", ReadIniValue ("Common", "mouse_click_down", 10, 5, 500))
  1581. endfunc
  1582.  
  1583. func Init ()
  1584.  
  1585. if ($initialized) then
  1586. return 0
  1587. endif
  1588.  
  1589. ; initialize everything
  1590. ReadIniFile ()
  1591. FillCoordinates ()
  1592. LoadStrengthCache ()
  1593. CreateGui ()
  1594.  
  1595. ; show short info
  1596. ShowMsgBox (0, "Roll along", _
  1597. "This utility can be used to roll perfect abilities in Baldur's Gate. " _
  1598. & "Just run it while abilities selection page is on screen. " _
  1599. & "It will do all the work for you, maybe asking some silly questions, " _
  1600. & "like which numbers it has rolled just now (it can not read yet), " _
  1601. & "or whether to continue rolling or not." & Chr (10) _
  1602. & "You can see '" & $trashTitle & "' window on screen - move it aside, such " _
  1603. & "that it will not obscure Baldur's Gate window, but don't close it - " _
  1604. & "it is used to capture trash events left in buffer sometimes " _
  1605. & "(note: to avoid trash events, press buttons in dialogs with mouse). " _
  1606. & "By the way, I should have mentioned that you have to run the game " _
  1607. & "in windowed mode, otherwise this utility will not roll anything." & Chr (10) _
  1608. & "When identifying number for strength, when you see '18/x', type 'x' " _
  1609. & "as a number. For example, 18/03 means 3, while 18/00 means 100 " _
  1610. & "(the best)." & Chr (10) _
  1611. & "Press 'Pause/Break' at any time to stop rolling." & Chr (10) _
  1612. & "Let's have some fun?")
  1613.  
  1614. ; wait until user activates abilities selection page
  1615. while (1)
  1616. local $ret = ShowMsgBox (3, "Answer me", "Abilities selection page is active?")
  1617. if ($ret = 6) then
  1618. exitloop
  1619. endif
  1620. if ($ret <> 7) then
  1621. Abort (30)
  1622. endif
  1623. wend
  1624.  
  1625. ; get checksums for common images
  1626. GetCommonChecksums ()
  1627.  
  1628. $initialized = 1
  1629.  
  1630. endfunc
  1631.  
  1632. func Main ()
  1633.  
  1634. ReadIniFile ()
  1635.  
  1636. while (1)
  1637. ; ask if user wants to roll abilities again
  1638. if (ShowMsgBox (4, "Answer me", "Continue rolling?") <> 6) then
  1639. Abort (0)
  1640. endif
  1641.  
  1642. ; reread all checksums
  1643. GetAllChecksums ()
  1644.  
  1645. ; roll abilities
  1646. MainLoop ()
  1647.  
  1648. ; recall best combination
  1649. Recall ()
  1650. wend
  1651.  
  1652. endfunc
  1653.  
  1654. ; at last, execute everything
  1655. Init ()
  1656. Main ()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement