Advertisement
Guest User

Untitled

a guest
Sep 30th, 2014
180
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 188.17 KB | None | 0 0
  1. ; Path of Exile Item Info Tooltip
  2. ;
  3. ; Version: 1.7.5 (hazydoc / IGN:Sadou)
  4. ;
  5. ; This script was originally based on the POE_iLVL_DPS-Revealer script (v1.2d) found here:
  6. ; https://www.pathofexile.com/forum/view-thread/594346
  7. ;
  8. ; Changes to the POE_iLVL_DPS-Revealer script as recent as it's version 1.4.1 have been
  9. ; brought over. Thank you Nipper4369 and Kislorod!
  10. ;
  11. ; The script has been added to substantially to enable the following features in addition to
  12. ; itemlevel and weapon DPS reveal:
  13. ;
  14. ; - show total affix statistic for rare items
  15. ; - show possible min-max ranges for all affixes on rare items
  16. ; - reveal the combination of difficult compound affixes (you might be surprised what you find)
  17. ; - show affix ranges for uniques
  18. ; - show map info (thank you, Kislorod and Necrolis)
  19. ; - show max socket info (thank you, Necrolis)
  20. ; - has the ability to convert currency items to chaos orbs (you can adjust the rates by editing
  21. ; <datadir>\CurrencyRates.txt)
  22. ; - can show which gems are valuable and/or drop-only (all user adjustable)
  23. ; - can show a reminder for uniques that are generally considered valuable (user adjustable as well)
  24. ; - adds a system tray icon and proper system tray description tooltip
  25. ;
  26. ; All of these features are user-adjustable by using a "database" of text files which come
  27. ; with the script and are easy to edit by non developers. See header comments in those files
  28. ; for format infos and data sources.
  29. ;
  30. ; Known issues:
  31. ;
  32. ; Even though there have been tons of tests made on composite affix combinations, I expect
  33. ; there to be edge cases still that may return an invalid or not found affix bracket.
  34. ; You can see these entries in the affix detail lines if they have the text "n/a" (not available)
  35. ; somewhere in them or if you see an empty range " - *". The star by the way marks ranges
  36. ; that have been added together for a guessed attempt as to the composition of a possible
  37. ; compound affix. If you see this star, take a closer look for a moment to check if the
  38. ; projection is correct. I expect these edge cases to be properly dealt with over time as the
  39. ; script matures. For now I'd estimate that at least 80% of the truly hard cases are correctly
  40. ; identified.
  41. ;
  42. ; Some background info: because the game concatenates values from multiple affix sources into
  43. ; one final entry on the ingame tooltip there is no reliable way to work backwards from the
  44. ; composite value to each individual part. For example, Stun Recovery can be added as suffix if
  45. ; it contributes alone, but can also be a prefix if it is a composite of Stun Recovery and
  46. ; Evasion Rating (or others). Because there is one final entry, while prefix and suffix can
  47. ; appear at the same time and will be added together, you can't reliably reverse engineer which
  48. ; affix contributed what part of the composite value. This is akin to taking a random source of
  49. ; numbers, adding them up to one value and then asking someone to work out backwards what the
  50. ; original source values were.
  51. ; Similarily, in cases like boosted Stun Recovery (1) and Evasion Rating (2) on an item in difficult
  52. ; cases there is no 100% reliable way to tell if the prefix "+ Evasion Rating / Block and Stun Recovery"
  53. ; contributed to both stats at once or if the suffix "+ Block and Stun Recovery" contributed to (1)
  54. ; and the prefix "+ Evasion Rating" cotributed to (2) or possibly a combination of both.
  55. ; Often it is possible to make guesses by working your way backwards from both partial affixes, by
  56. ; looking at the affix bracket ranges and the item level to see what is even possible to be there and
  57. ; what isn't. In the worst case for a double compound affix, all four ranges will be possible to be
  58. ; combined.
  59. ;
  60. ; I have tested the tooltip on many, many items in game from my own stash and from trade chat
  61. ; and I can say that in the overwhelming majority of cases the tooltip does indeed work correctly.
  62. ;
  63. ; IMPORTANT: as you may know, the total amount of affixes (w/o implicit mods) can be 6, of which
  64. ; 3 at most are prefixes and likewise 3 at most are suffixes. Be especially weary, then of cases
  65. ; where this prefix/suffix limit is overcapped. It may happen that the tooltip shows 4 suffixes,
  66. ; and 3 prefixes total. In this case the most likely explanation is that the script failed to properly
  67. ; determine composite affixes. Composite affixes ("Comp. Prefix" or "Comp. Suffix" in the tooltip)
  68. ; are two affix lines on the ingame tooltip that together form one single composite affix.
  69. ; Edit v1.4: This hasn't happened for a longer time now, but I am leaving this important note in
  70. ; so end users stay vigilant (assuming anyone even reads this wall of text :)).
  71. ;
  72. ; - I do not know which affixes are affected by +% Item Quality. Currently I have functions in place
  73. ; that can boost a range or a single value to adjust for Item Quality but currently these aren't used
  74. ; much. Partially this is also because it is not easy to tell if out-of-bounds cases are the result
  75. ; of faulty input data (I initially pulled data from the PoE mods compendium but later made the PoE
  76. ; homepage the authoritative source overruling data from other sources) or of other unreckognized and
  77. ; unhandled entities or systems.
  78. ;
  79. ; Todo:
  80. ;
  81. ; - handle ranges for implicit mods
  82. ;
  83. ; Notes:
  84. ;
  85. ; - Global values marked with an inline comment "d" are globals for debugging so they can be easily
  86. ; (re-)enabled using global search and replace. Marking variables as global means they will show
  87. ; up in AHK's Variables and contents view of the script.
  88. ;
  89. ; Needs AutoHotKey v1.0.45 or later
  90. ;
  91. ; Original credits:
  92. ;
  93. ; mcpower - for the base iLVL display of the script 5months ago before Immo.
  94. ; Immo - for the base iLVL display of the script.(Which was taken from mcpower.)
  95. ; olop4444 - for helping me figure out the calculations for Q20 items.
  96. ; Aeons - for a rewrite and fancy tooltips.
  97. ; kongyuyu - for base item level display.
  98. ; Fayted - for testing the script.
  99. ;
  100. ; Original author's comment:
  101. ;
  102. ; If you have any questions or comments please post them there as well. If you think you can help
  103. ; improve this project. I am looking for contributors. So Pm me if you think you can help.
  104. ;
  105. ; If you have a issue please post what version you are using.
  106. ; Reason being is that something that might be a issue might already be fixed.
  107. ;
  108.  
  109. ;
  110. ; Garena offcial chinese version
  111. ; by love60729@ptt silentlich@ptt
  112. ;
  113.  
  114. ; Run test suites (see end of script)
  115. ; Note: don't set this to true for normal every day use...
  116. ; This is just for fellow developers.
  117. RunTests := False
  118.  
  119. #SingleInstance force
  120. #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
  121. #Persistent ; Stay open in background
  122. SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
  123. StringCaseSense, On ; Match strings with case.
  124.  
  125. ; OPTIONS
  126.  
  127. OnlyActiveIfPOEIsFront = 0 ; Set to 1 to make it so the script does nothing if Path of Exile window isn't the frontmost.
  128. ; If 0, the script also works if PoE isn't frontmost. This is handy for have the script parse
  129. ; textual item representations appearing somewhere else, like in the forums or text files.
  130.  
  131. ShowItemLevel = 1 ; Show item level and the item type's base level (enabled by default change to 0 to disable)
  132. ShowMaxSockets = 1 ; Show the max sockets based on ilvl and type
  133. ShowDamageCalculations = 1 ; Show damage projections (for weapons only)
  134.  
  135. ShowAffixTotals = 1 ; Show total affix statistics
  136. ShowAffixDetails = 1 ; Show detailed info about affixes
  137. ShowAffixLevel = 0 ; Show item level of the affix
  138. ShowAffixBracket = 1 ; Show range for the affix' bracket as is on the item
  139. ShowAffixMaxPossible = 1 ; Show max possible bracket for an affix based on the item's item level
  140. ShowAffixBracketTier = 1 ; Show a T# indicator of the tier the affix bracket is in.
  141. ; T1 being the highest possible, T2 second-to-highest and so on
  142.  
  143. TierRelativeToItemLevel = 0 ; When determining the affix bracket tier, take item level into consideration.
  144. ; However, this also means that the lower the item level the less the diversity
  145. ; of possible affix tiers since there aren't as many possibilities. This will
  146. ; give the illusion that a low level item might be really, really good when it
  147. ; has all T1 but in reality it can only have T1 since it's item level is so low
  148. ; it can only ever take the first bracket.
  149. ;
  150. ; If this option is set to 0, the tiers will always display relative to the full
  151. ; range of tiers available, ignoring the item level.
  152.  
  153. ShowCurrencyValueInChaos = 1 ; Convert the value of currency items into chaos orbs.
  154. ; This is based on the rates defined in <datadir>\CurrencyRates.txt
  155. ; You should edit this file with the current currency rates.
  156.  
  157. ShowUniqueEvaluation = 0 ; Display reminder when a unique is valuable.
  158. ; This is based on <datadir>\ValuableUniques.txt
  159. ; You can edit this file to suit your own needs.
  160.  
  161. ShowGemEvaluation = 0 ; Display reminder when a gem is valuable and/or drop only.
  162. ; This is based on <datadir>\ValuableGems.txt and <datadir>\DropOnlyGems.txt
  163. ; You can edit these files to suit your own needs.
  164.  
  165. GemQualityValueThreshold = 10 ; If the gem's added quality exceeds this value, consider it valuable regardless of which gem it is.
  166.  
  167. MaxSpanStartingFromFirst = 1 ; When showing max possible, don't just show the highest possible affix bracket
  168. ; but construct a pseudo range which spans the lower bound of the lowest possible
  169. ; bracket to the upper bound of the highest possible one.
  170. ;
  171. ; This is usually what you want to see when evaluating an item's worth. The exception
  172. ; being when you want to reroll an affix to the highest possible value within it's
  173. ; current bracket - then you need to see the affix range that is actually on the item
  174. ; right now.
  175.  
  176. CompactDoubleRanges = 1 ; Show double ranges as "1-172" instead of "1-8 to 160-172"
  177. CompactAffixTypes = 1 ; Use compact affix type designations: Suffix = 後綴, Prefix = 前綴, Comp. Suffix = 複合後綴, Comp. Prefix = 複合前綴
  178.  
  179. MarkHighLinksAsValuable = 0 ; Mark rares or uniques with 5L or 6L as valuable.
  180.  
  181. MirrorAffixLines = 1 ; Show a copy of the affix line in question when showing affix details.
  182. ;
  183. ; For example, would display "Prefix, 5-250" instead of "+246 to Accuracy Rating, Prefix, 5-250".
  184. ; Since the affixes are processed in order one can attribute which is which to the ordering of
  185. ; the lines in the tooltip to the item data in game.
  186.  
  187. MirrorLineFieldWidth = 18 ; Mirrored affix line width. Set to a number above 0 to truncate (or pad) to this many characters.
  188. ; Appends AffixDetailEllipsis when truncating.
  189. ValueRangeFieldWidth = 7 ; Width of field that displays the affix' value range(s). Set to a number larger than 0 to truncate (or pad) to this many characters.
  190. ;
  191. ; Keep in mind that there are sometimes double ranges to be displayed. Like for example on an axe, implicit physical damage might
  192. ; have a lower bound range and a upper bound range. In this case the lower bound range can have at most a 3 digit minimum value,
  193. ; and at most a 3 digit maximum value. To then display just the lower bound (which constitutes one value range field), you would need
  194. ; at least 7 characters (ex: 132-179). To complete the example here is how it would look like with 2 fields (lower and upper bound)
  195. ; 132-179 168-189. Note that you don't need to set 15 as option value to display both fields correctly. As the name implies the option
  196. ; is per field, so a value of 8 can display two 8 character wide fields correctly.
  197.  
  198. AffixDetailDelimiter := " " ; Field delimiter for affix detail lines. This is put between value range fields. If this value were set to a comma, the above
  199. ; double range example would become 132-179,168-189.
  200.  
  201. AffixDetailEllipsis := "…" ; If the MirrorLineFieldWidth is set to a value that is smaller than the actual length of the affix line text
  202. ; the affix line will be cut off and this text will be appended at the end to indicate tha the line was truncated.
  203. ;
  204. ; Usually this is set to the ASCII or Unicode value of the three dot ellipsis (alt code: 0133).
  205. ; Note that the correct display of text characters outside the ASCII standard depend on the file encoding and the
  206. ; AHK version used. For best results, save this file as ANSI encoding which can be read and displayed correctly by
  207. ; either ANSI based AutoHotkey or Unicode based AutoHotkey.
  208. ;
  209. ; Example: assume the affix line to be mirrored is '+#% increased Spell Damage'.
  210. ; If the MirrorLineFieldWidth is set to 18, this field would be shown as '+#% increased Spel…'
  211.  
  212. PutResultsOnClipboard = 0 ; Put result text on clipboard (overwriting the textual representation the game put there to begin with)
  213.  
  214. ; Pixels mouse must move to auto-dismiss tooltip
  215. MouseMoveThreshold := 40
  216.  
  217. ; Set this to 1 if you want to have the tooltip disappear after the time frame set below.
  218. ; Otherwise you will have to move the mouse by 5 pixels for the tip to disappear.
  219. UseTooltipTimeout = 0
  220.  
  221. ;How many ticks to wait before removing tooltip. 1 tick = 100ms. Example, 50 ticks = 5secends, 75 Ticks = 7.5Secends
  222. ToolTipTimeoutTicks := 150
  223.  
  224. ; Font size for the tooltip, leave empty for default
  225. FontSize := 9.5
  226.  
  227. ; OPTIONS END
  228.  
  229.  
  230.  
  231.  
  232.  
  233. ; Menu tooltip
  234. Menu, tray, Tip, Path of Exile Item Info 1.7.5
  235.  
  236. ; Windows system tray icon
  237. ; possible values: poe.ico, poe-bw.ico, poe-web.ico, info.ico
  238. Menu, tray, Icon, data\poe-bw.ico
  239.  
  240. If (A_AhkVersion <= "1.0.45")
  241. {
  242. msgbox, You need AutoHotkey v1.0.45 or later to run this script. `n`nPlease go to http://ahkscript.org/download and download a recent version.
  243. exit
  244. }
  245.  
  246. IfNotExist, %A_ScriptDir%\data
  247. {
  248. msgbox, Error 37`n`n"data" directory not found at "%A_ScriptDir%".`n`nPlease make sure the data directory is present at the same location where you are executing the script from.
  249. exit
  250. }
  251.  
  252. #Include %A_ScriptDir%\data\MapList.txt
  253.  
  254. MsgUnhandled := "Unhandled case. Please report the item that you are inspecting by pasting the textual item representation that is on your clipboard right now into a reply to the script's forum thread at http://www.pathofexile.com/forum/view-thread/790438.`n`nThanks so much for helping out!"
  255.  
  256. ; Create font for later use
  257. FixedFont := CreateFont()
  258.  
  259. ; Creates a font for later use
  260. CreateFont()
  261. {
  262. Global FontSize
  263. Options :=
  264. If (!(FontSize = ""))
  265. {
  266. Options = s%FontSize%
  267. }
  268. Gui Font, %Options%, Courier New
  269. Gui Font, %Options%, Consolas
  270. Gui Add, Text, HwndHidden,
  271. SendMessage, 0x31,,,, ahk_id %Hidden%
  272. return ErrorLevel
  273. }
  274.  
  275. ; Sets the font for a created ahk tooltip
  276. SetFont(Font)
  277. {
  278. SendMessage, 0x30, Font, 1,, ahk_class tooltips_class32 ahk_exe autohotkey.exe
  279. }
  280.  
  281. ParseElementalDamage(String, DmgType, ByRef DmgLo, ByRef DmgHi)
  282. {
  283. IfInString, String, %DmgType%傷害
  284. {
  285. IfInString, String, 轉換 or IfInString, String, 承受
  286. return
  287. IfNotInString, String, 增加
  288. {
  289. StringSplit, Arr, String, %A_Space%
  290. StringSplit, Arr, Arr2, -
  291. DmgLo := Arr1
  292. DmgHi := Arr2
  293. }
  294. }
  295. }
  296.  
  297. ; Function that checks item type name against entries
  298. ; from ItemList.txt to get the item's base level
  299. ; Added by kongyuyu, changed by hazydoc
  300. CheckBaseLevel(ItemTypeName)
  301. {
  302. ItemListArray = 0
  303. Loop, Read, %A_WorkingDir%\data\ItemList.txt
  304. {
  305. ; This loop retrieves each line from the file, one at a time.
  306. ItemListArray += 1 ; Keep track of how many items are in the array.
  307. StringSplit, NameLevel, A_LoopReadLine, |,
  308. Array%ItemListArray%1 := NameLevel1 ; Store this line in the next array element.
  309. Array%ItemListArray%2 := NameLevel2
  310. }
  311.  
  312. Loop %ItemListArray% {
  313. element := Array%A_Index%1
  314. If(ItemTypeName == element)
  315. {
  316. BaseLevel := Array%A_Index%2
  317. Break
  318. }
  319. }
  320. return BaseLevel
  321. }
  322.  
  323. CheckRarityLevel(RarityString)
  324. {
  325. IfInString, RarityString, Normal
  326. return 1
  327. IfInString, RarityString, Magic
  328. return 2
  329. IfInString, RarityString, Rare
  330. return 3
  331. IfInString, RarityString, Unique
  332. return 4
  333. return 0 ; unknown rarity. shouldn't happen!
  334. }
  335.  
  336. ParseItemType(ItemDataStats, ItemDataNamePlate, ByRef BaseType, ByRef SubType, ByRef GripType)
  337. {
  338. ; Grip type only matters for weapons at this point. For all others it will be 'None'.
  339. GripType = None
  340.  
  341. ; Check stats section first as weapons usually have their sub type as first line
  342. Loop, Parse, ItemDataStats, `n, `r
  343. {
  344. IfInString, A_LoopField, 單手斧
  345. {
  346. BaseType = Weapon
  347. SubType = Axe
  348. GripType = 1H
  349. return
  350. }
  351. IfInString, A_LoopField, 雙手斧
  352. {
  353. BaseType = Weapon
  354. SubType = Axe
  355. GripType = 2H
  356. return
  357. }
  358. IfInString, A_LoopField, 單手錘
  359. {
  360. BaseType = Weapon
  361. SubType = Mace
  362. GripType = 1H
  363. return
  364. }
  365. IfInString, A_LoopField, 雙手錘
  366. {
  367. BaseType = Weapon
  368. SubType = Mace
  369. GripType = 2H
  370. return
  371. }
  372. IfInString, A_LoopField, 權杖
  373. {
  374. BaseType = Weapon
  375. SubType = Sceptre
  376. GripType = 1H
  377. return
  378. }
  379. IfInString, A_LoopField, 長杖
  380. {
  381. BaseType = Weapon
  382. SubType = Staff
  383. GripType = 2H
  384. return
  385. }
  386. IfInString, A_LoopField, 單手劍
  387. {
  388. BaseType = Weapon
  389. SubType = Sword
  390. GripType = 1H
  391. return
  392. }
  393. IfInString, A_LoopField, 雙手劍
  394. {
  395. BaseType = Weapon
  396. SubType = Sword
  397. GripType = 2H
  398. return
  399. }
  400. IfInString, A_LoopField, 匕首
  401. {
  402. BaseType = Weapon
  403. SubType = Dagger
  404. GripType = 1H
  405. return
  406. }
  407. IfInString, A_LoopField, 爪
  408. {
  409. BaseType = Weapon
  410. SubType = Claw
  411. GripType = 1H
  412. return
  413. }
  414. IfInString, A_LoopField, 弓
  415. {
  416. ; Not really sure if I should classify bow as 2H (because that would make sense)
  417. ; but you can equip a quiver in 2nd hand slot, so it could be 1H?
  418. BaseType = Weapon
  419. SubType = Bow
  420. GripType = 1H
  421. return
  422. }
  423. IfInString, A_LoopField, 法杖
  424. {
  425. BaseType = Weapon
  426. SubType = Wand
  427. GripType = 1H
  428. return
  429. }
  430. }
  431.  
  432. ; Check name plate section
  433. Loop, Parse, ItemDataNamePlate, `n, `r
  434. {
  435. ; a few cases that cause incorrect id later
  436. ; and thus should come first
  437. ; Note: still need to work on proper id for
  438. ; all armour types.
  439. IfInString, A_LoopField, Ringmail
  440. {
  441. BaseType = Armour
  442. SubType = BodyArmour
  443. return
  444. }
  445. IfInString, A_LoopField, Mantle
  446. {
  447. BaseType = Armour
  448. SubType = BodyArmour
  449. return
  450. }
  451. IfInString, A_LoopField, Shell
  452. {
  453. BaseType = Armour
  454. SubType = BodyArmour
  455. return
  456. }
  457.  
  458. ; Belts, Amulets, Rings, Quivers, Flasks
  459. IfInString, A_LoopField, Rustic Sash
  460. {
  461. BaseType = Item
  462. SubType = Belt
  463. return
  464. }
  465. IfInString, A_LoopField, Belt
  466. {
  467. BaseType = Item
  468. SubType = Belt
  469. return
  470. }
  471. IfInString, A_LoopField, 項鍊
  472. {
  473. BaseType = Item
  474. SubType = Amulet
  475. return
  476. }
  477. IfInString, A_LoopField, 戒指
  478. {
  479. BaseType = Item
  480. SubType = Ring
  481. return
  482. }
  483. IfInString, A_LoopField, Quiver
  484. {
  485. BaseType = Item
  486. SubType = Quiver
  487. return
  488. }
  489. IfInString, A_LoopField, Flask
  490. {
  491. BaseType = Item
  492. SubType = Flask
  493. return
  494. }
  495. IfInString, A_LoopField, %A_Space%Map
  496. {
  497. BaseType = Map
  498. global matchList
  499. Loop % matchList.MaxIndex()
  500. {
  501. Match := matchList[A_Index]
  502. IfInString, A_LoopField, %Match%
  503. {
  504. SubType = %Match%
  505. return
  506. }
  507. }
  508.  
  509. SubType = Unknown%A_Space%Map
  510. return
  511. }
  512. ; Dry Peninsula fix
  513. IfInString, A_LoopField, Dry%A_Space%Peninsula
  514. {
  515. BaseType = Map
  516. SubType = Dry%A_Space%Peninsula
  517. return
  518. }
  519.  
  520. ; Shields
  521. IfInString, A_LoopField, Shield
  522. {
  523. BaseType = Armour
  524. SubType = Shield
  525. return
  526. }
  527. IfInString, A_LoopField, Buckler
  528. {
  529. BaseType = Armour
  530. SubType = Shield
  531. return
  532. }
  533. IfInString, A_LoopField, Bundle
  534. {
  535. BaseType = Armour
  536. SubType = Shield
  537. return
  538. }
  539. IfInString, A_LoopField, Gloves
  540. {
  541. BaseType = Armour
  542. SubType = Gloves
  543. return
  544. }
  545. IfInString, A_LoopField, Mitts
  546. {
  547. BaseType = Armour
  548. SubType = Gloves
  549. return
  550. }
  551. IfInString, A_LoopField, Gauntlets
  552. {
  553. BaseType = Armour
  554. SubType = Gloves
  555. return
  556. }
  557.  
  558. ; Helmets
  559. IfInString, A_LoopField, Helmet
  560. {
  561. BaseType = Armour
  562. SubType = Helmet
  563. return
  564. }
  565. IfInString, A_LoopField, Helm
  566. {
  567. BaseType = Armour
  568. SubType = Helmet
  569. return
  570. }
  571. If (InStr(A_LoopField, "Hat") AND (Not InStr(A_LoopField, "Hate")))
  572. {
  573. BaseType = Armour
  574. SubType = Helmet
  575. return
  576. }
  577. IfInString, A_LoopField, Mask
  578. {
  579. BaseType = Armour
  580. SubType = Helmet
  581. return
  582. }
  583. IfInString, A_LoopField, Hood
  584. {
  585. BaseType = Armour
  586. SubType = Helmet
  587. return
  588. }
  589. IfInString, A_LoopField, Ursine Pelt
  590. {
  591. BaseType = Armour
  592. SubType = Helmet
  593. return
  594. }
  595. IfInString, A_LoopField, Lion Pelt
  596. {
  597. BaseType = Armour
  598. SubType = Helmet
  599. return
  600. }
  601. IfInString, A_LoopField, Circlet
  602. {
  603. BaseType = Armour
  604. SubType = Helmet
  605. return
  606. }
  607. IfInString, A_LoopField, Sallet
  608. {
  609. BaseType = Armour
  610. SubType = Helmet
  611. return
  612. }
  613. IfInString, A_LoopField, Burgonet
  614. {
  615. BaseType = Armour
  616. SubType = Helmet
  617. return
  618. }
  619. IfInString, A_LoopField, Bascinet
  620. {
  621. BaseType = Armour
  622. SubType = Helmet
  623. return
  624. }
  625. IfInString, A_LoopField, Crown
  626. {
  627. BaseType = Armour
  628. SubType = Helmet
  629. return
  630. }
  631. IfInString, A_LoopField, Cage
  632. {
  633. BaseType = Armour
  634. SubType = Helmet
  635. return
  636. }
  637. IfInString, A_LoopField, Tricorne
  638. {
  639. BaseType = Armour
  640. SubType = Helmet
  641. return
  642. }
  643.  
  644. ; Boots
  645. IfInString, A_LoopField, Boots
  646. {
  647. BaseType = Armour
  648. SubType = Boots
  649. return
  650. }
  651. IfInString, A_LoopField, Greaves
  652. {
  653. BaseType = Armour
  654. SubType = Boots
  655. return
  656. }
  657. IfInString, A_LoopField, Slippers
  658. {
  659. BaseType = Armour
  660. SubType = Boots
  661. return
  662. }
  663. }
  664.  
  665. ; TODO: need a reliable way to determine sub type for armour
  666. ; right now it's just determine anything else first if it's
  667. ; not that, it's armour.
  668. BaseType = Armour
  669. SubType = Armour
  670. }
  671.  
  672. GetClipboardContents(DropNewlines = False)
  673. {
  674. Result =
  675. If Not DropNewlines
  676. {
  677. Loop, Parse, Clipboard, `n, `r
  678. {
  679. Result := Result . A_LoopField . "`r`n"
  680. }
  681. }
  682. Else
  683. {
  684. Loop, Parse, Clipboard, `n, `r
  685. {
  686. Result := Result . A_LoopField
  687. }
  688. }
  689. return Result
  690. }
  691.  
  692. SetClipboardContents(String)
  693. {
  694. Clipboard := String
  695. }
  696.  
  697. ; attempted to create a nice re-usable function for all the string splitting
  698. ; doesn't work correctly yet!
  699. SplitString(StrInput, StrDelimiter)
  700. {
  701. TempDelim := "``"
  702. StringReplace, TempResult, StrInput, %StrDelimiter%, %TempDelim%, All
  703. StringSplit, Parts, TempResult, %TempDelim%
  704. return Parts
  705. }
  706.  
  707. ; Look up just the most applicable bracket for an affix.
  708. ; Most applicable means Value is between bounds of bracket range
  709. ; OR highest entry possible given the item level
  710. ; returns: "#-#" format range
  711. ; If Value is unspecified ("") return the max possible bracket
  712. ; based on item level
  713. LookupAffixBracket(Filename, ItemLevel, Value="", ByRef BracketLevel="")
  714. {
  715. AffixLevel := 0
  716. AffixDataIndex := 0
  717. If (Not Value == "")
  718. {
  719. ValueLo := Value ; value from ingame tooltip
  720. ValueHi := Value ; for single values (which most of them are) ValueLo == ValueHi
  721. ParseRange(Value, ValueHi, ValueLo)
  722. }
  723. ; msgbox, Filename: %Filename%`, Value: %Value%`, ValueLo: %ValueLo%`, ValueHi: %ValueHi%
  724. LookupIsDoubleRange := False ; for affixes like "Adds +# ... Damage" which have a lower AND an upper bound range
  725. BracketRange := "n/a"
  726. Loop, Read, %A_WorkingDir%\%Filename%
  727. {
  728. AffixDataIndex += 1
  729. StringSplit, AffixDataParts, A_LoopReadLine, |,
  730. RangeLevel := AffixDataParts1
  731. RangeValues := AffixDataParts2
  732. If (RangeLevel > ItemLevel)
  733. {
  734. Break
  735. }
  736. IfInString, RangeValues, `,
  737. {
  738. LookupIsDoubleRange := True
  739. }
  740. If (LookupIsDoubleRange)
  741. {
  742. ; example lines from txt file database for double range lookups:
  743. ; 3|1,14-15
  744. ; 13|1-3,35-37
  745. StringSplit, DoubleRangeParts, RangeValues, `,
  746. LB := DoubleRangeParts%DoubleRangeParts%1
  747. UB := DoubleRangeParts%DoubleRangeParts%2
  748. ; default case: lower bound is single value: #
  749. ; see level 3 case in example lines above
  750. LBMin := LB
  751. LBMax := LB
  752. UBMin := UB
  753. UBMax := UB
  754. IfInString, LB, -
  755. {
  756. ; lower bound is a range: #-#
  757. ParseRange(LB, LBMax, LBMin)
  758. }
  759. IfInString, UB, -
  760. {
  761. ParseRange(UB, UBMax, UBMin)
  762. }
  763. LBPart = %LBMin%
  764. UBPart = %UBMax%
  765. ; record bracket range if it is within bounds of the text file entry
  766. If (Value == "" or (((ValueLo >= LBMin) and (ValueLo <= LBMax)) and ((ValueHi >= UBMin) and (ValueHi <= UBMax))))
  767. {
  768. BracketRange = %LBPart%-%UBPart%
  769. AffixLevel = %RangeLevel%
  770. }
  771. }
  772. Else
  773. {
  774. ParseRange(RangeValues, HiVal, LoVal)
  775. ; record bracket range if it is within bounds of the text file entry
  776. If (Value == "" or ((ValueLo >= LoVal) and (ValueHi <= HiVal)))
  777. {
  778. BracketRange = %LoVal%-%HiVal%
  779. AffixLevel = %RangeLevel%
  780. }
  781. }
  782. }
  783. BracketLevel := AffixLevel
  784. return BracketRange
  785. }
  786.  
  787. ; Look up complete data for an affix. Depending on settings flags
  788. ; this may include many things, and will return a string used for
  789. ; end user display rather than further calculations.
  790. ; Use LookupAffixBracket if you need a range format to do calculations with.
  791. LookupAffixData(Filename, ItemLevel, Value, ByRef BracketLevel="", ByRef Tier=0)
  792. {
  793. Global MaxLevel
  794. Global MaxSpanStartingFromFirst
  795. Global CompactDoubleRanges
  796. Global TierRelativeToItemLevel
  797. MaxLevel := 0
  798. AffixLevel := 0
  799. AffixDataIndex := 0
  800. ValueLo := Value ; value from ingame tooltip
  801. ValueHi := Value ; for single values (which most of them are) ValueLo == ValueHi
  802. ValueIsMinMax := False ; treat Value as min/max units (#-#) or as single unit (#)
  803. LookupIsDoubleRange := False ; for affixes like "Adds +# ... Damage" which have a lower AND an upper bound range
  804. FirstRangeValues =
  805. BracketRange := "n/a"
  806. MaxRange =
  807. FinalRange =
  808. MaxLevel := 1
  809. RangeLevel := 1
  810. Tier := 0
  811. MaxTier := 0
  812. IfInString, Value, -
  813. {
  814. ParseRange(Value, ValueHi, ValueLo)
  815. ValueIsMinMax := True
  816. }
  817. ; Pre-pass to determine max tier
  818. Loop, Read, %A_WorkingDir%\%Filename%
  819. {
  820. MaxTier += 1
  821. StringSplit, AffixDataParts, A_LoopReadLine, |,
  822. RangeLevel := AffixDataParts1
  823. If (TierRelativeToItemLevel AND (RangeLevel > ItemLevel))
  824. {
  825. Break
  826. }
  827. }
  828. ;msgbox, MaxTier: %MaxTier%
  829. Loop, Read, %A_WorkingDir%\%Filename%
  830. {
  831. AffixDataIndex += 1
  832. StringSplit, AffixDataParts, A_LoopReadLine, |,
  833. RangeValues := AffixDataParts2
  834. RangeLevel := AffixDataParts1
  835. If (AffixDataIndex == 1)
  836. {
  837. FirstRangeValues := RangeValues
  838. }
  839. If (RangeLevel > ItemLevel)
  840. {
  841. Break
  842. }
  843. MaxLevel := RangeLevel
  844. IfInString, RangeValues, `,
  845. {
  846. LookupIsDoubleRange := True
  847. }
  848. If (LookupIsDoubleRange)
  849. {
  850. ; ; variables for min/max double ranges, like in the "Adds +# ... Damage" case
  851. ; Global LBMin ; (L)ower (B)ound minium value
  852. ; Global LBMax ; (L)ower (B)ound maximum value
  853. ; GLobal UBMin ; (U)pper (B)ound minimum value
  854. ; GLobal UBMax ; (U)pper (B)ound maximum value
  855. ; ; same, just for the first range's values
  856. ; Global FRLBMin
  857. ; Global FRLBMax
  858. ; Global FRUBMin
  859. ; Global FRUBMax
  860. ; example lines from txt file database for double range lookups:
  861. ; 3|1,14-15
  862. ; 13|1-3,35-37
  863. StringSplit, DoubleRangeParts, RangeValues, `,
  864. LB := DoubleRangeParts%DoubleRangeParts%1
  865. UB := DoubleRangeParts%DoubleRangeParts%2
  866. ; default case: lower bound is single value: #
  867. ; see level 3 case in example lines above
  868. LBMin := LB
  869. LBMax := LB
  870. UBMin := UB
  871. UBMax := UB
  872. IfInString, LB, -
  873. {
  874. ; lower bound is a range: #-#
  875. ParseRange(LB, LBMax, LBMin)
  876. }
  877. IfInString, UB, -
  878. {
  879. ParseRange(UB, UBMax, UBMin)
  880. }
  881. If (AffixDataIndex == 1)
  882. {
  883. StringSplit, FirstDoubleRangeParts, FirstRangeValues, `,
  884. FRLB := FirstDoubleRangeParts%FirstDoubleRangeParts%1
  885. FRUB := FirstDoubleRangeParts%FirstDoubleRangeParts%2
  886. ParseRange(FRUB, FRUBMax, FRUBMin)
  887. ParseRange(FRLB, FRLBMax, FRLBMin)
  888. }
  889. If ((LBMin == LBMax) or CompactDoubleRanges)
  890. {
  891. LBPart = %LBMin%
  892. }
  893. Else
  894. {
  895. LBPart = %LBMin%-%LBMax%
  896. }
  897. If ((UBMin == UBMax) or CompactDoubleRanges)
  898. {
  899. UBPart = %UBMax%
  900. }
  901. Else
  902. {
  903. UBPart = %UBMin%-%UBMax%
  904. }
  905. If ((FRLBMin == FRLBMax) or CompactDoubleRanges)
  906. {
  907. FRLBPart = %FRLBMin%
  908. }
  909. Else
  910. {
  911. FRLBPart = %FRLBMin%-%FRLBMax%
  912. }
  913. If (CompactDoubleRanges)
  914. {
  915. MiddlePart := "-"
  916. }
  917. Else
  918. {
  919. MiddlePart := " to "
  920. }
  921. ; record bracket range if it is withing bounds of the text file entry
  922. If (((ValueLo >= LBMin) and (ValueLo <= LBMax)) and ((ValueHi >= UBMin) and (ValueHi <= UBMax)))
  923. {
  924. ;msgbox, Value: %Value%`, LBPart: %LBPart%`, UBPart: %UBPart%
  925. BracketRange = %LBPart%%MiddlePart%%UBPart%
  926. AffixLevel = %MaxLevel%
  927. Tier := ((MaxTier - AffixDataIndex) + 1)
  928. ;msgbox, BracketRange: %BracketRange%
  929. }
  930. ; record max possible range regardless of within bounds
  931. If (MaxSpanStartingFromFirst)
  932. {
  933. MaxRange = %FRLBPart%%MiddlePart%%UBPart%
  934. }
  935. Else
  936. {
  937. MaxRange = %LBPart%%MiddlePart%%UBPart%
  938. }
  939. }
  940. Else
  941. {
  942. If (AffixDataIndex = 1)
  943. {
  944. ParseRange(FirstRangeValues, FRHiVal, FRLoVal)
  945. }
  946. ParseRange(RangeValues, HiVal, LoVal)
  947. ; record bracket range if it is within bounds of the text file entry
  948. If ((ValueLo >= LoVal) and (ValueHi <= HiVal))
  949. {
  950. If (LoVal = HiVal)
  951. {
  952. BracketRange = %LoVal%
  953. }
  954. Else
  955. {
  956. BracketRange = %LoVal%-%HiVal%
  957. }
  958. AffixLevel = %MaxLevel%
  959. Tier := ((MaxTier - AffixDataIndex) + 1)
  960. ;msgbox, AffixDataIndex: %AffixDataIndex%, FirstRangeValues: %FirstRangeValues%,
  961. }
  962. ; record max possible range regardless of within bounds
  963. If (MaxSpanStartingFromFirst)
  964. {
  965. MaxRange = %FRLoVal%-%HiVal%
  966. }
  967. Else
  968. {
  969. MaxRange = %LoVal%-%HiVal%
  970. }
  971. }
  972. ; msgbox, Filename: %Filename%`n ValueLo: %ValueLo%`, ValueHi: %ValueHi%`n LoVal: %LoVal%`, HiVal: %HiVal%
  973. }
  974. BracketLevel := AffixLevel
  975. FinalRange := AssembleValueRangeFields(BracketRange, BracketLevel, MaxRange, MaxLevel)
  976. ; msgbox, FinalRange: %FinalRange%
  977. return FinalRange
  978. }
  979.  
  980. AssembleValueRangeFields(BracketRange, BracketLevel, MaxRange="", MaxLevel=0)
  981. {
  982. Global ShowAffixLevel
  983. Global ShowAffixBracket
  984. Global ShowAffixMaxPossible
  985. Global ValueRangeFieldWidth
  986. Global AffixDetailDelimiter
  987. If (ShowAffixBracket)
  988. {
  989. FinalRange := BracketRange
  990. If (ValueRangeFieldWidth > 0)
  991. {
  992. FinalRange := StrPad(FinalRange, ValueRangeFieldWidth, "left")
  993. }
  994. If (ShowAffixLevel)
  995. {
  996. FinalRange := FinalRange . " " . "(" . BracketLevel . ")" . ", "
  997. }
  998. Else
  999. {
  1000. FinalRange := FinalRange . AffixDetailDelimiter
  1001. }
  1002. }
  1003. If (MaxRange and ShowAffixMaxPossible)
  1004. {
  1005. If (ValueRangeFieldWidth > 0)
  1006. {
  1007. MaxRange := StrPad(MaxRange, ValueRangeFieldWidth, "left")
  1008. }
  1009. FinalRange := FinalRange . MaxRange
  1010. If (ShowAffixLevel)
  1011. {
  1012. FinalRange := FinalRange . " " . "(" . MaxLevel . ")"
  1013. }
  1014. }
  1015. return FinalRange
  1016. }
  1017.  
  1018. ParseRarity(ItemData_NamePlate)
  1019. {
  1020. Loop, Parse, ItemData_NamePlate, `n, `r
  1021. {
  1022. IfInString, A_LoopField, Rarity:
  1023. {
  1024. StringSplit, RarityParts, A_LoopField, %A_Space%
  1025. Break
  1026. }
  1027. }
  1028. return RarityParts%RarityParts%2
  1029. }
  1030.  
  1031. ParseQuality(ItemDataNamePlate)
  1032. {
  1033. ItemQuality := 0
  1034. Loop, Parse, ItemDataNamePlate, `n, `r
  1035. {
  1036. If (StrLen(A_LoopField) = 0)
  1037. {
  1038. Break
  1039. }
  1040. IfInString, A_LoopField, Unidentified
  1041. {
  1042. Break
  1043. }
  1044. IfInString, A_LoopField, Quality:
  1045. {
  1046. ItemQuality := RegExReplace(A_LoopField, "Quality: \+(\d+)% .*", "$1")
  1047. Break
  1048. }
  1049. }
  1050. return ItemQuality
  1051. }
  1052.  
  1053. ParseAugmentations(ItemDataChunk, ByRef AffixCSVList)
  1054. {
  1055. Global CurAugment
  1056. CurAugment := ItemDataChunk
  1057. Loop, Parse, ItemDataChunk, `n, `r
  1058. {
  1059. CurAugment := A_LoopField
  1060. IfInString, A_LoopField, Requirements:
  1061. {
  1062. Break
  1063. }
  1064. IfInString, A_LoopField, (augmented)
  1065. {
  1066. StringSplit, LineParts, A_LoopField, :
  1067. AffixCSVList := AffixCSVList . "'" . LineParts%LineParts%1 . "'"
  1068. AffixCSVList := AffixCSVList . ", "
  1069. }
  1070. }
  1071. AffixCSVList := SubStr(AffixCSVList, 1, -2)
  1072. }
  1073.  
  1074. ParseRequirements(ItemDataChunk, ByRef Level, ByRef Attributes, ByRef Values="")
  1075. {
  1076. IfNotInString, ItemDataChunk, Requirements
  1077. {
  1078. return
  1079. }
  1080. Attr =
  1081. AttrValues =
  1082. Delim := ","
  1083. DelimLen := StrLen(Delim)
  1084. Loop, Parse, ItemDataChunk, `n, `r
  1085. {
  1086. If StrLen(A_LoopField) = 0
  1087. {
  1088. Break ; not interested in blank lines
  1089. }
  1090. IfInString, A_LoopField, Str
  1091. {
  1092. Attr := Attr . "Str" . Delim
  1093. AttrValues := AttrValues . GetColonValue(A_LoopField) . Delim
  1094. }
  1095. IfInString, A_LoopField, Dex
  1096. {
  1097. Attr := Attr . "Dex" . Delim
  1098. AttrValues := AttrValues . GetColonValue(A_LoopField) . Delim
  1099. }
  1100. IfInString, A_LoopField, Int
  1101. {
  1102. Attr := Attr . "Int" . Delim
  1103. AttrValues := AttrValues . GetColonValue(A_LoopField) . Delim
  1104. }
  1105. IfInString, A_LoopField, Level
  1106. {
  1107. Level := GetColonValue(A_LoopField)
  1108. }
  1109. }
  1110. ; chop off last Delim
  1111. If (SubStr(Attr, -(DelimLen-1)) == Delim)
  1112. {
  1113. Attr := SubStr(Attr, 1, -(DelimLen))
  1114. }
  1115. If (SubStr(AttrValues, -(DelimLen-1)) == Delim)
  1116. {
  1117. AttrValues := SubStr(AttrValues, 1, -(DelimLen))
  1118. }
  1119. Attributes := Attr
  1120. Values := AttrValues
  1121. }
  1122.  
  1123. ; parses #low-#high and sets Hi to #high and Lo to #low
  1124. ; if RangeChunk is just a single value (#) it will set both
  1125. ; Hi and Lo to this single value (effectively making the range 1-1 if # was 1)
  1126. ParseRange(RangeChunk, ByRef Hi, ByRef Lo)
  1127. {
  1128. IfInString, RangeChunk, -
  1129. {
  1130. StringSplit, RangeParts, RangeChunk, -
  1131. Lo := RegExReplace(RangeParts1, "(\d+?)", "$1")
  1132. Hi := RegExReplace(RangeParts2, "(\d+?)", "$1")
  1133. }
  1134. Else
  1135. {
  1136. Hi := RangeChunk
  1137. Lo := RangeChunk
  1138. }
  1139. }
  1140.  
  1141. ParseItemLevel(ItemData, PartialString="Itemlevel:")
  1142. {
  1143. Result =
  1144. Loop, Parse, ItemData, `n, `r
  1145. {
  1146. If StrLen(A_LoopField) = 0
  1147. {
  1148. Break
  1149. }
  1150. IfInString, A_LoopField, %PartialString%
  1151. {
  1152. StringSplit, ItemLevelParts, A_LoopField, %A_Space%
  1153. Result := ItemLevelParts2
  1154. Break
  1155. }
  1156. }
  1157. return Result
  1158. }
  1159.  
  1160. StrMult(Char, Times)
  1161. {
  1162. Result =
  1163. Loop, %Times%
  1164. {
  1165. Result := Result . Char
  1166. }
  1167. return Result
  1168. }
  1169.  
  1170. StrTrimSpaceLeft(String)
  1171. {
  1172. return RegExReplace(String, " *(.+?)", "$1")
  1173. }
  1174.  
  1175. StrTrimSpaceRight(String)
  1176. {
  1177. return RegExReplace(String, "(.+?) *$", "$1")
  1178. }
  1179.  
  1180. StrTrimSpace(String)
  1181. {
  1182. return RegExReplace(String, " *(.+?) *", "$1")
  1183. }
  1184.  
  1185. ; Pads a string with a multiple of PadChar to become a wanted total length.
  1186. ; Note that Side is the side that is padded not the anchored side.
  1187. ; Meaning, if you pad right side, the text will move left. If Side was an
  1188. ; anchor instead, the text would move right if anchored right.
  1189. StrPad(String, Length, Side="right", PadChar=" ")
  1190. {
  1191. ; Result := String
  1192. StringLen, Len, String
  1193. AddLen := Length-Len
  1194. If (AddLen <= 0)
  1195. {
  1196. ; msgbox, String: %String%`, Length: %Length%`, Len: %Len%`, AddLen: %AddLen%
  1197. return String
  1198. }
  1199. Pad := StrMult(PadChar, AddLen)
  1200. If (Side == "right")
  1201. {
  1202. Result := String . Pad
  1203. }
  1204. Else
  1205. {
  1206. Result := Pad . String
  1207. }
  1208. return Result
  1209. }
  1210.  
  1211. ; estimate indicator, marks end user display values so they can take a look at it
  1212. MarkAsGuesstimate(ValueRange, Side="left", Indicator=" * ")
  1213. {
  1214. Global ValueRangeFieldWidth
  1215. Global MarkedAsGuess
  1216. MarkedAsGuess := True
  1217. return StrPad(ValueRange . Indicator, ValueRangeFieldWidth + StrLen(Indicator), Side)
  1218. }
  1219.  
  1220. MakeAffixDetailLine(AffixLine, AffixType, ValueRange, Tier)
  1221. {
  1222. Global ItemDataRarity
  1223. Delim := "|"
  1224. Ellipsis := AffixDetailEllipsis
  1225. Line := AffixLine . Delim . ValueRange . Delim . AffixType
  1226. If (ItemDataRarity == "Rare")
  1227. {
  1228. Line := Line . Delim . Tier
  1229. }
  1230. return Line
  1231. }
  1232.  
  1233. AppendAffixInfo(Line, AffixPos)
  1234. {
  1235. Global
  1236. AffixLines%AffixPos% := Line
  1237. }
  1238.  
  1239. AssembleAffixDetails()
  1240. {
  1241. Global
  1242. Local Result
  1243. Local Delim
  1244. Local Ellipsis
  1245. Local CurLine
  1246. Local IsImplicitMod
  1247. Local TierString
  1248. Local ValueRangeString
  1249. AffixLine =
  1250. AffixType =
  1251. ValueRange =
  1252. AffixTier =
  1253. Loop, %NumAffixLines%
  1254. {
  1255. CurLine := AffixLines%A_Index%
  1256. ; blank out affix line parts so that when affix line splits
  1257. ; into less parts than before, there won't be left overs
  1258. Loop, 3
  1259. {
  1260. AffixLineParts%A_Index% =
  1261. }
  1262. StringSplit, AffixLineParts, CurLine, |
  1263. AffixLine := AffixLineParts1
  1264. ValueRange := AffixLineParts2
  1265. AffixType := AffixLineParts3
  1266. AffixTier := AffixLineParts4
  1267.  
  1268. ;msgbox, AffixTier: %AffixTier%
  1269.  
  1270. Delim := AffixDetailDelimiter
  1271. Ellipsis := AffixDetailEllipsis
  1272.  
  1273. If (ValueRangeFieldWidth > 0)
  1274. {
  1275. ValueRange := StrPad(ValueRange, ValueRangeFieldWidth, "left")
  1276. }
  1277. If (MirrorAffixLines = 1)
  1278. {
  1279. If (MirrorLineFieldWidth > 0)
  1280. {
  1281. If(StrLen(AffixLine) > MirrorLineFieldWidth)
  1282. {
  1283. AffixLine := StrTrimSpaceRight(SubStr(AffixLine, 1, MirrorLineFieldWidth)) . Ellipsis
  1284. }
  1285. AffixLine := StrPad(AffixLine, MirrorLineFieldWidth + StrLen(Ellipsis))
  1286. }
  1287. ProcessedLine := AffixLine . Delim
  1288. }
  1289. IfInString, ValueRange, *
  1290. {
  1291. ValueRangeString := StrPad(ValueRange, (ValueRangeFieldWidth * 2) + (StrLen(AffixDetailDelimiter)))
  1292. }
  1293. Else
  1294. {
  1295. ValueRangeString := ValueRange
  1296. }
  1297. ProcessedLine := ProcessedLine . ValueRangeString . Delim
  1298. If (ShowAffixBracketTier == 1 AND Not (ItemDataRarity == "Unique"))
  1299. {
  1300. If (InStr(ValueRange, "*") AND ShowAffixBracketTier)
  1301. {
  1302. TierString := " "
  1303. }
  1304. Else
  1305. {
  1306. TierString := StrPad("T" . AffixTier, 3, "left")
  1307. }
  1308. ProcessedLine := ProcessedLine . TierString . Delim
  1309. }
  1310. ProcessedLine := ProcessedLine . AffixType . Delim
  1311. Result := Result . "`n" . ProcessedLine
  1312. }
  1313. ; msgbox, Result: %Result%
  1314. return Result
  1315. }
  1316.  
  1317. ; Same as AdjustRangeForQuality, except that Value is just
  1318. ; a single value and not a range.
  1319. AdjustValueForQuality(Value, ItemQuality, Direction="up")
  1320. {
  1321. If (ItemQuality < 1)
  1322. return Value
  1323. Divisor := ItemQuality / 100
  1324. If (Direction == "up")
  1325. {
  1326. Result := Round(Value + (Value * Divisor))
  1327. }
  1328. Else
  1329. {
  1330. Result := Round(Value - (Value * Divisor))
  1331. }
  1332. return Result
  1333. }
  1334.  
  1335. ; Adjust an affix' range for +% Quality on an item.
  1336. ; For example: given the range 10-20 and item quality +15%
  1337. ; the result would be 11.5-23 which is currently rounded up
  1338. ; to 12-23. Note that Direction does not play a part in rounding
  1339. ; rather it controls if adjusting up towards quality increase or
  1340. ; down from quality increase (to get the original value back)
  1341. AdjustRangeForQuality(ValueRange, ItemQuality, Direction="up")
  1342. {
  1343. If (ItemQuality = 0)
  1344. {
  1345. return ValueRange
  1346. }
  1347. VRHi := 0
  1348. VRLo := 0
  1349. ParseRange(ValueRange, VRHi, VRLo)
  1350. Divisor := ItemQuality / 100
  1351. If (Direction == "up")
  1352. {
  1353. VRHi := Round(VRHi + (VRHi * Divisor))
  1354. VRLo := Round(VRLo + (VRLo * Divisor))
  1355. }
  1356. Else
  1357. {
  1358. VRHi := Round(VRHi - (VRHi * Divisor))
  1359. VRLo := Round(VRLo - (VRLo * Divisor))
  1360. }
  1361. If (VRLo == VRHi)
  1362. {
  1363. ValueRange = %VRLo%
  1364. }
  1365. Else
  1366. {
  1367. ValueRange = %VRLo%-%VRHi%
  1368. }
  1369. return ValueRange
  1370. }
  1371.  
  1372. ; checks ActualValue against ValueRange, returning 1
  1373. ; if ActualValue is within bounds of ValueRange, 0 otherwise
  1374. WithinBounds(ValueRange, ActualValue)
  1375. {
  1376. ; msgbox, ValueRange: %ValueRange%`, ActualValue: %ActualValue%
  1377. VHi := 0
  1378. VLo := 0
  1379. ParseRange(ValueRange, VHi, VLo)
  1380. Result := 1
  1381. IfInString, ActualValue, -
  1382. {
  1383. AVHi := 0
  1384. AVLo := 0
  1385. ParseRange(ActualValue, AVHi, AVLo)
  1386. If ((AVLo < VLo) or (AVHi > VHi))
  1387. {
  1388. Result := 0
  1389. }
  1390. }
  1391. Else
  1392. {
  1393. If ((ActualValue < VLo) or (ActualValue > VHi))
  1394. {
  1395. Result := 0
  1396. }
  1397. }
  1398. ; msgbox, Result: %Result%
  1399. return Result
  1400. }
  1401.  
  1402. GetAffixTypeFromProcessedLine(PartialAffixString)
  1403. {
  1404. Global
  1405. Loop, %NumAffixLines%
  1406. {
  1407. Local AffixLine
  1408. AffixLine := AffixLines%A_Index%
  1409. IfInString, AffixLine, %PartialAffixString%
  1410. {
  1411. Local AffixLineParts
  1412. StringSplit, AffixLineParts, AffixLine, |
  1413. return AffixLineParts3
  1414. }
  1415. }
  1416. }
  1417.  
  1418. ; Get actual value from a line of the ingame tooltip as a number
  1419. ; that can be used in calculations.
  1420. GetActualValue(ActualValueLine)
  1421. {
  1422. Result := RegExReplace(ActualValueLine, ".*?\+?(\d+(?:-\d+|\.\d+)?).*", "$1")
  1423. return Result
  1424. }
  1425.  
  1426. ; Get value from a color line, e.g. given the line "Level: 57", returns the number 57
  1427. GetColonValue(Line)
  1428. {
  1429. IfInString, Line, :
  1430. {
  1431. StringSplit, LineParts, Line, :
  1432. Result := StrTrimSpace(LineParts%LineParts%2)
  1433. return Result
  1434. }
  1435. }
  1436.  
  1437. RangeMid(Range)
  1438. {
  1439. If (Range = 0 or Range = "0" or Range = "0-0")
  1440. {
  1441. return 0
  1442. }
  1443. RHi := 0
  1444. RLo := 0
  1445. ParseRange(Range, RHi, RLo)
  1446. RSum := RHi+RLo
  1447. If (RSum == 0)
  1448. {
  1449. return 0
  1450. }
  1451. return Floor((RHi+RLo)/2)
  1452. }
  1453.  
  1454. RangeMin(Range)
  1455. {
  1456. If (Range = 0 or Range = "0" or Range = "0-0")
  1457. {
  1458. return 0
  1459. }
  1460. RHi := 0
  1461. RLo := 0
  1462. ParseRange(Range, RHi, RLo)
  1463. return RLo
  1464. }
  1465.  
  1466. RangeMax(Range)
  1467. {
  1468. If (Range = 0 or Range = "0" or Range = "0-0")
  1469. {
  1470. return 0
  1471. }
  1472. RHi := 0
  1473. RLo := 0
  1474. ParseRange(Range, RHi, RLo)
  1475. return RHi
  1476. }
  1477.  
  1478. AddRange(Range1, Range2)
  1479. {
  1480. R1Hi := 0
  1481. R1Lo := 0
  1482. R2Hi := 0
  1483. R2Lo := 0
  1484. ParseRange(Range1, R1Hi, R1Lo)
  1485. ParseRange(Range2, R2Hi, R2Lo)
  1486. FinalHi := R1Hi + R2Hi
  1487. FinalLo := R1Lo + R2Lo
  1488. FinalRange = %FinalLo%-%FinalHi%
  1489. return FinalRange
  1490. }
  1491.  
  1492. ; used to check return values from LookupAffixBracket()
  1493. IsValidBracket(Bracket)
  1494. {
  1495. If (Bracket == "n/a")
  1496. {
  1497. return False
  1498. }
  1499. return True
  1500. }
  1501.  
  1502. ; used to check return values from LookupAffixData()
  1503. IsValidRange(Bracket)
  1504. {
  1505. IfInString, Bracket, n/a
  1506. {
  1507. return False
  1508. }
  1509. return True
  1510. }
  1511.  
  1512. ; Note that while ExtractCompAffixBalance() can be run on processed data
  1513. ; that has compact affix type declarations (or not) for this function to
  1514. ; work properly, make sure to run it on data that has compact affix types
  1515. ; turned off. The reason being that it is hard to count prefixes by there
  1516. ; being a "P" in a line that also has mirrored affix descriptions.
  1517. ExtractTotalAffixBalance(ProcessedData, ByRef Prefixes, ByRef Suffixes, ByRef CompPrefixes, ByRef CompSuffixes)
  1518. {
  1519. ; msgbox, ProcessedData: %ProcessedData%
  1520. Loop, Parse, ProcessedData, `n, `r
  1521. {
  1522. AffixLine := A_LoopField
  1523. IfInString, AffixLine, Comp. Prefix
  1524. {
  1525. CompPrefixes += 1
  1526. }
  1527. IfInString, AffixLine, Comp. Suffix
  1528. {
  1529. CompSuffixes += 1
  1530. }
  1531. }
  1532. ProcessedData := RegExReplace(ProcessedData, "Comp\. Prefix", "")
  1533. ProcessedData := RegExReplace(ProcessedData, "Comp\. Suffix", "")
  1534. ; msgbox, ProcessedData: %ProcessedData%
  1535. Loop, Parse, ProcessedData, `n, `r
  1536. {
  1537. AffixLine := A_LoopField
  1538. IfInString, AffixLine, Prefix
  1539. {
  1540. Prefixes += 1
  1541. ; ProcessedData := RegExReplace(ProcessedData, "Prefix", "")
  1542. }
  1543. IfInString, AffixLine, Suffix
  1544. {
  1545. Suffixes += 1
  1546. ; ProcessedData := RegExReplace(ProcessedData, "Suffix", "")
  1547. }
  1548. }
  1549. }
  1550. ExtractCompositeAffixBalance(ProcessedData, ByRef CompPrefixes, ByRef CompSuffixes)
  1551. {
  1552. Loop, Parse, ProcessedData, `n, `r
  1553. {
  1554. AffixLine := A_LoopField
  1555. IfInString, AffixLine, Comp. Prefix
  1556. {
  1557. CompPrefixes += 1
  1558. }
  1559. IfInString, AffixLine, Comp. Suffix
  1560. {
  1561. CompSuffixes += 1
  1562. }
  1563. }
  1564. }
  1565.  
  1566. ParseAffixes(ItemDataChunk, ItemLevel, ItemQuality, ByRef NumPrefixes, ByRef NumSuffixes)
  1567. {
  1568. Global ItemBaseType
  1569. Global ItemSubType
  1570. Global ItemGripType
  1571. Global NumAffixLines
  1572. Global ValueRangeFieldWidth ; for StrPad on guesstimated values
  1573. Global MsgUnhandled
  1574. Global MarkedAsGuess
  1575.  
  1576. ; keeps track of how many affix lines we have so they can be assembled later
  1577. ; acts as a loop index variable when iterating each affix data part
  1578. NumAffixLines := 0
  1579. NumPrefixes := 0
  1580. NumSuffixes := 0
  1581.  
  1582. ; Composition flags
  1583. ; these are required for later descision making when guesstimating
  1584. ; sources for parts of a value from composite and/or same name affixes
  1585. ; They will be set to the line number where they occur in the pre-pass
  1586. ; loop so that details for that line can be changed later after we
  1587. ; have more clues for possible compositions.
  1588. HasIIQ := 0
  1589. HasIncrArmour := 0
  1590. HasIncrEvasion := 0
  1591. HasIncrEnergyShield := 0
  1592. HasHybridDefences := 0
  1593. HasIncrArmourAndES := 0
  1594. HasIncrArmourAndEvasion := 0
  1595. HasIncrEvasionAndES := 0
  1596. HasIncrLightRadius := 0
  1597. HasIncrAccuracyRating := 0
  1598. HasIncrPhysDmg := 0
  1599. HasToAccuracyRating := 0
  1600. HasStunRecovery := 0
  1601. HasSpellDamage := 0
  1602. HasMaxMana := 0
  1603.  
  1604. ; max mana already accounted for in case of composite prefix+prefix "Spell Damage / Max Mana" + "Max Mana"
  1605. MaxManaPartial =
  1606.  
  1607. ; Accuracy Rating already accounted for in case of
  1608. ; composite prefix + composite suffix: "increased Physical Damage / to Accuracy Rating" + "to Accuracy Rating / Light Radius"
  1609. ; composite prefix + suffix: "increased Physical Damage / to Accuracy Rating" + "to Accuracy Rating"
  1610. ARPartial =
  1611. ARAffixTypePartial =
  1612.  
  1613. ; Partial for Block and Stun Recovery
  1614. BSRecPartial =
  1615.  
  1616. ; --- PRE-PASS ---
  1617.  
  1618. ; to determine composition flags
  1619. Loop, Parse, ItemDataChunk, `n, `r
  1620. {
  1621. If StrLen(A_LoopField) = 0
  1622. {
  1623. Break ; not interested in blank lines
  1624. }
  1625. IfInString, ItemDataChunk, Unidentified
  1626. {
  1627. Break ; not interested in unidentified items
  1628. }
  1629.  
  1630. NumAffixLines += 1
  1631.  
  1632. IfInString, A_LoopField, increased Light Radius
  1633. {
  1634. HasIncrLightRadius := A_Index
  1635. Continue
  1636. }
  1637. IfInString, A_LoopField, increased Quantity
  1638. {
  1639. HasIIQ := A_Index
  1640. Continue
  1641. }
  1642. IfInString, A_LoopField, increased Physical Damage
  1643. {
  1644. HasIncrPhysDmg := A_Index
  1645. Continue
  1646. }
  1647. IfInString, A_LoopField, increased Accuracy Rating
  1648. {
  1649. HasIncrAccuracyRating := A_Index
  1650. Continue
  1651. }
  1652. IfInString, A_LoopField, to Accuracy Rating
  1653. {
  1654. HasToAccuracyRating := A_Index
  1655. Continue
  1656. }
  1657. IfInString, A_LoopField, increased Armour and Evasion
  1658. {
  1659. HasHybridDefences := A_Index
  1660. HasIncrArmourAndEvasion := A_Index
  1661. Continue
  1662. }
  1663. IfInString, A_LoopField, increased Armour and Energy Shield
  1664. {
  1665. HasHybridDefences := A_Index
  1666. HasIncrArmourAndES := A_Index
  1667. Continue
  1668. }
  1669. IfInString, A_LoopField, increased Evasion and Energy Shield
  1670. {
  1671. HasHybridDefences := A_Index
  1672. HasIncrEvasionAndES := A_Index
  1673. Continue
  1674. }
  1675. IfInString, A_LoopField, increased Armour
  1676. {
  1677. HasIncrArmour := A_Index
  1678. Continue
  1679. }
  1680. IfInString, A_LoopField, increased Evasion Rating
  1681. {
  1682. HasIncrEvasion := A_Index
  1683. Continue
  1684. }
  1685. IfInString, A_LoopField, increased Energy Shield
  1686. {
  1687. HasIncrEnergyShield := A_Index
  1688. Continue
  1689. }
  1690. IfInString, A_LoopField, increased Block and Stun Recovery
  1691. {
  1692. HasStunRecovery := A_Index
  1693. Continue
  1694. }
  1695. IfInString, A_LoopField, increased Spell Damage
  1696. {
  1697. HasSpellDamage := A_Index
  1698. Continue
  1699. }
  1700. IfInString, A_LoopField, to maximum Mana
  1701. {
  1702. HasMaxMana := A_Index
  1703. Continue
  1704. }
  1705. }
  1706.  
  1707. ; Reset the AffixLines "array" and other vars
  1708. ResetAffixDetailVars()
  1709.  
  1710. ; --- SIMPLE AFFIXES ---
  1711.  
  1712. Loop, Parse, ItemDataChunk, `n, `r
  1713. {
  1714. If StrLen(A_LoopField) = 0
  1715. {
  1716. Break ; not interested in blank lines
  1717. }
  1718. IfInString, ItemDataChunk, Unidentified
  1719. {
  1720. Break ; not interested in unidentified items
  1721. }
  1722.  
  1723. MarkedAsGuess := False
  1724.  
  1725. ; msgbox, % ItemDataChunk
  1726.  
  1727. ; Note: yes, this superlong IfInString structure sucks
  1728. ; but hey, AHK sucks as a scripting language, so bite me.
  1729. ; But in all seriousness, the incrementing parts could be
  1730. ; covered with one label+goto per affix type but I decided
  1731. ; not to because the if bodies are actually placeholders
  1732. ; for a system that looks up max and min values possible
  1733. ; per affix from a collection of text files. The latter is
  1734. ; a TODO for a future version of the script though.
  1735.  
  1736. ; Global CurrValue ; d
  1737. CurrValue := GetActualValue(A_LoopField)
  1738. CurrTier := 0
  1739. BracketLevel := 0
  1740.  
  1741. ;msgbox, CurrTier: %CurrTier%
  1742.  
  1743. ; Suffixes
  1744.  
  1745. IfInString, A_LoopField, 攻擊速度
  1746. {
  1747. NumSuffixes += 1
  1748. If (ItemBaseType == "Weapon") ; ItemBaseType is Global!
  1749. {
  1750. ValueRange := LookupAffixData("data\AttackSpeed_Weapons.txt", ItemLevel, CurrValue, "", CurrTier)
  1751. }
  1752. Else
  1753. {
  1754. ValueRange := LookupAffixData("data\AttackSpeed_ArmourAndItems.txt", ItemLevel, CurrValue, "", CurrTier)
  1755. }
  1756. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1757. Continue
  1758. }
  1759. IfInString, A_LoopField, 照亮範圍
  1760. {
  1761. AffixType := "Comp. Suffix"
  1762. ValueRange := LookupAffixData("data\IncrAccuracyRating_LightRadius.txt", ItemLevel, CurrValue, "", CurrTier)
  1763. NumSuffixes += 1
  1764. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  1765. Continue
  1766. }
  1767.  
  1768. IfInString, A_LoopField, 全能力
  1769. {
  1770. NumSuffixes += 1
  1771. ValueRange := LookupAffixData("data\ToAllAttributes.txt", ItemLevel, CurrValue, "", CurrTier)
  1772. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1773. Continue
  1774. }
  1775. IfInString, A_LoopField, 力量
  1776. {
  1777. NumSuffixes += 1
  1778. ValueRange := LookupAffixData("data\ToStrength.txt", ItemLevel, CurrValue, "", CurrTier)
  1779. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1780. Continue
  1781. }
  1782. IfInString, A_LoopField, 智慧
  1783. {
  1784. NumSuffixes += 1
  1785. ValueRange := LookupAffixData("data\ToIntelligence.txt", ItemLevel, CurrValue, "", CurrTier)
  1786. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1787. Continue
  1788. }
  1789. IfInString, A_LoopField, 敏捷
  1790. {
  1791. NumSuffixes += 1
  1792. ValueRange := LookupAffixData("data\ToDexterity.txt", ItemLevel, CurrValue, "", CurrTier)
  1793. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1794. Continue
  1795. }
  1796. IfInString, A_LoopField, 施法速度
  1797. {
  1798. NumSuffixes += 1
  1799. ValueRange := LookupAffixData("data\CastSpeed.txt", ItemLevel, CurrValue, "", CurrTier)
  1800. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1801. Continue
  1802. }
  1803. ; This needs to come before "Critical Strike Chance" !
  1804. IfInString, A_LoopField, 全域法術暴擊率
  1805. {
  1806. NumSuffixes += 1
  1807. ValueRange := LookupAffixData("data\SpellCritChance.txt", ItemLevel, CurrValue, "", CurrTier)
  1808. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1809. Continue
  1810. }
  1811. IfInString, A_LoopField, 暴擊率
  1812. {
  1813. If (ItemSubType == "Quiver" or ItemSubType == "Amulet")
  1814. {
  1815. ValueRange := LookupAffixData("data\CritChance_AmuletsAndQuivers.txt", ItemLevel, CurrValue, "", CurrTier)
  1816. }
  1817. Else
  1818. {
  1819. ValueRange := LookupAffixData("data\CritChance_Weapons.txt", ItemLevel, CurrValue, "", CurrTier)
  1820. }
  1821. NumSuffixes += 1
  1822. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1823. Continue
  1824. }
  1825. IfInString, A_LoopField, 全域暴擊加成
  1826. {
  1827. If (ItemSubType == "Quiver" or ItemSubType == "Amulet")
  1828. {
  1829. ValueRange := LookupAffixData("data\CritMultiplier_AmuletsAndQuivers.txt", ItemLevel, CurrValue, "", CurrTier)
  1830. }
  1831. Else
  1832. {
  1833. ValueRange := LookupAffixData("data\CritMultiplier_Weapons.txt", ItemLevel, CurrValue, "", CurrTier)
  1834. }
  1835. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1836. NumSuffixes += 1
  1837. Continue
  1838. }
  1839. IfInString, A_LoopField, 火焰傷害
  1840. {
  1841. NumPrefixes += 1
  1842. ValueRange := LookupAffixData("data\IncrFireDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  1843. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  1844. Continue
  1845. }
  1846. IfInString, A_LoopField, 冰冷傷害
  1847. {
  1848. NumPrefixes += 1
  1849. ValueRange := LookupAffixData("data\IncrColdDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  1850. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  1851. Continue
  1852. }
  1853. IfInString, A_LoopField, 閃電傷害
  1854. {
  1855. NumPrefixes += 1
  1856. ValueRange := LookupAffixData("data\IncrLightningDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  1857. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  1858. Continue
  1859. }
  1860. IfInString, A_LoopField, 閃電 Radius
  1861. {
  1862. ValueRange := LookupAffixData("data\LightRadius_AccuracyRating.txt", ItemLevel, CurrValue, "", CurrTier)
  1863. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Comp. Suffix", ValueRange, CurrTier), A_Index)
  1864. Continue
  1865. }
  1866. IfInString, A_LoopField, 格檔機率
  1867. {
  1868. NumSuffixes += 1
  1869. ValueRange := LookupAffixData("data\BlockChance.txt", ItemLevel, CurrValue, "", CurrTier)
  1870. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1871. Continue
  1872. }
  1873.  
  1874. ; Flask effects (on belts)
  1875. IfInString, A_LoopField, 減少使用藥水充能量
  1876. {
  1877. NumSuffixes += 1
  1878. ValueRange := LookupAffixData("data\FlaskChargesUsed.txt", ItemLevel, CurrValue, "", CurrTier)
  1879. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1880. Continue
  1881. }
  1882. IfInString, A_LoopField, 增加藥水充能上限
  1883. {
  1884. NumSuffixes += 1
  1885. ValueRange := LookupAffixData("data\FlaskChargesGained.txt", ItemLevel, CurrValue, "", CurrTier)
  1886. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1887. Continue
  1888. }
  1889. IfInString, A_LoopField, 藥劑使用期間
  1890. {
  1891. NumSuffixes += 1
  1892. ValueRange := LookupAffixData("data\FlaskDuration.txt", ItemLevel, CurrValue, "", CurrTier)
  1893. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1894. Continue
  1895. }
  1896.  
  1897. ; Flasks Suffixes
  1898. ; only applicable to *drumroll* ... flasks
  1899. IfInString, A_LoopField, Dispels
  1900. {
  1901. ; covers Shock, Burning and Frozen and Chilled
  1902. If (NumSuffixes < 1)
  1903. {
  1904. NumSuffixes += 1
  1905. }
  1906. Continue
  1907. }
  1908. IfInString, A_LoopField, 移除放血
  1909. {
  1910. If (NumSuffixes < 1)
  1911. {
  1912. NumSuffixes += 1
  1913. }
  1914. Continue
  1915. }
  1916. IfInString, A_LoopField, 移除詛咒
  1917. {
  1918. If (NumSuffixes < 1)
  1919. {
  1920. NumSuffixes += 1
  1921. }
  1922. Continue
  1923. }
  1924. IfInString, A_LoopField, 藥劑使用期間
  1925. {
  1926. If (NumSuffixes < 1)
  1927. {
  1928. NumSuffixes += 1
  1929. }
  1930. Continue
  1931. }
  1932. IfInString, A_LoopField, Adds Knockback
  1933. {
  1934. If (NumSuffixes < 1)
  1935. {
  1936. NumSuffixes += 1
  1937. }
  1938. Continue
  1939. }
  1940. IfInString, A_LoopField, Life Recovery to Minions
  1941. {
  1942. If (NumSuffixes < 1)
  1943. {
  1944. NumSuffixes += 1
  1945. }
  1946. Continue
  1947. }
  1948. ; END Flask Suffixes
  1949.  
  1950. IfInString, A_LoopField, 物品數量
  1951. {
  1952. NumSuffixes += 1
  1953. ValueRange := LookupAffixData("data\IIQ.txt", ItemLevel, CurrValue, "", CurrTier)
  1954. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1955. Continue
  1956. }
  1957. IfInString, A_LoopField, 擊殺回復生命
  1958. {
  1959. NumSuffixes += 1
  1960. ValueRange := LookupAffixData("data\LifeOnKill.txt", ItemLevel, CurrValue, "", CurrTier)
  1961. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1962. Continue
  1963. }
  1964. IfInString, A_LoopField, 擊中回復生命
  1965. {
  1966. NumSuffixes += 1
  1967. ValueRange := LookupAffixData("data\LifeOnHit.txt", ItemLevel, CurrValue, "", CurrTier)
  1968. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1969. Continue
  1970. }
  1971. IfInString, A_LoopField, 每秒生命回復
  1972. {
  1973. NumSuffixes += 1
  1974. ValueRange := LookupAffixData("data\LifeRegen.txt", ItemLevel, CurrValue, "", CurrTier)
  1975. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1976. Continue
  1977. }
  1978. IfInString, A_LoopField, 擊殺回復魔力
  1979. {
  1980. ; Not a typo: 'G' in Gained is capital here as opposed to 'Life gained'
  1981. NumSuffixes += 1
  1982. ValueRange := LookupAffixData("data\ManaOnKill.txt", ItemLevel, CurrValue, "", CurrTier)
  1983. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1984. Continue
  1985. }
  1986. IfInString, A_LoopField, 魔力回復速度
  1987. {
  1988. NumSuffixes += 1
  1989. ValueRange := LookupAffixData("data\ManaRegen.txt", ItemLevel, CurrValue, "", CurrTier)
  1990. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1991. Continue
  1992. }
  1993. IfInString, A_LoopField, 投射物速度
  1994. {
  1995. NumSuffixes += 1
  1996. ValueRange := LookupAffixData("data\ProjectileSpeed.txt", ItemLevel, CurrValue, "", CurrTier)
  1997. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  1998. Continue
  1999. }
  2000. IfInString, A_LoopField, 能力值需求
  2001. {
  2002. NumSuffixes += 1
  2003. ValueRange := LookupAffixData("data\ReducedAttrReqs.txt", ItemLevel, CurrValue, "", CurrTier)
  2004. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2005. Continue
  2006. }
  2007. IfInString, A_LoopField, 全部元素抗性
  2008. {
  2009. NumSuffixes += 1
  2010. ValueRange := LookupAffixData("data\AllResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2011. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2012. Continue
  2013. }
  2014. IfInString, A_LoopField, 火焰抗性
  2015. {
  2016. NumSuffixes += 1
  2017. ValueRange := LookupAffixData("data\FireResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2018. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2019. Continue
  2020. }
  2021. IfInString, A_LoopField, 閃電抗性
  2022. {
  2023. NumSuffixes += 1
  2024. ValueRange := LookupAffixData("data\LightningResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2025. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2026. Continue
  2027. }
  2028. IfInString, A_LoopField, 冰冷抗性
  2029. {
  2030. NumSuffixes += 1
  2031. ValueRange := LookupAffixData("data\ColdResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2032. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2033. Continue
  2034. }
  2035. IfInString, A_LoopField, 混沌抗性
  2036. {
  2037. NumSuffixes += 1
  2038. ValueRange := LookupAffixData("data\ChaosResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2039. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2040. Continue
  2041. }
  2042. If RegExMatch(A_LoopField, ".*to (冰冷|火焰|閃電) 和 (冰冷|火焰|閃電) 抗性")
  2043. {
  2044. ; Catches two-stone rings and the like which have "+#% to Cold and Lightning Resistances"
  2045. IfInString, A_LoopField, 火焰
  2046. {
  2047. NumSuffixes += 1
  2048. ValueRange := LookupAffixData("data\FireResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2049. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2050. Continue
  2051. }
  2052. IfInString, A_LoopField, 閃電
  2053. {
  2054. NumSuffixes += 1
  2055. ValueRange := LookupAffixData("data\LightningResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2056. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2057. Continue
  2058. }
  2059. IfInString, A_LoopField, 冰冷
  2060. {
  2061. NumSuffixes += 1
  2062. ValueRange := LookupAffixData("data\ColdResist.txt", ItemLevel, CurrValue, "", CurrTier)
  2063. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2064. Continue
  2065. }
  2066. }
  2067. IfInString, A_LoopField, 暈眩回復
  2068. {
  2069. NumSuffixes += 1
  2070. ValueRange := LookupAffixData("data\StunDuration.txt", ItemLevel, CurrValue, "", CurrTier)
  2071. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2072. Continue
  2073. }
  2074. IfInString, A_LoopField, 敵人暈眩門檻
  2075. {
  2076. NumSuffixes += 1
  2077. ValueRange := LookupAffixData("data\StunThreshold.txt", ItemLevel, CurrValue, "", CurrTier)
  2078. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  2079. Continue
  2080. }
  2081.  
  2082. ; Prefixes
  2083.  
  2084. IfInString, A_LoopField, 護甲
  2085. {
  2086. NumPrefixes += 1
  2087. If (ItemBaseType == "Item")
  2088. {
  2089. ; Global
  2090. ValueRange := LookupAffixData("data\ToArmour_Items.txt", ItemLevel, CurrValue, "", CurrTier)
  2091. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2092. }
  2093. Else
  2094. {
  2095. ; Local
  2096. ValueRange := LookupAffixData("data\ToArmour_WeaponsAndArmour.txt", ItemLevel, CurrValue, "", CurrTier)
  2097. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2098. }
  2099. Continue
  2100. }
  2101. IfInString, A_LoopField, 護甲和閃避
  2102. {
  2103. AffixType := "Prefix"
  2104. AEBracketLevel := 0
  2105. ValueRange := LookupAffixData("data\ArmourAndEvasion.txt", ItemLevel, CurrValue, AEBracketLevel, CurrTier)
  2106. If (HasStunRecovery)
  2107. {
  2108. AEBracketLevel2 := AEBracketLevel
  2109.  
  2110. AEBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, AEBracketLevel2)
  2111. If (Not IsValidRange(ValueRange) AND IsValidBracket(AEBracket))
  2112. {
  2113. ValueRange := LookupAffixData("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, AEBracketLevel2, CurrTier)
  2114. }
  2115. AffixType := "Comp. Prefix"
  2116. BSRecBracketLevel := 0
  2117. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2118. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", AEBracketLevel2, "", BSRecBracketLevel)
  2119. If (Not IsValidRange(ValueRange))
  2120. {
  2121. ValueRange := LookupAffixData(PrefixPathOther, ItemLevel, CurrValue, AEBracketLevel, CurrTier)
  2122. }
  2123. If (Not IsValidBracket(BSRecPartial))
  2124. {
  2125. ; This means that we are actually dealing with a Prefix + Comp. Prefix.
  2126. ; To get the part for the hybrid defence that is contributed by the straight prefix,
  2127. ; lookup the bracket level for the B&S Recovery line and then work out the partials
  2128. ; for the hybrid stat from the bracket level of B&S.
  2129. ; Example:
  2130. ; 87% increased Armour and Evasion
  2131. ; 7% increased Block and Stun Recovery
  2132. ;
  2133. ; 1) 7% B&S indicates bracket level 2 (6-7)
  2134. ; 2) lookup bracket level 2 from the hybrid stat + block and stun recovery table
  2135. ; This works out to be 6-14.
  2136. ; 3) subtract 6-14 from 87 to get the rest contributed by the hybrid stat as pure prefix.
  2137. ; Currently when subtracting a range from a single value we just use the range's
  2138. ; max as single value. This may need changing depending on circumstance but it
  2139. ; works for now. EDIT: no longer the case, now uses RangeMid(...). #'s below changed to
  2140. ; reflect that...
  2141. ; 87-10 = 77
  2142. ; 4) lookup affix data for increased Armour and Evasion with value of 77
  2143. ; We now know, this is a Comp. Prefix+Prefix
  2144. BSRecBracketLevel := 0
  2145. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2146. If (Not IsValidBracket(BSRecPartial))
  2147. {
  2148. ; This means that the hybrid stat is a Comp. Prefix+Prefix and BS rec is a Comp. Prefix+Suffix
  2149. ; This is ambiguous and tough to resolve, but we'll try anyway...
  2150. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, "", BSRecBracketLevel)
  2151. }
  2152. ; msgbox, BSRecValue: %BSRecValue%`, BSRecBracketLevel: %BSRecBracketLevel%`, BSRecPartial: %BSRecPartial%
  2153.  
  2154. AEBSBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", BSRecBracketLevel)
  2155.  
  2156. ; msgbox, AEBSBracket: %AEBSBracket%
  2157. If (Not WithinBounds(AEBSBracket, CurrValue))
  2158. {
  2159. AERest := CurrValue - RangeMid(AEBSBracket)
  2160. AEBracket := LookupAffixBracket("data\ArmourAndEvasion.txt", ItemLevel, AERest)
  2161. ; msgbox, AEBracket: %AEBracket%`, AEBSBracket: %AEBSBracket%`,AERest: %AERest%
  2162.  
  2163. If (Not IsValidBracket(AEBracket))
  2164. {
  2165. AEBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue)
  2166. }
  2167. If (Not WithinBounds(AEBracket, CurrValue))
  2168. {
  2169. ValueRange := AddRange(AEBSBracket, AEBracket)
  2170. ValueRange := MarkAsGuesstimate(ValueRange)
  2171. AffixType := "Comp. Prefix+Prefix"
  2172. NumPrefixes += 1
  2173. }
  2174. }
  2175.  
  2176. If (WithinBounds(BSRecPartial, BSRecValue))
  2177. {
  2178. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2179. BSRecPartial =
  2180. }
  2181. }
  2182. }
  2183. NumPrefixes += 1
  2184. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2185. Continue
  2186. }
  2187. IfInString, A_LoopField, 護甲和能量護盾
  2188. {
  2189. AffixType := "Prefix"
  2190. AESBracketLevel := 0
  2191. ValueRange := LookupAffixData("data\ArmourAndEnergyShield.txt", ItemLevel, CurrValue, AESBracketLevel, CurrTier)
  2192. If (HasStunRecovery)
  2193. {
  2194. AESBracketLevel2 := AESBracketLevel
  2195.  
  2196. AESBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, AESBracketLevel2)
  2197. If (Not IsValidRange(ValueRange) AND IsValidBracket(AESBracket))
  2198. {
  2199. ValueRange := LookupAffixData("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, AESBracketLevel2, CurrTier)
  2200. }
  2201. AffixType := "Comp. Prefix"
  2202. BSRecBracketLevel := 0
  2203. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2204. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", AESBracketLevel2, "", BSRecBracketLevel)
  2205. If (Not IsValidBracket(BSRecPartial))
  2206. {
  2207. BSRecPartial := LookupAffixBracket("data\StunRecovery_Armour.txt", AESBracketLevel, "", BSRecBracketLevel)
  2208. }
  2209. If (Not IsValidBracket(BSRecPartial))
  2210. {
  2211. BSRecBracketLevel := 0
  2212. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2213. If (Not IsValidBracket(BSRecPartial))
  2214. {
  2215. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, "", BSRecBracketLevel)
  2216. }
  2217.  
  2218. AESBSBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", BSRecBracketLevel)
  2219.  
  2220. If (Not WithinBounds(AESBSBracket, CurrValue))
  2221. {
  2222. AESRest := CurrValue - RangeMid(AESBSBracket)
  2223. AESBracket := LookupAffixBracket("data\ArmourAndEnergyShield.txt", ItemLevel, AESRest)
  2224.  
  2225. If (Not IsValidBracket(AESBracket))
  2226. {
  2227. AESBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue)
  2228. }
  2229. If (Not WithinBounds(AESBracket, CurrValue))
  2230. {
  2231. ValueRange := AddRange(AESBSBracket, AESBracket)
  2232. ValueRange := MarkAsGuesstimate(ValueRange)
  2233. AffixType := "Comp. Prefix+Prefix"
  2234. NumPrefixes += 1
  2235. }
  2236. }
  2237. If (WithinBounds(BSRecPartial, BSRecValue))
  2238. {
  2239. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2240. BSRecPartial =
  2241. }
  2242. }
  2243. }
  2244. NumPrefixes += 1
  2245. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2246. Continue
  2247. }
  2248. IfInString, A_LoopField, 閃避和能量護盾
  2249. {
  2250. AffixType := "Prefix"
  2251. EESBracketLevel := 0
  2252. ValueRange := LookupAffixData("data\EvasionAndEnergyShield.txt", ItemLevel, CurrValue, EESBracketLevel, CurrTier)
  2253. If (HasStunRecovery)
  2254. {
  2255. EESBracketLevel2 := EESBracketLevel
  2256.  
  2257. EESBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, EESBracketLevel2)
  2258. If (Not IsValidRange(ValueRange) AND IsValidBracket(EESBracket))
  2259. {
  2260. ValueRange := LookupAffixData("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue, EESBracketLevel2, CurrTier)
  2261. }
  2262.  
  2263. AffixType := "Comp. Prefix"
  2264. BSRecBracketLevel := 0
  2265. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2266. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", EESBracketLevel2, "", BSRecBracketLevel)
  2267. If (Not IsValidBracket(BSRecPartial))
  2268. {
  2269. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", EESBracketLevel, "", BSRecBracketLevel)
  2270. }
  2271. If (Not IsValidBracket(BSRecPartial))
  2272. {
  2273. BSRecBracketLevel := 0
  2274. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2275. If (Not IsValidBracket(BSRecPartial))
  2276. {
  2277. BSRecPartial := LookupAffixBracket("data\StunRecovery_Hybrid.txt", ItemLevel, "", BSRecBracketLevel)
  2278. }
  2279.  
  2280. EESBSBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", BSRecBracketLevel)
  2281.  
  2282. If (Not WithinBounds(EESBSBracket, CurrValue))
  2283. {
  2284. EESRest := CurrValue - RangeMid(EESBSBracket)
  2285. EESBracket := LookupAffixBracket("data\EvasionAndEnergyShield.txt", ItemLevel, EESRest)
  2286.  
  2287. If (Not IsValidBracket(EESBracket))
  2288. {
  2289. EESBracket := LookupAffixBracket("data\HybridDefences_StunRecovery.txt", ItemLevel, CurrValue)
  2290. }
  2291. If (Not WithinBounds(EESBracket, CurrValue))
  2292. {
  2293. ValueRange := AddRange(EESBSBracket, EESBracket)
  2294. ValueRange := MarkAsGuesstimate(ValueRange)
  2295. AffixType := "Comp. Prefix+Prefix"
  2296. NumPrefixes += 1
  2297. }
  2298. }
  2299.  
  2300. If (WithinBounds(BSRecPartial, BSRecValue))
  2301. {
  2302. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2303. BSRecPartial =
  2304. }
  2305. }
  2306. }
  2307. NumPrefixes += 1
  2308. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2309. Continue
  2310. }
  2311. IfInString, A_LoopField, 護甲2
  2312. {
  2313. AffixType := "Prefix"
  2314. IABracketLevel := 0
  2315. If (ItemBaseType == "Item")
  2316. {
  2317. ; Global
  2318. PrefixPath := "data\IncrArmour_Items.txt"
  2319. PrefixPathOther := "data\IncrArmour_WeaponsAndArmour.txt"
  2320. }
  2321. Else
  2322. {
  2323. ; Local
  2324. PrefixPath := "data\IncrArmour_WeaponsAndArmour.txt"
  2325. PrefixPathOther := "data\IncrArmour_Items.txt"
  2326. }
  2327. ValueRange := LookupAffixData(PrefixPath, ItemLevel, CurrValue, IABracketLevel, CurrTier)
  2328. If (Not IsValidRange(ValueRange))
  2329. {
  2330. ValueRange := LookupAffixData(PrefixPathOther, ItemLevel, CurrValue, IABracketLevel, CurrTier)
  2331. }
  2332. If (HasStunRecovery)
  2333. {
  2334. IABracketLevel2 := IABracketLevel
  2335.  
  2336. ASRBracket := LookupAffixBracket("data\Armour_StunRecovery.txt", ItemLevel, CurrValue, IABracketLevel2)
  2337. If (Not IsValidRange(ValueRange) AND IsValidBracket(ASRBracket))
  2338. {
  2339. ValueRange := LookupAffixData("data\Armour_StunRecovery.txt", ItemLevel, CurrValue, IABracketLevel2, CurrTier)
  2340. }
  2341.  
  2342. AffixType := "Comp. Prefix"
  2343. BSRecBracketLevel := 0
  2344. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2345. BSRecPartial := LookupAffixBracket("data\StunRecovery_Armour.txt", IABracketLevel2, "", BSRecBracketLevel)
  2346. ;msgbox, IABracketLevel: %IABracketLevel%`, BSRecValue: %BSRecValue%`, BSRecBracketLevel: %BSRecBracketLevel%`, BSRecPartial: %BSRecPartial%
  2347. If (Not IsValidBracket(BSRecPartial))
  2348. {
  2349. BSRecPartial := LookupAffixBracket("data\StunRecovery_Armour.txt", IABracketLevel, "", BSRecBracketLevel)
  2350. }
  2351. If (Not IsValidBracket(BSRecPartial))
  2352. {
  2353. BSRecBracketLevel := 0
  2354. BSRecPartial := LookupAffixBracket("data\StunRecovery_Armour.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2355. If (Not IsValidBracket(BSRecPartial))
  2356. {
  2357. BSRecPartial := LookupAffixBracket("data\StunRecovery_Armour.txt", ItemLevel, "", BSRecBracketLevel)
  2358. }
  2359. ;msgbox, BSRecValue: %BSRecValue%`, BSRecBracketLevel: %BSRecBracketLevel%`, BSRecPartial: %BSRecPartial%
  2360.  
  2361. IABSBracket := LookupAffixBracket("data\Armour_StunRecovery.txt", BSRecBracketLevel)
  2362.  
  2363. If (Not WithinBounds(IABSBracket, CurrValue))
  2364. {
  2365. IARest := CurrValue - RangeMid(IABSBracket)
  2366. IABracket := LookupAffixBracket(PrefixPath, ItemLevel, IARest)
  2367. ;msgbox, IABracket: %IABracket%`, IABSBracket: %IABSBracket%`, IARest: %IARest%
  2368. If (Not IsValidBracket(IABracket))
  2369. {
  2370. IABracket := LookupAffixBracket(PrefixPath, ItemLevel, CurrValue)
  2371. }
  2372. If (Not WithinBounds(IABracket, CurrValue))
  2373. {
  2374. ValueRange := AddRange(IABSBracket, IABracket)
  2375. ValueRange := MarkAsGuesstimate(ValueRange)
  2376. AffixType := "Comp. Prefix+Prefix"
  2377. NumPrefixes += 1
  2378. }
  2379. }
  2380.  
  2381. If (WithinBounds(BSRecPartial, BSRecValue))
  2382. {
  2383. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2384. BSRecPartial =
  2385. }
  2386. }
  2387. }
  2388. NumPrefixes += 1
  2389. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2390. Continue
  2391. }
  2392. IfInString, A_LoopField, 閃避2
  2393. {
  2394. NumPrefixes += 1
  2395. If (ItemBaseType == "Item")
  2396. {
  2397. ValueRange := LookupAffixData("data\ToEvasion_Items.txt", ItemLevel, CurrValue, "", CurrTier)
  2398. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2399. }
  2400. Else
  2401. {
  2402. ValueRange := LookupAffixData("data\ToEvasion_Armour.txt", ItemLevel, CurrValue, "", CurrTier)
  2403. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2404. }
  2405. Continue
  2406. }
  2407. IfInString, A_LoopField, 閃避3
  2408. {
  2409. AffixType := "Prefix"
  2410. IEBracketLevel := 0
  2411. If (ItemBaseType == "Item")
  2412. {
  2413. ; Global
  2414. PrefixPath := "data\IncrEvasion_Items.txt"
  2415. PrefixPathOther := "data\IncrEvasion_Armour.txt"
  2416. }
  2417. Else
  2418. {
  2419. ; Local
  2420. PrefixPath := "data\IncrEvasion_Armour.txt"
  2421. PrefixPathOther := "data\IncrEvasion_Items.txt"
  2422. }
  2423. ValueRange := LookupAffixData(PrefixPath, ItemLevel, CurrValue, IEBracketLevel, CurrTier)
  2424. If (Not IsValidRange(ValueRange))
  2425. {
  2426. ValueRange := LookupAffixData(PrefixPathOther, ItemLevel, CurrValue, IEBracketLevel, CurrTier)
  2427. }
  2428. If (HasStunRecovery)
  2429. {
  2430. IEBracketLevel2 := IEBracketLevel
  2431.  
  2432. ; determine composite bracket level and store in IEBracketLevel2, for example:
  2433. ; 8% increased Evasion, 26% increased Block and Stun Recover =>
  2434. ; 8% is bracket level 2 (6-14), so 'B+S Rec from Evasion' level 2 makes BSRec partial 6-7
  2435. ERSRBracket := LookupAffixBracket("data\Evasion_StunRecovery.txt", ItemLevel, CurrValue, IEBracketLevel2)
  2436. If (Not IsValidRange(ValueRange) AND IsValidBracket(ERSRBracket))
  2437. {
  2438. ValueRange := LookupAffixData("data\Evasion_StunRecovery.txt", ItemLevel, CurrValue, IEBracketLevel2, CurrTier)
  2439. }
  2440.  
  2441. AffixType := "Comp. Prefix"
  2442. BSRecBracketLevel := 0
  2443. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2444. BSRecPartial := LookupAffixBracket("data\StunRecovery_Evasion.txt", IEBracketLevel2, "", BSRecBracketLevel)
  2445. ;msgbox, IEBracketLevel: %IEBracketLevel%`, ValueRange: %ValueRange%, BSRecPartial: %BSRecPartial%, BSRecValue: %BSRecValue%, IEBracketLevel: %IEBracketLevel%
  2446. If (Not IsValidBracket(BSRecPartial))
  2447. {
  2448. BSRecPartial := LookupAffixBracket("data\StunRecovery_Evasion.txt", IEBracketLevel, "", BSRecBracketLevel)
  2449. }
  2450. If (Not IsValidRange(ValueRange) and (Not IsValidBracket(BSRecPartial) or Not WithinBounds(BSRecPartial, BSRecValue)))
  2451. {
  2452. BSRecBracketLevel := 0
  2453. BSRecPartial := LookupAffixBracket("data\StunRecovery_Evasion.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2454. If (Not IsValidBracket(BSRecPartial))
  2455. {
  2456. BSRecPartial := LookupAffixBracket("data\StunRecovery_Evasion.txt", ItemLevel, "", BSRecBracketLevel)
  2457. }
  2458.  
  2459. IEBSBracket := LookupAffixBracket("data\Evasion_StunRecovery.txt", BSRecBracketLevel)
  2460.  
  2461. If (Not WithinBounds(IEBSBracket, CurrValue))
  2462. {
  2463. IERest := CurrValue - RangeMid(IEBSBracket)
  2464. IEBracket := LookupAffixBracket(PrefixPath, ItemLevel, IERest)
  2465. If (Not IsValidBracket(IEBracket))
  2466. {
  2467. IEBracket := LookupAffixBracket(PrefixPath, ItemLevel, CurrValue, "")
  2468. }
  2469. If (Not WithinBounds(IEBracket, CurrValue))
  2470. {
  2471. ; msgbox, IEBracket: %IEBracket%, IEBSBracket: %IEBSBracket%
  2472. ValueRange := AddRange(IEBSBracket, IEBracket)
  2473. ValueRange := MarkAsGuesstimate(ValueRange)
  2474. AffixType := "Comp. Prefix+Prefix"
  2475. NumPrefixes += 1
  2476. }
  2477. }
  2478.  
  2479. If (WithinBounds(BSRecPartial, BSRecValue))
  2480. {
  2481. ; msgbox, BSRecPartial: %BSRecPartial%, BSRecValue: %BSRecValue%
  2482. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2483. BSRecPartial =
  2484. }
  2485. }
  2486. }
  2487. NumPrefixes += 1
  2488. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2489. Continue
  2490. }
  2491. IfInString, A_LoopField, 最大能量護盾
  2492. {
  2493. PrefixType := "Prefix"
  2494. If (ItemSubType == "Ring" or ItemSubType == "Amulet" or ItemSubType == "Belt")
  2495. {
  2496. ValueRange := LookupAffixData("data\ToMaxEnergyShield.txt", ItemLevel, CurrValue, "", CurrTier)
  2497. }
  2498. Else
  2499. {
  2500. ValueRange := LookupAffixData("data\ToEnergyShield.txt", ItemLevel, CurrValue, "", CurrTier)
  2501.  
  2502. }
  2503. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2504. NumPrefixes += 1
  2505. Continue
  2506. }
  2507. IfInString, A_LoopField, 能量護盾
  2508. {
  2509. AffixType := "Prefix"
  2510. IESBracketLevel := 0
  2511. PrefixPath := "data\IncrEnergyShield.txt"
  2512. ValueRange := LookupAffixData(PrefixPath, ItemLevel, CurrValue, IESBracketLevel, CurrTier)
  2513.  
  2514. If (HasStunRecovery)
  2515. {
  2516. IESBracketLevel2 := IESBracketLevel
  2517.  
  2518. ESSRBracket := LookupAffixBracket("data\EnergyShield_StunRecovery.txt", ItemLevel, CurrValue, IESBracketLevel2)
  2519. If (Not IsValidRange(ValueRange) AND IsValidBracket(ESSRBracket))
  2520. {
  2521. ValueRange := LookupAffixData("data\EnergyShield_StunRecovery.txt", ItemLevel, CurrValue, IESBracketLevel2, CurrTier)
  2522. }
  2523.  
  2524. AffixType := "Comp. Prefix"
  2525. BSRecBracketLevel := 0
  2526. BSRecPartial := LookupAffixBracket("data\StunRecovery_EnergyShield.txt", IESBracketLevel2, "", BSRecBracketLevel)
  2527. BSRecValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Block and Stun Recovery")
  2528. If (Not IsValidBracket(BSRecPartial))
  2529. {
  2530. BSRecPartial := LookupAffixBracket("data\StunRecovery_EnergyShield.txt", IESBracketLevel, "", BSRecBracketLevel)
  2531. }
  2532. If (Not IsValidBracket(BSRecPartial))
  2533. {
  2534. BSRecBracketLevel := 0
  2535. BSRecPartial := LookupAffixBracket("data\StunRecovery_EnergyShield.txt", ItemLevel, BSRecValue, BSRecBracketLevel)
  2536. If (Not IsValidBracket(BSRecPartial))
  2537. {
  2538. BSRecPartial := LookupAffixBracket("data\StunRecovery_EnergyShield.txt", ItemLevel, "", BSRecBracketLevel)
  2539. }
  2540. IESBSBracket := LookupAffixBracket("data\EnergyShield_StunRecovery.txt", BSRecBracketLevel)
  2541.  
  2542. If (Not WithinBounds(IEBSBracket, CurrValue))
  2543. {
  2544. IESRest := CurrValue - RangeMid(IESBSBracket)
  2545. IESBracket := LookupAffixBracket(PrefixPath, ItemLevel, IESRest)
  2546.  
  2547. If (Not WithinBounds(IESBracket, CurrValue))
  2548. {
  2549. ValueRange := AddRange(IESBSBracket, IESBracket)
  2550. ValueRange := MarkAsGuesstimate(ValueRange)
  2551. AffixType := "Comp. Prefix+Prefix"
  2552. NumPrefixes += 1
  2553. }
  2554. }
  2555.  
  2556. If (WithinBounds(BSRecPartial, BSRecValue))
  2557. {
  2558. ; BS Recovery value within bounds, this means BS Rec is all acounted for
  2559. BSRecPartial =
  2560. }
  2561. }
  2562. }
  2563. NumPrefixes += 1
  2564. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2565. Continue
  2566. }
  2567. IfInString, A_LoopField, 最大能量護盾2
  2568. {
  2569. NumPrefixes += 1
  2570. ValueRange := LookupAffixData("data\IncrMaxEnergyShield_Amulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2571. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2572. Continue
  2573. }
  2574. If RegExMatch(A_LoopField, "Adds \d+?\-\d+? 物理傷害")
  2575. {
  2576. If (ItemBaseType == "Weapon")
  2577. {
  2578. If (ItemSubType == "Bow")
  2579. {
  2580. ValueRange := LookupAffixData("data\AddedPhysDamage_2H.txt", ItemLevel, CurrValue, "", CurrTier)
  2581. }
  2582. Else
  2583. {
  2584. If (ItemGripType == "1H") ; one handed weapons
  2585. {
  2586. ValueRange := LookupAffixData("data\AddedPhysDamage_1H.txt", ItemLevel, CurrValue, "", CurrTier)
  2587. }
  2588. Else
  2589. {
  2590. ValueRange := LookupAffixData("data\AddedPhysDamage_2H.txt", ItemLevel, CurrValue, "", CurrTier)
  2591. }
  2592. }
  2593. }
  2594. Else
  2595. {
  2596. If (ItemSubType == "Amulet")
  2597. {
  2598. ValueRange := LookupAffixData("data\AddedPhysDamage_Amulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2599. }
  2600. Else
  2601. {
  2602. If (ItemSubType == "Quiver")
  2603. {
  2604. ValueRange := LookupAffixData("data\AddedPhysDamage_Quivers.txt", ItemLevel, CurrValue, "", CurrTier)
  2605. }
  2606. Else
  2607. {
  2608. If (ItemSubType == "Ring")
  2609. {
  2610. ValueRange := LookupAffixData("data\AddedPhysDamage_Rings.txt", ItemLevel, CurrValue, "", CurrTier)
  2611. }
  2612. Else
  2613. {
  2614. ; there is no Else for rare items, but some uniques have added phys damage
  2615. ; just lookup in 1H for now
  2616. ValueRange := LookupAffixData("data\AddedPhysDamage_Amulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2617. }
  2618. }
  2619. }
  2620. }
  2621. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2622. NumPrefixes += 1
  2623. Continue
  2624. }
  2625. If RegExMatch(A_LoopField, "Adds \d+?\-\d+? 冰冷傷害")
  2626. {
  2627. If (ItemSubType == "Amulet" or ItemSubType == "Ring")
  2628. {
  2629. ValueRange := LookupAffixData("data\AddedColdDamage_RingsAndAmulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2630. }
  2631. Else
  2632. {
  2633. If (ItemSubType == "Gloves")
  2634. {
  2635. ValueRange := LookupAffixData("data\AddedColdDamage_Gloves.txt", ItemLevel, CurrValue, "", CurrTier)
  2636. }
  2637. Else
  2638. {
  2639. If (ItemSubType == "Quiver")
  2640. {
  2641. ValueRange := LookupAffixData("data\AddedColdDamage_Quivers.txt", ItemLevel, CurrValue, "", CurrTier)
  2642. }
  2643. Else
  2644. {
  2645. If (ItemGripType == "1H")
  2646. {
  2647. ValueRange := LookupAffixData("data\AddedColdDamage_1H.txt", ItemLevel, CurrValue, "", CurrTier)
  2648. }
  2649. Else
  2650. {
  2651. ValueRange := LookupAffixData("data\AddedColdDamage_2H.txt", ItemLevel, CurrValue, "", CurrTier)
  2652. }
  2653. }
  2654. }
  2655. }
  2656. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2657. NumPrefixes += 1
  2658. Continue
  2659. }
  2660. If RegExMatch(A_LoopField, "Adds \d+?\-\d+? 火焰傷害")
  2661. {
  2662. If (ItemSubType == "Amulet" or ItemSubType == "Ring")
  2663. {
  2664. ValueRange := LookupAffixData("data\AddedFireDamage_RingsAndAmulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2665. }
  2666. Else
  2667. {
  2668. If (ItemSubType == "Gloves")
  2669. {
  2670. ValueRange := LookupAffixData("data\AddedFireDamage_Gloves.txt", ItemLevel, CurrValue, "", CurrTier)
  2671. }
  2672. Else
  2673. {
  2674. If (ItemSubType == "Quiver")
  2675. {
  2676. ValueRange := LookupAffixData("data\AddedFireDamage_Quivers.txt", ItemLevel, CurrValue, "", CurrTier)
  2677. }
  2678. Else
  2679. {
  2680. If (ItemGripType == "1H") ; one handed weapons
  2681. {
  2682. ValueRange := LookupAffixData("data\AddedFireDamage_1H.txt", ItemLevel, CurrValue, "", CurrTier)
  2683. }
  2684. Else
  2685. {
  2686. ValueRange := LookupAffixData("data\AddedFireDamage_2H.txt", ItemLevel, CurrValue, "", CurrTier)
  2687. }
  2688. }
  2689. }
  2690. }
  2691. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2692. NumPrefixes += 1
  2693. Continue
  2694. }
  2695. If RegExMatch(A_LoopField, "Adds \d+?\-\d+? 閃電傷害")
  2696. {
  2697. If (ItemSubType == "Amulet" or ItemSubType == "Ring")
  2698. {
  2699. ValueRange := LookupAffixData("data\AddedLightningDamage_RingsAndAmulets.txt", ItemLevel, CurrValue, "", CurrTier)
  2700. }
  2701. Else
  2702. {
  2703. If (ItemSubType == "Gloves")
  2704. {
  2705. ValueRange := LookupAffixData("data\AddedLightningDamage_Gloves.txt", ItemLevel, CurrValue, "", CurrTier)
  2706. }
  2707. Else
  2708. {
  2709. If (ItemSubType == "Quiver")
  2710. {
  2711. ValueRange := LookupAffixData("data\AddedLightningDamage_Quivers.txt", ItemLevel, CurrValue, "", CurrTier)
  2712. }
  2713. Else
  2714. {
  2715. If (ItemGripType == "1H") ; one handed weapons
  2716. {
  2717. ValueRange := LookupAffixData("data\AddedLightningDamage_1H.txt", ItemLevel, CurrValue, "", CurrTier)
  2718. }
  2719. Else
  2720. {
  2721. ValueRange := LookupAffixData("data\AddedLightningDamage_2H.txt", ItemLevel, CurrValue, "", CurrTier)
  2722. }
  2723. }
  2724. }
  2725. }
  2726. ActualRange := GetActualValue(A_LoopField)
  2727. AffixType := "Prefix"
  2728. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  2729. NumPrefixes += 1
  2730. Continue
  2731. }
  2732. IfInString, A_LoopField, 物理傷害
  2733. {
  2734. NumPrefixes += 1
  2735. ValueRange := LookupAffixData("data\PhysDamagereturn.txt", ItemLevel, CurrValue, "", CurrTier)
  2736. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2737. Continue
  2738. }
  2739. IfInString, A_LoopField, 寶石等級
  2740. {
  2741. If (ItemBaseType == "Weapon")
  2742. {
  2743. If (ItemSubType == "Bow")
  2744. {
  2745. ValueRange := LookupAffixData("data\GemLevel_Bow.txt", ItemLevel, CurrValue, "", CurrTier)
  2746. }
  2747. Else
  2748. {
  2749. If (InStr(A_LoopField, "Fire") OR InStr(A_LoopField, "Cold") OR InStr(A_LoopField, "Lightning"))
  2750. {
  2751. ValueRange := LookupAffixData("data\GemLevel_Elemental.txt", ItemLevel, CurrValue, "", CurrTier)
  2752. }
  2753. Else
  2754. {
  2755. If (InStr(A_LoopField, "Melee"))
  2756. {
  2757. ValueRange := LookupAffixData("data\GemLevel_Melee.txt", ItemLevel, CurrValue, "", CurrTier)
  2758. }
  2759. Else
  2760. {
  2761. ; Paragorn's
  2762. ValueRange := LookupAffixData("data\GemLevel.txt", ItemLevel, CurrValue, "", CurrTier)
  2763. }
  2764. }
  2765. }
  2766. }
  2767. Else
  2768. {
  2769. If (InStr(A_LoopField, "Minion"))
  2770. {
  2771. ValueRange := LookupAffixData("data\GemLevel_Minion.txt", ItemLevel, CurrValue, "", CurrTier)
  2772. }
  2773. Else If (InStr(A_LoopField, "Fire") OR InStr(A_LoopField, "Cold") OR InStr(A_LoopField, "Lightning"))
  2774. {
  2775. ValueRange := LookupAffixData("data\GemLevel_Elemental.txt", ItemLevel, CurrValue, "", CurrTier)
  2776. }
  2777. Else If (InStr(A_LoopField, "Melee"))
  2778. {
  2779. ValueRange := LookupAffixData("data\GemLevel_Melee.txt", ItemLevel, CurrValue, "", CurrTier)
  2780. }
  2781. }
  2782. NumPrefixes += 1
  2783. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2784. Continue
  2785. }
  2786. IfInString, A_LoopField, 最大生命
  2787. {
  2788. ValueRange := LookupAffixData("data\MaxLife.txt", ItemLevel, CurrValue, "", CurrTier)
  2789. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2790. NumPrefixes += 1
  2791. Continue
  2792. }
  2793. IfInString, A_LoopField, 物理攻擊傷害偷取生命
  2794. {
  2795. NumPrefixes += 1
  2796. ValueRange := LookupAffixData("data\LifeLeech.txt", ItemLevel, CurrValue, "", CurrTier)
  2797. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2798. Continue
  2799. }
  2800. IfInString, A_LoopField, 移動速度
  2801. {
  2802. NumPrefixes += 1
  2803. ValueRange := LookupAffixData("data\MovementSpeed.txt", ItemLevel, CurrValue, "", CurrTier)
  2804. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2805. Continue
  2806. }
  2807. IfInString, A_LoopField, 武器元素傷害
  2808. {
  2809. NumPrefixes += 1
  2810. ValueRange := LookupAffixData("data\IncrWeaponElementalDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  2811. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2812. Continue
  2813. }
  2814.  
  2815. ; Flask effects (on belts)
  2816. IfInString, A_LoopField, 藥劑魔力回復速度
  2817. {
  2818. NumPrefixes += 1
  2819. ValueRange := LookupAffixData("data\FlaskManaRecoveryRate.txt", ItemLevel, CurrValue, "", CurrTier)
  2820. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2821. Continue
  2822. }
  2823. IfInString, A_LoopField, 藥劑生命回復速度
  2824. {
  2825. NumPrefixes += 1
  2826. ValueRange := LookupAffixData("data\FlaskLifeRecoveryRate.txt", ItemLevel, CurrValue, "", CurrTier)
  2827. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  2828. Continue
  2829. }
  2830.  
  2831. ; Flask prefixes
  2832. IfInString, A_LoopField, 回復速度
  2833. {
  2834. If (NumPrefixes < 1)
  2835. {
  2836. NumPrefixes += 1
  2837. }
  2838. Continue
  2839. }
  2840. IfInString, A_LoopField, 回復量
  2841. {
  2842. If (NumPrefixes < 1)
  2843. {
  2844. NumPrefixes += 1
  2845. }
  2846. Continue
  2847. }
  2848. IfInString, A_LoopField, Charges
  2849. {
  2850. If (NumPrefixes < 1)
  2851. {
  2852. NumPrefixes += 1
  2853. }
  2854. Continue
  2855. }
  2856. IfInString, A_LoopField, 立即回復
  2857. {
  2858. If (NumPrefixes < 1)
  2859. {
  2860. NumPrefixes += 1
  2861. }
  2862. Continue
  2863. }
  2864. IfInString, A_LoopField, 藥劑充能時
  2865. {
  2866. If (NumPrefixes < 1)
  2867. {
  2868. NumPrefixes += 1
  2869. }
  2870. Continue
  2871. }
  2872. IfInString, A_LoopField, 回復時
  2873. {
  2874. If (NumPrefixes < 1)
  2875. {
  2876. NumPrefixes += 1
  2877. }
  2878. Continue
  2879. }
  2880. IfInString, A_LoopField, 魔力回復
  2881. {
  2882. If (NumPrefixes < 1)
  2883. {
  2884. NumPrefixes += 1
  2885. }
  2886. Continue
  2887. }
  2888. IfInString, A_LoopField, 生命回復
  2889. {
  2890. If (NumPrefixes < 1)
  2891. {
  2892. NumPrefixes += 1
  2893. }
  2894. Continue
  2895. }
  2896. }
  2897.  
  2898. ; --- COMPLEX AFFIXES ---
  2899.  
  2900. Loop, Parse, ItemDataChunk, `n, `r
  2901. {
  2902. If StrLen(A_LoopField) = 0
  2903. {
  2904. Break ; not interested in blank lines
  2905. }
  2906. IfInString, ItemDataChunk, Unidentified
  2907. {
  2908. Break ; not interested in unidentified items
  2909. }
  2910.  
  2911. CurrValue := GetActualValue(A_LoopField)
  2912.  
  2913. ; "Spell Damage +%" (simple prefix)
  2914. ; "Spell Damage +% (1H)" / "Base Maximum Mana" - Limited to sceptres, wands, and daggers.
  2915. ; "Spell Damage +% (Staff)" / "Base Maximum Mana"
  2916. IfInString, A_LoopField, 法術傷害
  2917. {
  2918. AffixType := "Prefix"
  2919. If (HasMaxMana)
  2920. {
  2921. SDBracketLevel := 0
  2922. MMBracketLevel := 0
  2923. MaxManaValue := ExtractValueFromAffixLine(ItemDataChunk, "maximum Mana")
  2924. If (ItemSubType == "Staff")
  2925. {
  2926. SpellDamageBracket := LookupAffixBracket("data\SpellDamage_MaxMana_Staff.txt", ItemLevel, CurrValue, SDBracketLevel)
  2927. If (Not IsValidBracket(SpellDamageBracket))
  2928. {
  2929. AffixType := "Comp. Prefix+Prefix"
  2930. NumPrefixes += 1
  2931.  
  2932. ; need to find the bracket level by looking at max mana value instead
  2933. MaxManaBracket := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", ItemLevel, MaxManaValue, MMBracketLevel)
  2934. If (Not IsValidBracket(MaxManaBracket))
  2935. {
  2936. ; this actually means that both the "increased Spell Damage" line and
  2937. ; the "to maximum Mana" line are made up of composite prefix + prefix
  2938. ; I haven't seen such an item yet but you never know. In any case this
  2939. ; is completely ambiguous and can't be resolved. Mark line with EstInd
  2940. ; so user knows she needs to take a look at it.
  2941. AffixType := "Comp. Prefix+Comp. Prefix"
  2942. ValueRange := StrPad(EstInd, ValueRangeFieldWidth + StrLen(EstInd), "left")
  2943. }
  2944. Else
  2945. {
  2946. SpellDamageBracketFromComp := LookupAffixBracket("data\SpellDamage_MaxMana_Staff.txt", MMBracketLevel)
  2947. SDValueRest := CurrValue - RangeMid(SpellDamageBracketFromComp)
  2948. SpellDamageBracket := LookupAffixBracket("data\SpellDamage_Staff.txt", ItemLevel, SDValueRest, SDBracketLevel)
  2949. ValueRange := AddRange(SpellDamageBracket, SpellDamageBracketFromComp)
  2950. ValueRange := MarkAsGuesstimate(ValueRange)
  2951. }
  2952. }
  2953. Else
  2954. {
  2955. ValueRange := LookupAffixData("data\SpellDamage_MaxMana_Staff.txt", ItemLevel, CurrValue, BracketLevel, CurrTier)
  2956. MaxManaBracket := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", BracketLevel)
  2957. AffixType := "Comp. Prefix"
  2958. }
  2959. }
  2960. Else
  2961. {
  2962. SpellDamageBracket := LookupAffixBracket("data\SpellDamage_MaxMana_1H.txt", ItemLevel, CurrValue, SDBracketLevel)
  2963. If (Not IsValidBracket(SpellDamageBracket))
  2964. {
  2965. AffixType := "Comp. Prefix+Prefix"
  2966. NumPrefixes += 1
  2967.  
  2968. ; need to find the bracket level by looking at max mana value instead
  2969. MaxManaBracket := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", ItemLevel, MaxManaValue, MMBracketLevel)
  2970. If (Not IsValidBracket(MaxManaBracket))
  2971. {
  2972. MaxManaBracket := LookupAffixBracket("data\MaxMana.txt", ItemLevel, MaxManaValue, MMBracketLevel)
  2973. If (IsValidBracket(MaxManaBracket))
  2974. {
  2975. AffixType := "Prefix"
  2976. If (ItemSubType == "Staff")
  2977. {
  2978. ValueRange := LookupAffixData("data\SpellDamage_Staff.txt", ItemLevel, CurrValue, SDBracketLevel, CurrTier)
  2979. }
  2980. Else
  2981. {
  2982. ValueRange := LookupAffixData("data\SpellDamage_1H.txt", ItemLevel, CurrValue, SDBracketLevel, CurrTier)
  2983. }
  2984. ValueRange := StrPad(ValueRange, ValueRangeFieldWidth, "left")
  2985. }
  2986. Else
  2987. {
  2988. msgbox, %MsgUnhandled%
  2989. ValueRange := StrPad("n/a", ValueRangeFieldWidth, "left")
  2990. }
  2991. }
  2992. Else
  2993. {
  2994. SpellDamageBracketFromComp := LookupAffixBracket("data\SpellDamage_MaxMana_1H.txt", MMBracketLevel)
  2995. SDValueRest := CurrValue - RangeMid(SpellDamageBracketFromComp)
  2996. SpellDamageBracket := LookupAffixBracket("data\SpellDamage_1H.txt", ItemLevel, SDValueRest, SDBracketLevel)
  2997. ValueRange := AddRange(SpellDamageBracket, SpellDamageBracketFromComp)
  2998. ValueRange := MarkAsGuesstimate(ValueRange)
  2999. }
  3000. }
  3001. Else
  3002. {
  3003. ValueRange := LookupAffixData("data\SpellDamage_MaxMana_1H.txt", ItemLevel, CurrValue, BracketLevel, CurrTier)
  3004. MaxManaBracket := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", BracketLevel)
  3005. AffixType := "Comp. Prefix"
  3006. }
  3007. }
  3008. ; if MaxManaValue falls within bounds of MaxManaBracket this means the max mana value is already fully accounted for
  3009. If (WithinBounds(MaxManaBracket, MaxManaValue))
  3010. {
  3011. MaxManaPartial =
  3012. }
  3013. Else
  3014. {
  3015. MaxManaPartial := MaxManaBracket
  3016. }
  3017. }
  3018. Else
  3019. {
  3020. If (ItemSubType == "Amulet")
  3021. {
  3022. ValueRange := LookupAffixData("data\SpellDamage_Amulets.txt", ItemLevel, CurrValue, "", CurrTier)
  3023. }
  3024. Else
  3025. {
  3026. If (ItemSubType == "Staff")
  3027. {
  3028. ValueRange := LookupAffixData("data\SpellDamage_Staff.txt", ItemLevel, CurrValue, "", CurrTier)
  3029. }
  3030. Else
  3031. {
  3032. ValueRange := LookupAffixData("data\SpellDamage_1H.txt", ItemLevel, CurrValue, "", CurrTier)
  3033. }
  3034. }
  3035. NumPrefixes += 1
  3036. }
  3037. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3038. Continue
  3039. }
  3040.  
  3041. ; "Base Maximum Mana" (simple prefix)
  3042. ; "1H Spell Damage" / "Base Maximum Mana" (complex prefix)
  3043. ; "Staff Spell Damage" / "Base Maximum Mana" (complex prefix)
  3044. IfInString, A_LoopField, 最大魔力
  3045. {
  3046. AffixType := "Prefix"
  3047. If (ItemBaseType == "Weapon")
  3048. {
  3049. If (HasSpellDamage)
  3050. {
  3051. If (MaxManaPartial and Not WithinBounds(MaxManaPartial, CurrValue))
  3052. {
  3053. ; msgbox, MaxManaPartial: %MaxManaPartial%
  3054. NumPrefixes += 1
  3055. AffixType := "Comp. Prefix+Prefix"
  3056.  
  3057. ValueRange := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", ItemLevel, CurrValue)
  3058. MaxManaRest := CurrValue-RangeMid(MaxManaPartial)
  3059.  
  3060. ; msgbox, MaxManaPartial: %MaxManaPartial%
  3061. ; msgbox, MaxManaRest: %MaxManaRest%
  3062. If (MaxManaRest >= 15) ; 15 because the lowest possible value at this time for Max Mana is 15 at bracket level 1
  3063. {
  3064. ; Lookup remaining Max Mana bracket that comes from Max Mana being concatenated as simple prefix
  3065. ValueRange1 := LookupAffixBracket("data\MaxMana.txt", ItemLevel, MaxManaRest)
  3066. ValueRange2 := MaxManaPartial
  3067. ; msgbox, MaxManaPartial: %MaxManaPartial%`, ValueRange1: %ValueRange1%`, ValueRange2: %ValueRange2%
  3068.  
  3069. ; Add these ranges together to get an estimated range
  3070. ValueRange := AddRange(ValueRange1, ValueRange2)
  3071. ValueRange := MarkAsGuesstimate(ValueRange)
  3072. }
  3073. Else
  3074. {
  3075. ; Could be that the spell damage affix is actually a pure spell damage affix
  3076. ; (w/o the added max mana) so this would mean max mana is a pure prefix - if
  3077. ; NumPrefixes allows it, ofc...
  3078. If (NumPrefixes < 3)
  3079. {
  3080. AffixType := "Prefix"
  3081. ValueRange := LookupAffixData("data\MaxMana.txt", ItemLevel, CurrValue, "", CurrTier)
  3082. ChangeAffixDetailLine("increased Spell Damage", "Comp. Prefix", "Prefix")
  3083. }
  3084. }
  3085. }
  3086. Else
  3087. {
  3088. ; it's on a weapon, there is Spell Damage but no MaxManaPartial or NumPrefixes already is 3
  3089. AffixType := "Comp. Prefix"
  3090. ValueRange := LookupAffixBracket("data\MaxMana_SpellDamage_StaffAnd1H.txt", ItemLevel, CurrValue)
  3091. If (Not IsValidBracket(ValueRange))
  3092. {
  3093. ; incr. spell damage is actually a prefix and not a comp. prefix
  3094. ; so max mana must be a normal prefix as well then
  3095. AffixType := "Prefix"
  3096. ValueRange := LookupAffixData("data\MaxMana.txt", ItemLevel, CurrValue, "", CurrTier)
  3097. }
  3098. Else
  3099. {
  3100. ValueRange := MarkAsGuesstimate(ValueRange)
  3101. }
  3102. }
  3103. ; check if we still need to increment for the Spell Damage part
  3104. If (NumPrefixes < 3)
  3105. {
  3106. NumPrefixes += 1
  3107. }
  3108. }
  3109. Else
  3110. {
  3111. ; it's on a weapon but there is no Spell Damage, which makes it a simple prefix
  3112. Goto, SimpleMaxManaPrefix
  3113. }
  3114. }
  3115. Else
  3116. {
  3117. ; Armour...
  3118. ; Max Mana cannot appear on belts but I won't exclude them for now
  3119. ; to future-proof against when max mana on belts might be added.
  3120. Goto, SimpleMaxManaPrefix
  3121. }
  3122.  
  3123. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3124. Continue
  3125.  
  3126. SimpleMaxManaPrefix:
  3127. NumPrefixes += 1
  3128. ValueRange := LookupAffixData("data\MaxMana.txt", ItemLevel, CurrValue, "", CurrTier)
  3129. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3130. Continue
  3131. }
  3132.  
  3133. ; "Local Physical Damage +%" (simple prefix)
  3134. ; "Local Physical Damage +%" / "Local Accuracy Rating" (complex prefix)
  3135. ; only on Weapons
  3136. ; needs to come before Accuracy Rating stuff
  3137. IfInString, A_LoopField, 物理傷害
  3138. {
  3139. AffixType := "Prefix"
  3140. IPDPath := "data\IncrPhysDamage.txt"
  3141. If (HasToAccuracyRating)
  3142. {
  3143. ARIPDPath := "data\AccuracyRating_IncrPhysDamage.txt"
  3144. IPDARPath := "data\IncrPhysDamage_AccuracyRating.txt"
  3145. ARValue := ExtractValueFromAffixLine(ItemDataChunk, "to Accuracy Rating")
  3146. ARPath := "data\AccuracyRating_Global.txt"
  3147. If (ItemBaseType == "Weapon")
  3148. {
  3149. ARPath := "data\AccuracyRating_Local.txt"
  3150. }
  3151.  
  3152. ; look up IPD bracket, and use its bracket level to cross reference the corresponding
  3153. ; AR bracket. If both check out (are within bounds of their bracket level) case is
  3154. ; simple: Comp. Prefix (IPD / AR)
  3155. IPDBracketLevel := 0
  3156. IPDBracket := LookupAffixBracket(IPDARPath, ItemLevel, CurrValue, IPDBracketLevel)
  3157. ARBracket := LookupAffixBracket(ARIPDPath, IPDBracketLevel)
  3158.  
  3159. If (HasIncrLightRadius)
  3160. {
  3161. LRValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Light Radius")
  3162. ; first check if the AR value that comes with the Comp. Prefix AR / Light Radius
  3163. ; already covers the complete AR value. If so, from that follows that the Incr.
  3164. ; Phys Damage value can only be a Damage Scaling prefix.
  3165. LRBracketLevel := 0
  3166. LRBracket := LookupAffixBracket("data\LightRadius_AccuracyRating.txt", ItemLevel, LRValue, LRBracketLevel)
  3167. ARLRBracket := LookupAffixBracket("data\AccuracyRating_LightRadius.txt", LRBracketLevel)
  3168. If (IsValidBracket(ARLRBracket))
  3169. {
  3170. If (WithinBounds(ARLRBracket, ARValue) AND WithinBounds(IPDBracket, CurrValue))
  3171. {
  3172. ;msgbox, LRBracketLevel: %LRBracketLevel%, ARLRBracket: %ARLRBracket%
  3173. Goto, SimpleIPDPrefix
  3174. }
  3175. }
  3176. }
  3177.  
  3178. ; msgbox, IPDBracket: %IPDBracket%`, ARBracket: %ARBracket%
  3179.  
  3180. If (IsValidBracket(IPDBracket) and IsValidBracket(ARBracket))
  3181. {
  3182. Goto, CompIPDARPrefix
  3183. }
  3184.  
  3185. If (Not IsValidBracket(IPDBracket))
  3186. {
  3187. IPDBracket := LookupAffixBracket(IPDPath, ItemLevel, CurrValue)
  3188. ARBracket := LookupAffixBracket(ARPath, ItemLevel, ARValue) ; also lookup AR as if it were a simple suffix
  3189. ; msgbox, NumPrefixes: %NumPrefixes%, NumSuffixes: %NumSuffixes%, IPDBracket: %IPDBracket%, ARBracket: %ARBracket%
  3190. If (IsValidBracket(IPDBracket) and IsValidBracket(ARBracket) and NumPrefixes < 3)
  3191. {
  3192. HasIncrPhysDmg := 0
  3193. Goto, SimpleIPDPrefix
  3194. }
  3195. ARBracketLevel := 0
  3196. ARBracket := LookupAffixBracket(ARIPDPath, ItemLevel, ARValue, ARBracketLevel)
  3197. If (IsValidBracket(ARBracket))
  3198. {
  3199. IPDARBracket := LookupAffixBracket(IPDARPath, ARBracketLevel)
  3200. IPDRest := CurrValue - RangeMid(IPDARBracket)
  3201. IPDBracket := LookupAffixBracket(IPDPath, ItemLevel, IPDRest)
  3202. ValueRange := AddRange(IPDARBracket, IPDBracket)
  3203. ValueRange := MarkAsGuesstimate(ValueRange)
  3204. ARAffixTypePartial := "Comp. Prefix"
  3205. Goto, CompIPDARPrefixPrefix
  3206. }
  3207. }
  3208.  
  3209. If ((Not IsValidBracket(IPDBracket)) and (Not IsValidBracket(ARBracket)))
  3210. {
  3211. HasIncrPhysDmg := 0
  3212. Goto, CompIPDARPrefix
  3213. }
  3214.  
  3215. If (IsValidBracket(ARBracket))
  3216. {
  3217. ; AR bracket not found in the composite IPD/AR table
  3218. ARValue := ExtractValueFromAffixLine(ItemDataChunk, "to Accuracy Rating")
  3219. ARBracket := LookupAffixBracket(ARPath, ItemLevel, ARValue)
  3220.  
  3221. Goto, CompIPDARPrefix
  3222. }
  3223. If (IsValidBracket(IPDBracket))
  3224. {
  3225. ; AR bracket was found in the comp. IPD/AR table, but not the IPD bracket
  3226. Goto, SimpleIPDPrefix
  3227. }
  3228. Else
  3229. {
  3230. ValueRange := LookupAffixData(IPDPath, ItemLevel, CurrValue, "", CurrTier)
  3231. }
  3232. }
  3233. Else
  3234. {
  3235. Goto, SimpleIPDPrefix
  3236. }
  3237.  
  3238. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3239. Continue
  3240.  
  3241. SimpleIPDPrefix:
  3242. NumPrefixes += 1
  3243. ValueRange := LookupAffixData("data\IncrPhysDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  3244. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3245. Continue
  3246. CompIPDARPrefix:
  3247. AffixType := "Comp. Prefix"
  3248. ValueRange := LookupAffixData(IPDARPath, ItemLevel, CurrValue, "", CurrTier)
  3249. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3250. ARPartial := ARBracket
  3251. Continue
  3252. CompIPDARPrefixPrefix:
  3253. NumPrefixes += 1
  3254. AffixType := "Comp. Prefix+Prefix"
  3255. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3256. ARPartial := ARBracket
  3257. Continue
  3258. }
  3259.  
  3260. IfInString, A_LoopField, increased Block and Stun Recovery
  3261. {
  3262. AffixType := "Prefix"
  3263. If (HasHybridDefences)
  3264. {
  3265. AffixType := "Comp. Prefix"
  3266. BSRecAffixPath := "data\StunRecovery_Hybrid.txt"
  3267. BSRecAffixBracket := LookupAffixBracket(BSRecAffixPath, ItemLevel, CurrValue)
  3268. If (Not IsValidBracket(BSRecAffixBracket))
  3269. {
  3270. CompStatAffixType =
  3271. If (HasIncrArmourAndEvasion)
  3272. {
  3273. PartialAffixString := "increased Armour and Evasion"
  3274. }
  3275. If (HasIncrEvasionAndES)
  3276. {
  3277. PartialAffixString := "increased Evasion and Energy Shield"
  3278. }
  3279. If (HasIncrArmourAndES)
  3280. {
  3281. PartialAffixString := "increased Armour and Energy Shield"
  3282. }
  3283. CompStatAffixType := GetAffixTypeFromProcessedLine(PartialAffixString)
  3284. If (BSRecPartial)
  3285. {
  3286. ; msgbox, NumPrefixes: %NumPrefixes%`, NumSuffixes: %NumSuffixes%`, BSRest: %BSRest%`, BSRecPartial: %BSRecPartial%
  3287. If (WithinBounds(BSRecPartial, CurrValue))
  3288. {
  3289. IfInString, CompStatAffixType, Comp. Prefix
  3290. {
  3291. AffixType := CompStatAffixType
  3292. }
  3293. }
  3294. Else
  3295. {
  3296. If (NumSuffixes < 3)
  3297. {
  3298. AffixType := "Comp. Prefix+Suffix"
  3299. BSRest := CurrValue - RangeMid(BSRecPartial)
  3300. BSRecAffixBracket := LookupAffixBracket("data\StunRecovery_Suffix.txt", ItemLevel, BSRest)
  3301. If (Not IsValidBracket(BSRecAffixBracket))
  3302. {
  3303. AffixType := "Comp. Prefix+Prefix"
  3304. BSRecAffixBracket := LookupAffixBracket("data\StunRecovery_Prefix.txt", ItemLevel, CurrValue)
  3305. If (Not IsValidBracket(BSRecAffixBracket))
  3306. {
  3307. If (CompStatAffixType == "Comp. Prefix+Prefix" and NumSuffixes < 3)
  3308. {
  3309. AffixType := "Comp. Prefix+Suffix"
  3310. BSRecSuffixBracket := LookupAffixBracket("data\StunRecovery_Suffix.txt", ItemLevel, BSRest)
  3311. NumSuffixes += 1
  3312. If (Not IsValidBracket(BSRecSuffixBracket))
  3313. {
  3314. ; TODO: properly deal with this quick fix!
  3315. ;
  3316. ; if this point is reached this means that the parts that give to
  3317. ; increased armor/evasion/es/hybrid + stun recovery need to fully be
  3318. ; re-evaluated.
  3319. ;
  3320. ; take an ilvl 62 item with these 2 lines:
  3321. ;
  3322. ; 118% increased Armour and Evasion
  3323. ; 24% increased Block and Stun Recovery
  3324. ;
  3325. ; Since it's ilvl 62, we assume the hybrid + stun recovery bracket to be the
  3326. ; highest possible (lvl 60 bracket), which is 42-50. So that's max 50 of the
  3327. ; 118 dealth with.
  3328. ; Consequently, that puts the stun recovery partial at 14-15 for the lvl 60 bracket.
  3329. ; This now leaves, 68 of hybrid defence to account for, which we can do by assuming
  3330. ; the remainder to come from a hybrid defence prefix. So that's incr. Armour and Evasion
  3331. ; identified as CP+P
  3332. ; However, here come's the problem, our lvl 60 bracket had 14-15 stun recovery which
  3333. ; assuming max, leaves 9 remainder (24-15) to account for. Should be easy, right?
  3334. ; Just assume the rest comes from a stun recovery suffix and look it up. Except the
  3335. ; lowest possible entry for a stun recovery suffix is 11! Leaving us with the issues that
  3336. ; we know that CP+P is right for the hybrid + stun recovery line and CP+S is right for the
  3337. ; stun recovery line.
  3338. ; Most likely, what is wrong is the assumption earlier to take the highest possible
  3339. ; hybrid + stun recovery bracket. Problem is that wasn't apparent when hybrid defences
  3340. ; was processed.
  3341. ; At this point, a quick fix what I am doing is I just look up the complete stun recovery
  3342. ; value as if it were a suffix completely but still mark it as CP+S.
  3343. ; To deal with this correctly I would need to reprocess the hybrid + stun recovery line here
  3344. ; with a different ratio of the CP part to the P part to get a lower BSRecPartial.
  3345. ;
  3346. BSRecSuffixBracket := LookupAffixBracket("data\StunRecovery_Suffix.txt", ItemLevel, CurrValue)
  3347. ValueRange := LookupAffixBracket("data\StunRecovery_Suffix.txt", ItemLevel, CurrValue)
  3348. ValueRange := MarkAsGuesstimate(ValueRange)
  3349. }
  3350. Else
  3351. {
  3352. ValueRange := AddRange(BSRecSuffixBracket, BSRecPartial)
  3353. ValueRange := MarkAsGuesstimate(ValueRange)
  3354. }
  3355. }
  3356. Else
  3357. {
  3358. AffixType := "Suffix"
  3359. ValueRange := LookupAffixData("data\StunRecovery_Suffix.txt", ItemLevel, CurrValue, "", CurrTier)
  3360. If (NumSuffixes < 3)
  3361. {
  3362. NumSuffixes += 1
  3363. }
  3364. ChangeAffixDetailLine(PartialAffixString, "Comp. Prefix" , "Prefix")
  3365. }
  3366. }
  3367. Else
  3368. {
  3369. If (NumPrefixes < 3)
  3370. {
  3371. NumPrefixes += 1
  3372. }
  3373. }
  3374. }
  3375. Else
  3376. {
  3377. NumSuffixes += 1
  3378. ValueRange := AddRange(BSRecPartial, BSRecAffixBracket)
  3379. ValueRange := MarkAsGuesstimate(ValueRange)
  3380. }
  3381. }
  3382. }
  3383. }
  3384. }
  3385. Else
  3386. {
  3387. ; msgbox, % CurrValue
  3388. ValueRange := LookupAffixData(BSRecAffixPath, ItemLevel, CurrValue, "", CurrTier)
  3389. }
  3390. }
  3391. Else
  3392. {
  3393. AffixType := "Comp. Prefix"
  3394. If (HasIncrArmour)
  3395. {
  3396. PartialAffixString := "increased Armour"
  3397. BSRecAffixPath := "data\StunRecovery_Armour.txt"
  3398. }
  3399. If (HasIncrEvasion)
  3400. {
  3401. PartialAffixString := "increased Evasion Rating"
  3402. BSRecAffixPath := "data\StunRecovery_Evasion.txt"
  3403. }
  3404. If (HasIncrEnergyShield)
  3405. {
  3406. PartialAffixString := "increased Energy Shield"
  3407. BSRecAffixPath := "data\StunRecovery_EnergyShield.txt"
  3408. }
  3409. BSRecAffixBracket := LookupAffixBracket(BSRecAffixPath, ItemLevel, CurrValue)
  3410. If (Not IsValidBracket(BSRecAffixBracket))
  3411. {
  3412. CompStatAffixType := GetAffixTypeFromProcessedLine(PartialAffixString)
  3413. If (BSRecPartial)
  3414. {
  3415. If (WithinBounds(BSRecPartial, CurrValue))
  3416. {
  3417. IfInString, CompStatAffixType, Comp. Prefix
  3418. {
  3419. AffixType := CompStatAffixType
  3420. }
  3421. }
  3422. Else
  3423. {
  3424. If (NumSuffixes < 3)
  3425. {
  3426. AffixType := "Comp. Prefix+Suffix"
  3427. BSRest := CurrValue - RangeMid(BSRecPartial)
  3428. BSRecAffixBracket := LookupAffixBracket("data\StunRecovery_Suffix.txt", ItemLevel, BSRest)
  3429. If (Not IsValidBracket(BSRecAffixBracket))
  3430. {
  3431. AffixType := "Comp. Prefix+Prefix"
  3432. BSRecAffixBracket := LookupAffixBracket("data\StunRecovery_Prefix.txt", ItemLevel, CurrValue)
  3433. If (Not IsValidBracket(BSRecAffixBracket))
  3434. {
  3435. AffixType := "Suffix"
  3436. ValueRange := LookupAffixData("data\StunRecovery_Suffix.txt", ItemLevel, CurrValue, "", CurrTier)
  3437. If (NumSuffixes < 3)
  3438. {
  3439. NumSuffixes += 1
  3440. }
  3441. ChangeAffixDetailLine(PartialAffixString, "Comp. Prefix" , "Prefix")
  3442. }
  3443. Else
  3444. {
  3445. If (NumPrefixes < 3)
  3446. {
  3447. NumPrefixes += 1
  3448. }
  3449. }
  3450.  
  3451. }
  3452. Else
  3453. {
  3454. NumSuffixes += 1
  3455. ValueRange := AddRange(BSRecPartial, BSRecAffixBracket)
  3456. ValueRange := MarkAsGuesstimate(ValueRange)
  3457. }
  3458. }
  3459. }
  3460. }
  3461. Else
  3462. {
  3463. BSRecSuffixPath := "data\StunRecovery_Suffix.txt"
  3464. BSRecSuffixBracket := LookupAffixBracket(BSRecSuffixPath, ItemLevel, CurrValue)
  3465. If (IsValidBracket(BSRecSuffixBracket))
  3466. {
  3467. AffixType := "Suffix"
  3468. ValueRange := LookupAffixData(BSRecSuffixPath, ItemLevel, CurrValue, "", CurrTier)
  3469. If (NumSuffixes < 3)
  3470. {
  3471. NumSuffixes += 1
  3472. }
  3473. }
  3474. Else
  3475. {
  3476. BSRecPrefixPath := "data\StunRecovery_Prefix.txt"
  3477. BSRecPrefixBracket := LookupAffixBracket(BSRecPrefixPath, ItemLevel, CurrValue)
  3478. ValueRange := LookupAffixData(BSRecPrefixPath, ItemLevel, CurrValue, "", CurrTier)
  3479. }
  3480. }
  3481. }
  3482. Else
  3483. {
  3484. ; msgbox, BSRecAffixBracket: %BSRecAffixBracket%
  3485. ValueRange := LookupAffixData(BSRecAffixPath, ItemLevel, CurrValue, "", CurrTier)
  3486. }
  3487. }
  3488. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3489. Continue
  3490. }
  3491.  
  3492. ; AR is one tough beast... currently there are the following affixes affecting AR:
  3493. ; 1) "Accuracy Rating" (Suffix)
  3494. ; 2) "Local Accuracy Rating" (Suffix)
  3495. ; 3) "Light Radius / + Accuracy Rating" (Suffix) - only the first 2 entries, bc last entry combines LR with #% increased Accuracy Rating instead!
  3496. ; 4) "Local Physical Dmg +% / Local Accuracy Rating" (Prefix)
  3497.  
  3498. ; the difficulty lies in those cases that combine multiple of these affixes into one final display value
  3499. ; currently I try and tackle this by using a trickle-through partial balance approach. That is, go from
  3500. ; most special case to most normal, while subtracting the value that each case most likely contributes
  3501. ; until you have a value left that can be found in the most nominal case
  3502. ;
  3503. ; Important to note here:
  3504. ; ARPartial will be set during the "increased Physical Damage" case above
  3505.  
  3506. IfInString, A_LoopField, 命中
  3507. {
  3508. ; trickle-through order:
  3509. ; 1) increased AR, Light Radius, all except Belts, Comp. Suffix
  3510. ; 2) to AR, Light Radius, all except Belts, Comp. Suffix
  3511. ; 3) increased Phys Damage, to AR, Weapons, Prefix
  3512. ; 4) to AR, all except Belts, Suffix
  3513.  
  3514. ValueRangeAR := "0-0"
  3515. AffixType := ""
  3516. IPDAffixType := GetAffixTypeFromProcessedLine("increased Physical Damage")
  3517. If (HasIncrLightRadius and Not HasIncrAccuracyRating)
  3518. {
  3519. ; "of Shining" and "of Light"
  3520. LightRadiusValue := ExtractValueFromAffixLine(ItemDataChunk, "increased Light Radius")
  3521.  
  3522. ; get bracket level of the light radius so we can look up the corresponding AR bracket
  3523. BracketLevel := 0
  3524. LookupAffixBracket("data\LightRadius_AccuracyRating.txt", ItemLevel, LightRadiusValue, BracketLevel)
  3525. ARLRBracket := LookupAffixBracket("data\AccuracyRating_LightRadius.txt", BracketLevel)
  3526.  
  3527. AffixType := AffixType . "Comp. Suffix"
  3528. ValueRange := LookupAffixData("data\AccuracyRating_LightRadius.txt", ItemLevel, CurrValue, "", CurrTier)
  3529. NumSuffixes += 1
  3530.  
  3531. If (ARPartial)
  3532. {
  3533. ; append this affix' contribution to our partial AR range
  3534. ARPartial := AddRange(ARPartial, ARLRBracket)
  3535. }
  3536. ; msgbox, ARLRBracket: %ARLRBracket%, ARPartial: %ARPartial%
  3537. ; test if candidate range already covers current AR value
  3538. If (WithinBounds(ARLRBracket, CurrValue))
  3539. {
  3540. Goto, FinalizeAR
  3541. }
  3542. Else
  3543. {
  3544. AffixType := "Comp. Suffix+Suffix"
  3545. If (HasIncrPhysDmg)
  3546. {
  3547. If (ARPartial)
  3548. {
  3549. CombinedRange := AddRange(ARLRBracket, ARPartial)
  3550. ; msgbox, CombinedRange: %CombinedRange%
  3551. AffixType := "Comp. Prefix+Comp. Suffix"
  3552. If (WithinBounds(CombinedRange, CurrValue))
  3553. {
  3554. If (NumPrefixes < 3)
  3555. {
  3556. NumPrefixes += 1
  3557. }
  3558. ValueRange := CombinedRange
  3559. ValueRange := MarkAsGuesstimate(ValueRange)
  3560. Goto, FinalizeAR
  3561. }
  3562. Else
  3563. {
  3564. NumSuffixes -= 1
  3565. }
  3566. }
  3567.  
  3568. ; msgbox, IPDAffixType: %IPDAffixType%
  3569. If (InStr(IPDAffixType, "Comp. Prefix"))
  3570. {
  3571. ; AffixType := "Comp. Prefix+Comp. Suffix+Suffix"
  3572. If (NumPrefixes < 3)
  3573. {
  3574. NumPrefixes += 1
  3575. }
  3576. }
  3577. }
  3578. ARRest := CurrValue - RangeMid(ARLRBracket)
  3579. ARBracket := LookupAffixBracket("data\AccuracyRating_Global.txt", ItemLevel, ARRest)
  3580. ValueRange := AddRange(ARBracket, ARLRBracket)
  3581. ValueRange := MarkAsGuesstimate(ValueRange)
  3582. NumSuffixes += 1
  3583. Goto, FinalizeAR
  3584. }
  3585. }
  3586. If (ItemBaseType == "Weapon" and HasIncrPhysDmg)
  3587. {
  3588. ; this is one of the trickiest cases currently: if this If-construct is reached that means the item has
  3589. ; multiple composites - "To Accuracy Rating / Increased Light Radius" and "Increased Physical Damage
  3590. ; / To Accuracy Rating". On top of that it might also contain part "To Accuracy Rating" suffix, all of
  3591. ; which are concatenated into one single "to Accuracy Rating" entry. Currently it handles most cases,
  3592. ; if not all, but I still have a feeling I am missing something...
  3593. If (ARPartial)
  3594. {
  3595. If (WithinBounds(ARPartial, CurrValue))
  3596. {
  3597. AffixType := "Comp. Prefix"
  3598. If (NumPrefixes < 3)
  3599. {
  3600. NumPrefixes += 1
  3601. }
  3602. ValueRange := LookupAffixData("data\AccuracyRating_IncrPhysDamage.txt", ItemLevel, RangeMid(ARPartial), "", CurrTier)
  3603. Goto, FinalizeAR
  3604. }
  3605.  
  3606. ARPartialMid := RangeMid(ARPartial)
  3607. ARRest := CurrValue - ARPartialMid
  3608. If (ItemSubType == "Mace" and ItemGripType == "2H")
  3609. {
  3610. ARBracket := LookupAffixBracket("data\AccuracyRating_Global.txt", ItemLevel, ARRest)
  3611. }
  3612. Else
  3613. {
  3614. ARBracket := LookupAffixBracket("data\AccuracyRating_Local.txt", ItemLevel, ARRest)
  3615. }
  3616.  
  3617. ; msgbox, ItemLevel: %ItemLevel%`, ARRest: %ARRest%`, ARBracket: %ARBracket%`, ARPartial: %ARPartial%
  3618.  
  3619. If (IsValidBracket(ARBracket))
  3620. {
  3621. AffixType := "Comp. Prefix+Suffix"
  3622. If (NumSuffixes < 3)
  3623. {
  3624. NumSuffixes += 1
  3625. }
  3626. Else
  3627. {
  3628. AffixType := "Comp. Prefix"
  3629. If (NumPrefixes < 3)
  3630. {
  3631. NumPrefixes += 2
  3632. }
  3633. }
  3634. NumPrefixes += 1
  3635. ; msgbox, ARBracket: %ARBracket%`, ARPartial: %ARPartial%
  3636. ValueRange := AddRange(ARBracket, ARPartial)
  3637. ValueRange := MarkAsGuesstimate(ValueRange)
  3638.  
  3639. Goto, FinalizeAR
  3640. }
  3641. }
  3642. Else
  3643. {
  3644. ActualValue := CurrValue
  3645. }
  3646.  
  3647. ValueRangeAR := LookupAffixBracket("data\AccuracyRating_Global.txt", ItemLevel, ActualValue)
  3648. If (IsValidBracket(ValueRangeAR))
  3649. {
  3650. If (NumPrefixes >= 3)
  3651. {
  3652. AffixType := "Suffix"
  3653. If (NumSuffixes < 3)
  3654. {
  3655. NumSuffixes += 1
  3656. }
  3657. ValueRange := LookupAffixData("data\AccuracyRating_Local.txt", ItemLevel, ActualValue, "", CurrTier)
  3658. }
  3659. Else
  3660. {
  3661. IfInString, IPDAffixType, Comp. Prefix
  3662. {
  3663. AffixType := "Comp. Prefix"
  3664. }
  3665. Else
  3666. {
  3667. AffixType := "Prefix"
  3668. }
  3669. NumPrefixes += 1
  3670. }
  3671. Goto, FinalizeAR
  3672. }
  3673. Else
  3674. {
  3675. ARValueRest := CurrValue - (RangeMid(ValueRangeAR))
  3676. If (HasIncrLightRadius and Not HasIncrAccuracyRating)
  3677. {
  3678. AffixType := "Comp. Prefix+Comp. Suffix+Suffix"
  3679. }
  3680. Else
  3681. {
  3682. AffixType := "Comp. Prefix+Suffix"
  3683. }
  3684. NumPrefixes += 1
  3685. NumSuffixes += 1
  3686. ; ValueRange := LookupAffixData("data\AccuracyRating_IncrPhysDamage.txt", ItemLevel, CurrValue, "", CurrTier)
  3687. ValueRange := AddRange(ARPartial, ValueRangeAR)
  3688. ValueRange := MarkAsGuesstimate(ValueRange)
  3689. }
  3690. ; NumPrefixes should be incremented already by "increased Physical Damage" case
  3691. Goto, FinalizeAR
  3692. }
  3693. AffixType := "Suffix"
  3694. ValueRange := LookupAffixData("data\AccuracyRating_Global.txt", ItemLevel, CurrValue, "", CurrTier)
  3695. NumSuffixes += 1
  3696. Goto, FinalizeAR
  3697.  
  3698. FinalizeAR:
  3699. If (StrLen(ARAffixTypePartial) > 0 AND (Not InStr(AffixType, ARAffixTypePartial)))
  3700. {
  3701. AffixType := ARAffixTypePartial . "+" . AffixType
  3702. If (InStr(ARAffixTypePartial, "Prefix") AND NumPrefixes < 3)
  3703. {
  3704. NumPrefixes += 1
  3705. }
  3706. Else If (InStr(ARAffixTypePartial, "Suffix") AND NumSuffixes < 3)
  3707. {
  3708. NumSuffixes += 1
  3709. }
  3710. ARAffixTypePartial =
  3711. }
  3712. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, AffixType, ValueRange, CurrTier), A_Index)
  3713. Continue
  3714. }
  3715.  
  3716. IfInString, A_LoopField, 物品稀有度
  3717. {
  3718. ActualValue := CurrValue
  3719. If (NumSuffixes <= 3)
  3720. {
  3721. ValueRange := LookupAffixBracket("data\IIR_Suffix.txt", ItemLevel, ActualValue)
  3722. ValueRangeAlt := LookupAffixBracket("data\IIR_Prefix.txt", ItemLevel, ActualValue)
  3723. }
  3724. Else
  3725. {
  3726. ValueRange := LookupAffixBracket("data\IIR_Prefix.txt", ItemLevel, ActualValue)
  3727. ValueRangeAlt := LookupAffixBracket("data\IIR_Suffix.txt", ItemLevel, ActualValue)
  3728. }
  3729. If (Not IsValidBracket(ValueRange))
  3730. {
  3731. If (Not IsValidBracket(ValueRangeAlt))
  3732. {
  3733. NumPrefixes += 1
  3734. NumSuffixes += 1
  3735. ; try to reverse engineer composition of both ranges
  3736. PrefixDivisor := 1
  3737. SuffixDivisor := 1
  3738. Loop
  3739. {
  3740. ValueRangeSuffix := LookupAffixBracket("data\IIR_Suffix.txt", ItemLevel, Floor(ActualValue/SuffixDivisor))
  3741. ValueRangePrefix := LookupAffixBracket("data\IIR_Prefix.txt", ItemLevel, Floor(ActualValue/PrefixDivisor))
  3742. If (Not IsValidBracket(ValueRangeSuffix))
  3743. {
  3744. SuffixDivisor += 0.25
  3745. }
  3746. If (Not IsValidBracket(ValueRangePrefix))
  3747. {
  3748. PrefixDivisor += 0.25
  3749. }
  3750. If ((IsValidBracket(ValueRangeSuffix)) and (IsValidBracket(ValueRangePrefix)))
  3751. {
  3752. Break
  3753. }
  3754. }
  3755. ValueRange := AddRange(ValueRangePrefix, ValueRangeSuffix)
  3756. Goto, FinalizeIIRAsPrefixAndSuffix
  3757. }
  3758. Else
  3759. {
  3760. ValueRange := ValueRangePrefix
  3761. Goto, FinalizeIIRAsPrefix
  3762. }
  3763. }
  3764. Else
  3765. {
  3766. If (NumSuffixes >= 3) {
  3767. Goto, FinalizeIIRAsPrefix
  3768. }
  3769. Goto, FinalizeIIRAsSuffix
  3770. }
  3771.  
  3772. FinalizeIIRAsPrefix:
  3773. NumPrefixes += 1
  3774. ValueRange := LookupAffixData("data\IIR_Prefix.txt", ItemLevel, ActualValue, "", CurrTier)
  3775. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix", ValueRange, CurrTier), A_Index)
  3776. Continue
  3777.  
  3778. FinalizeIIRAsSuffix:
  3779. NumSuffixes += 1
  3780. ValueRange := LookupAffixData("data\IIR_Suffix.txt", ItemLevel, ActualValue, "", CurrTier)
  3781. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Suffix", ValueRange, CurrTier), A_Index)
  3782. Continue
  3783.  
  3784. FinalizeIIRAsPrefixAndSuffix:
  3785. ValueRange := MarkAsGuesstimate(ValueRange)
  3786. AppendAffixInfo(MakeAffixDetailLine(A_LoopField, "Prefix+Suffix", ValueRange, CurrTier), A_Index)
  3787. Continue
  3788. }
  3789. }
  3790. }
  3791.  
  3792. ; change a detail line that was already processed and added to the
  3793. ; AffixLines "stack". This can be used for example to change the
  3794. ; affix type when more is known about a possible affix combo.
  3795. ; For example with a IPD / AR combo, if IPD was thought to be a
  3796. ; prefix but later (when processing AR) found to be a composite
  3797. ; prefix.
  3798. ChangeAffixDetailLine(PartialAffixString, SearchRegex, ReplaceRegex)
  3799. {
  3800. Global
  3801. Loop, %NumAffixLines%
  3802. {
  3803. CurAffixLine := AffixLines%A_Index%
  3804. IfInString, CurAffixLine, %PartialAffixString%
  3805. {
  3806. local NewLine
  3807. NewLine := RegExReplace(CurAffixLine, SearchRegex, ReplaceRegex)
  3808. AffixLines%A_Index% := NewLine
  3809. return True
  3810. }
  3811. }
  3812. return False
  3813. }
  3814.  
  3815. ExtractValueFromAffixLine(ItemDataChunk, PartialAffixString)
  3816. {
  3817. Loop, Parse, ItemDataChunk, `n, `r
  3818. {
  3819. If StrLen(A_LoopField) = 0
  3820. {
  3821. Break ; not interested in blank lines
  3822. }
  3823. IfInString, ItemDataChunk, Unidentified
  3824. {
  3825. Break ; not interested in unidentified items
  3826. }
  3827.  
  3828. CurrValue := GetActualValue(A_LoopField)
  3829.  
  3830. IfInString, A_LoopField, %PartialAffixString%
  3831. {
  3832. return CurrValue
  3833. }
  3834. }
  3835. }
  3836.  
  3837. ResetAffixDetailVars()
  3838. {
  3839. Global
  3840. NumPrefixes := 0
  3841. NumSuffixes := 0
  3842. TotalAffixes := 0
  3843. Loop, %NumAffixLines%
  3844. {
  3845. AffixLines%A_Index% =
  3846. }
  3847. Loop, 3
  3848. {
  3849. AffixLineParts%A_Index% =
  3850. }
  3851. }
  3852.  
  3853. IsEmptyString(String)
  3854. {
  3855. If (StrLen(String) == 0)
  3856. {
  3857. return True
  3858. }
  3859. Else
  3860. {
  3861. String := RegExReplace(String, "[\r\n ]", "")
  3862. If (StrLen(String) < 1)
  3863. {
  3864. return True
  3865. }
  3866. }
  3867. return False
  3868. }
  3869.  
  3870. PreProcessContents(CBContents)
  3871. {
  3872. ; place fixes for data inconsistencies here
  3873.  
  3874. ; I have not determined the reason for this, but a Heartbreaker - a unique - linked in chat
  3875. ; showed the following line below the Rarity: ... bit:
  3876. ; You cannot use this item. Its stats will be ignored. Please remove it.`n--------
  3877. ; This of course throws off subsequent parsing attempts so it is best to fix it beforehand.
  3878. Needle := "You cannot use this item. Its stats will be ignored. Please remove it.`r`n--------`r`n"
  3879. StringReplace, CBContents, CBContents, %Needle%,
  3880.  
  3881. return CBContents
  3882. }
  3883.  
  3884. PostProcessData(ParsedData)
  3885. {
  3886. Global CompactAffixTypes
  3887. If (CompactAffixTypes > 0)
  3888. {
  3889. StringReplace, TempResult, ParsedData, --------, ``, All
  3890. StringSplit, ParsedDataParts, TempResult, ``
  3891.  
  3892. NameAndDPSPart := ParsedDataParts1
  3893. SecondPart := ParsedDataParts2 ; total affix statistics for rare items or implicit mods for unique items
  3894. ThirdPart := ParsedDataParts3 ; affix composition for rare and unique items
  3895. FourthPart := ParsedDataParts4 ; Valuable line for unique items
  3896.  
  3897. ThirdPart := RegExReplace(ThirdPart, "Comp\. ", "複合")
  3898. ThirdPart := RegExReplace(ThirdPart, "Suffix", "後綴")
  3899. ThirdPart := RegExReplace(ThirdPart, "Prefix", "前綴")
  3900.  
  3901. ParsedData := NameAndDPSPart
  3902. If (Not IsEmptyString(SecondPart)) ; two because of possible newline control chars
  3903. {
  3904. ParsedData := ParsedData . "--------" . SecondPart
  3905. }
  3906. If (Not IsEmptyString(ThirdPart))
  3907. {
  3908. ParsedData := ParsedData . "--------" . ThirdPart
  3909. }
  3910. If (Not IsEmptyString(FourthPart))
  3911. {
  3912. ParsedData := ParsedData . "--------" . FourthPart
  3913. }
  3914. }
  3915.  
  3916. return ParsedData
  3917. }
  3918.  
  3919. ParseClipBoardChanges()
  3920. {
  3921. Global PutResultsOnClipboard
  3922.  
  3923. CBContents := GetClipboardContents()
  3924. CBContents := PreProcessContents(CBContents)
  3925.  
  3926. ParsedData := ParseItemData(CBContents)
  3927. ParsedData := PostProcessData(ParsedData)
  3928.  
  3929. If (PutResultsOnClipboard > 0)
  3930. {
  3931. SetClipboardContents(ParsedData)
  3932. }
  3933. ShowToolTip(ParsedData)
  3934. }
  3935.  
  3936. AssembleDamageDetails(FullItemData)
  3937. {
  3938. PhysLo := 0
  3939. PhysHi := 0
  3940. Quality := 0
  3941. AttackSpeed := 0
  3942. PhysMult := 0
  3943. ChaoLo := 0
  3944. ChaoHi := 0
  3945. ColdLo := 0
  3946. ColdHi := 0
  3947. FireLo := 0
  3948. FireHi := 0
  3949. LighLo := 0
  3950. LighHi := 0
  3951.  
  3952. Loop, Parse, FullItemData, `n, `r
  3953. {
  3954. ; Get quality
  3955. IfInString, A_LoopField, 品質:
  3956. {
  3957. StringSplit, Arr, A_LoopField, %A_Space%, +`%
  3958. Quality := Arr2
  3959. Continue
  3960. }
  3961.  
  3962. ; Get total physical damage
  3963. IfInString, A_LoopField, 物理傷害:
  3964. {
  3965. ; IsWeapon := True
  3966. StringSplit, Arr, A_LoopField, %A_Space%
  3967. StringSplit, Arr, Arr2, -
  3968. PhysLo := Arr1
  3969. PhysHi := Arr2
  3970. Continue
  3971. }
  3972.  
  3973. ; Fix for Elemental damage only weapons. Like the Oro's Sacrifice
  3974. IfInString, A_LoopField, 元素傷害:
  3975. {
  3976. Continue
  3977. }
  3978.  
  3979. ; Get attack speed
  3980. IfInString, A_LoopField, 每秒攻擊次數:
  3981. {
  3982. StringSplit, Arr, A_LoopField, %A_Space%
  3983. AttackSpeed := Arr2
  3984. Continue
  3985. }
  3986.  
  3987. ; Get percentage physical damage increase
  3988. IfInString, A_LoopField, 物理傷害
  3989. {
  3990. IfInString, A_LoopField, 增加
  3991. {
  3992. StringSplit, Arr, A_LoopField, %A_Space%, `%
  3993. PhysMult := Arr2
  3994. Continue
  3995. }
  3996. }
  3997.  
  3998. ;Lines to skip fix for converted type damage. Like the Voltaxic Rift
  3999. IfInString, A_LoopField, 轉換為
  4000. Goto, SkipDamageParse
  4001. IfInString, A_LoopField, 可以感電
  4002. Goto, SkipDamageParse
  4003.  
  4004. ; Lines to skip for weapons that alter damage based on if equipped as
  4005. ; main or off hand. In that case skipp the off hand calc and just use
  4006. ; main hand as determining factor. Examples: Dyadus, Wings of Entropy
  4007. IfInString, A_LoopField, 在副手
  4008. Goto, SkipDamageParse
  4009.  
  4010. ; Parse elemental damage
  4011. ParseElementalDamage(A_LoopField, "混沌", ChaoLo, ChaoHi)
  4012. ParseElementalDamage(A_LoopField, "冰冷", ColdLo, ColdHi)
  4013. ParseElementalDamage(A_LoopField, "火焰", FireLo, FireHi)
  4014. ParseElementalDamage(A_LoopField, "閃電", LighLo, LighHi)
  4015.  
  4016. SkipDamageParse:
  4017. DoNothing := True
  4018. }
  4019.  
  4020. Result =
  4021.  
  4022. SetFormat, FloatFast, 5.1
  4023. PhysDps := ((PhysLo + PhysHi) / 2) * AttackSpeed
  4024. EleDps := ((ChaoLo + ChaoHi + ColdLo + ColdHi + FireLo + FireHi + LighLo + LighHi) / 2) * AttackSpeed
  4025. TotalDps := PhysDps + EleDps
  4026.  
  4027. Result = %Result%`n 物理 DPS: %PhysDps%`n 元素 DPS: %EleDps%`n 總合 DPS: %TotalDps%
  4028.  
  4029. ; Only show Q20 values if item is not Q20
  4030. If (Quality < 20) {
  4031. TotalPhysMult := (PhysMult + Quality + 100) / 100
  4032. BasePhysDps := PhysDps / TotalPhysMult
  4033. Q20Dps := BasePhysDps * ((PhysMult + 120) / 100) + EleDps
  4034.  
  4035. Result = %Result%`n Q20 DPS: %Q20Dps%
  4036. }
  4037. return Result
  4038. }
  4039.  
  4040. ParseItemName(ItemDataChunk, ByRef ItemName, ByRef ItemTypeName)
  4041. {
  4042. Loop, Parse, ItemDataChunk, `n, `r
  4043. {
  4044. If (A_Index == 1)
  4045. {
  4046. IfNotInString, A_LoopField, Rarity:
  4047. {
  4048. return
  4049. }
  4050. Else
  4051. {
  4052. Continue
  4053. }
  4054. }
  4055. If (StrLen(A_LoopField) == 0 or A_LoopField == "--------" or A_Index > 3)
  4056. {
  4057. return
  4058. }
  4059. If (A_Index = 2)
  4060. {
  4061. ItemName := A_LoopField
  4062. }
  4063. If (A_Index = 3)
  4064. {
  4065. ItemTypeName := A_LoopField
  4066. }
  4067. }
  4068. }
  4069.  
  4070. GemIsValuable(ItemName)
  4071. {
  4072. Loop, Read, %A_WorkingDir%\data\ValuableGems.txt
  4073. {
  4074. IfInString, ItemName, %A_LoopReadLine%
  4075. {
  4076. return True
  4077. }
  4078. }
  4079. return False
  4080. }
  4081.  
  4082. UniqueIsValuable(ItemName)
  4083. {
  4084. Loop, Read, %A_WorkingDir%\data\ValuableUniques.txt
  4085. {
  4086. IfInString, ItemName, %A_LoopReadLine%
  4087. {
  4088. return True
  4089. }
  4090. }
  4091. return False
  4092. }
  4093.  
  4094. GemIsDropOnly(ItemName)
  4095. {
  4096. Loop, Read, %A_WorkingDir%\data\DropOnlyGems.txt
  4097. {
  4098. IfInString, ItemName, %A_LoopReadLine%
  4099. {
  4100. return True
  4101. }
  4102. }
  4103. return False
  4104. }
  4105.  
  4106. ParseLinks(ItemData)
  4107. {
  4108. HighestLink := 0
  4109. Loop, Parse, ItemData, `n, `r
  4110. {
  4111. IfInString, A_LoopField, Sockets
  4112. {
  4113. LinksString := GetColonValue(A_LoopField)
  4114. If (RegExMatch(LinksString, ".-.-.-.-.-."))
  4115. {
  4116. HighestLink := 6
  4117. Break
  4118. }
  4119. If (RegExMatch(LinksString, ".-.-.-.-."))
  4120. {
  4121. HighestLink := 5
  4122. Break
  4123. }
  4124. If (RegExMatch(LinksString, ".-.-.-."))
  4125. {
  4126. HighestLink := 4
  4127. Break
  4128. }
  4129. If (RegExMatch(LinksString, ".-.-."))
  4130. {
  4131. HighestLink := 3
  4132. Break
  4133. }
  4134. If (RegExMatch(LinksString, ".-."))
  4135. {
  4136. HighestLink := 2
  4137. Break
  4138. }
  4139. }
  4140. }
  4141. return HighestLink
  4142. }
  4143.  
  4144. ; converts a currency stack to chaos
  4145. ; by looking up the conversion ratio
  4146. ; from CurrencyRates.txt
  4147. ConvertCurrency(ItemName, ItemStats)
  4148. {
  4149. If (InStr(ItemName, "碎片"))
  4150. {
  4151. If (InStr(ItemName, "卷軸"))
  4152. {
  4153. IsFragment := True
  4154. ItemName := "知識卷軸"
  4155. }
  4156. Else
  4157. {
  4158. IsShard := True
  4159. ItemName := SubStr(ItemName, 1, 3)
  4160. }
  4161. }
  4162. StackSize := SubStr(ItemStats, StrLen("堆疊數量: "))
  4163. StringSplit, StackSizeParts, StackSize, /
  4164. If (IsShard or IsFragment)
  4165. {
  4166. SetFormat, FloatFast, 5.3
  4167. StackSize := StackSizeParts1 / StackSizeParts2
  4168. }
  4169. Else
  4170. {
  4171. SetFormat, FloatFast, 5.2
  4172. StackSize := StackSizeParts1
  4173. }
  4174. ValueInChaos :=
  4175. Loop, Read, %A_WorkingDir%\data\CurrencyRates.txt
  4176. {
  4177. IfInString, A_LoopReadLine, `;
  4178. {
  4179. ; comment
  4180. Continue
  4181. }
  4182. If (StrLen(A_LoopReadLine) <= 2)
  4183. {
  4184. ; blank line (at most \r\n)
  4185. Continue
  4186. }
  4187. IfInString, A_LoopReadLine, %ItemName%
  4188. {
  4189. StringSplit, LineParts, A_LoopReadLine, |
  4190. ChaosRatio := LineParts2
  4191. StringSplit, ChaosRatioParts,ChaosRatio, :
  4192. ChaosMult := ChaosRatioParts2 / ChaosRatioParts1
  4193. ValueInChaos := (ChaosMult * StackSize)
  4194. ; msgbox, Name: %ItemName%`, StackSize: %StackSize%`, ChaosMult: %ChaosMult%`, ValueInChaos: %ValueInChaos%
  4195. }
  4196. }
  4197. return ValueInChaos
  4198. }
  4199.  
  4200. ; Parse unique affixes from text file database.
  4201. ; Has wanted side effect of populating AffixLines "array" vars.
  4202. ; return True if the unique was found the database
  4203. ParseUnique(ItemName)
  4204. {
  4205. Global
  4206. Local Delim
  4207. Delim := "|"
  4208. ResetAffixDetailVars()
  4209. UniqueFound := False
  4210. Loop, Read, %A_WorkingDir%\data\Uniques.txt
  4211. {
  4212. IfInString, A_LoopReadLine, `;
  4213. {
  4214. ; comment
  4215. Continue
  4216. }
  4217. If (StrLen(A_LoopReadLine) <= 2)
  4218. {
  4219. ; blank line
  4220. ; 2 characters at most: \r\n. Don't bother
  4221. ; checking if they are actually control chars
  4222. ; or normal letters.
  4223. Continue
  4224. }
  4225. IfInString, A_LoopReadLine, %ItemName%
  4226. {
  4227. StringSplit, LineParts, A_LoopReadLine, |
  4228. NumLineParts := LineParts0
  4229. NumAffixLines := NumLineParts-1 ; exclude item name at first pos
  4230. Local UniqueFound
  4231. UniqueFound := True
  4232. Local AppendImplicitSep
  4233. AppendImplicitSep := False
  4234. Idx := 1
  4235. Loop, % (NumLineParts)
  4236. {
  4237. If (A_Index > 1)
  4238. {
  4239. Local CurLinePart
  4240. Local AffixLine
  4241. Local ValueRange
  4242. CurLinePart := LineParts%A_Index%
  4243. IfInString, CurLinePart, :
  4244. {
  4245. StringSplit, CurLineParts, CurLinePart, :
  4246. AffixLine := CurLineParts2
  4247. ValueRange := CurLineParts1
  4248. IfInString, ValueRange, @
  4249. {
  4250. AppendImplicitSep := True
  4251. StringReplace, ValueRange, ValueRange, @
  4252. }
  4253. ; Make "Attacks per Second" float ranges to be like a double range.
  4254. ; Since a 2 decimal precision float value is 4 chars wide (#.##)
  4255. ; when including the radix point this means a float value range
  4256. ; is then 9 chars wide. Replacing the "-" with a "," effectively
  4257. ; makes it so that float ranges are treated as double ranges and
  4258. ; distributes the bounds over both value range fields. This may
  4259. ; or may not be desirable. On the plus side things will align
  4260. ; nicely, but on the negative side, it will be a bit unclearer that
  4261. ; both float values constitute a range and not two isolated values.
  4262. ValueRange := RegExReplace(ValueRange, "(\d+\.\d+)-(\d+\.\d+)", "$1,$2")
  4263. IfInString, ValueRange, `,
  4264. {
  4265. ; double range
  4266. StringSplit, ValueRangeParts, ValueRange, `,
  4267. Local ValueRangeParts
  4268. Local LowerBound
  4269. Local UpperBound
  4270. LowerBound := ValueRangeParts1
  4271. UpperBound := ValueRangeParts2
  4272. ValueRange := StrPad(LowerBound, ValueRangeFieldWidth, "left") . AffixDetailDelimiter . StrPad(UpperBound, ValueRangeFieldWidth, "left")
  4273. }
  4274. ProcessedLine := AffixLine . Delim . StrPad(ValueRange, ValueRangeFieldWidth, "left")
  4275. If (AppendImplicitSep)
  4276. {
  4277. ProcessedLine := ProcessedLine . "`n" . "--------"
  4278. AppendImplicitSep := False
  4279. }
  4280. AffixLines%Idx% := ProcessedLine
  4281. }
  4282. Else
  4283. {
  4284. AffixLines%Idx% := CurLinePart
  4285. }
  4286. Idx += 1
  4287. }
  4288. }
  4289. }
  4290. }
  4291.  
  4292. return UniqueFound
  4293. }
  4294.  
  4295. ; Main parse function
  4296. ParseItemData(ItemData, ByRef RarityLevel="", ByRef NumPrefixes="", ByRef NumSuffixes="")
  4297. {
  4298. ; global var access to support user options
  4299. Global ShowItemLevel
  4300. Global ShowMaxSockets
  4301. Global ShowDamageCalculations
  4302. Global ShowAffixTotals
  4303. Global ShowAffixDetails
  4304. Global ShowCurrencyValueInChaos
  4305. Global ShowGemEvaluation
  4306. Global ShowUniqueEvaluation
  4307. Global GemQualityValueThreshold
  4308. Global MarkHighLinksAsValuable
  4309.  
  4310. ; these 4 actually need to be global because
  4311. ; they are used in other functions
  4312. Global ItemBaseType
  4313. Global ItemSubType
  4314. Global ItemGripType
  4315. Global ItemDataRarity
  4316.  
  4317. ; marked " ; d" for debugging (to easily search & replace)
  4318. ; Global ItemData ; d
  4319. ; Global IsWeapon ; d
  4320. ; Global IsUnidentified ; d
  4321. ; Global IsCurrency ; d
  4322. ; Global ItemLevel ; d
  4323. ; Global ItemDataNamePlate ; d
  4324. ; Global ItemDataStats ; d
  4325. ; Global ItemDataRequirements ; d
  4326. ; Global RequiredAttributes ; d
  4327. ; Global ItemName ; d
  4328. ; Global ItemTypeName ; d
  4329. ; Global RequiredLevel ; d
  4330. ; Global RequiredAttributeValues ; d
  4331. ; Global ItemQuality ; d
  4332. ; Global ItemDataPartsIndexLast ; d
  4333. ; Global ItemDataPartsLast ; d
  4334. ; Global RarityLevel ; d
  4335. ; Global IsFlask ; d
  4336. ; Global IsUnique ; d
  4337. ; Global ItemDataImplicitMods ; d
  4338. ; Global NumPrefixes ; d
  4339. ; Global NumSuffixes ; d
  4340. ; Global NumAffixLines ; d
  4341. ; Global TotalAffixes ; d
  4342. ; Global ItemDataAffixes ; d
  4343. ; Global ItemDataStats ; d
  4344. ; Global AugmentedStats ; d
  4345.  
  4346. ; ItemDataParts0 =
  4347. ; Loop, 10
  4348. ; {
  4349. ; ItemDataParts%A_Index% =
  4350. ; }
  4351.  
  4352. ItemDataPartsIndexLast =
  4353. ItemDataPartsIndexAffixes =
  4354. ItemDataPartsLast =
  4355. ItemDataNamePlate =
  4356. ItemDataStats =
  4357. ItemDataAffixes =
  4358. ItemDataRequirements =
  4359. ItemDataRarity =
  4360. ItemDataLinks =
  4361. ItemName =
  4362. ItemTypeName =
  4363. ItemQuality =
  4364. ItemLevel =
  4365. ItemMaxSockets =
  4366. BaseLevel =
  4367. RarityLevel =
  4368. TempResult =
  4369.  
  4370. IsWeapon := False
  4371. IsQuiver := False
  4372. IsFlask := False
  4373. IsGem := False
  4374. IsCurrency := False
  4375. IsUnidentified := False
  4376. IsBelt := False
  4377. IsRing := False
  4378. IsUnsetRing := False
  4379. IsBow := False
  4380. IsAmulet := False
  4381. IsSingleSocket := False
  4382. IsFourSocket := False
  4383. IsThreeSocket := False
  4384. IsMap := False
  4385. IsUnique := False
  4386. IsRare := False
  4387.  
  4388. ItemBaseType =
  4389. ItemSubType =
  4390. ItemGripType =
  4391.  
  4392. ; AHK only allows splitting on single chars, so first
  4393. ; replace the split string (\r\n--------\r\n) with AHK's escape char (`)
  4394. ; then do the actual string splitting...
  4395. StringReplace, TempResult, ItemData, `r`n--------`r`n, ``, All
  4396. StringSplit, ItemDataParts, TempResult, ``,
  4397.  
  4398. ItemDataNamePlate := ItemDataParts1
  4399. ItemDataStats := ItemDataParts2
  4400. ItemDataRequirements := ItemDataParts3
  4401.  
  4402. ; ParseRequirements(ItemDataRequirements, RequiredLevel, RequiredAttributes, RequiredAttributeValues)
  4403. ; msgbox, RequiredLevel: %RequiredLevel%`, RequiredAttributes: %RequiredAttributes%`, RequiredAttributeValues: %RequiredAttributeValues%
  4404.  
  4405. ParseItemName(ItemDataNamePlate, ItemName, ItemTypeName)
  4406.  
  4407. ; assign length of the "array" so we can either grab the
  4408. ; last item (if non unique) or the item before last
  4409. ItemDataPartsIndexLast := ItemDataParts0
  4410. ItemDataPartsLast := ItemDataParts%ItemDataPartsIndexLast%
  4411. IfInString, ItemDataPartsLast, Unidentified
  4412. {
  4413. IsUnidentified := True
  4414. }
  4415.  
  4416. ItemQuality := ParseQuality(ItemDataStats)
  4417.  
  4418. ; this function should return the second part of the "Rarity: ..." line
  4419. ; in the case of "Rarity: Unique" it should return "Unique"
  4420. ItemDataRarity := ParseRarity(ItemDataNamePlate)
  4421.  
  4422. ItemDataLinks := ParseLinks(ItemData)
  4423.  
  4424. IsUnique := False
  4425. IfInString, ItemDataRarity, Unique
  4426. {
  4427. IsUnique := True
  4428. }
  4429.  
  4430. IfInString, ItemDataRarity, Rare
  4431. {
  4432. IsRare := True
  4433. }
  4434.  
  4435. IsGem := (InStr(ItemDataRarity, "Gem"))
  4436. IsCurrency := (InStr(ItemDataRarity, "Currency"))
  4437.  
  4438. If (IsGem)
  4439. {
  4440. RarityLevel := 0
  4441. ItemLevel := ParseItemLevel(ItemData, "Level:")
  4442. ItemLevelWord := "寶石等級:"
  4443. }
  4444. Else
  4445. {
  4446. If (IsCurrency and ShowCurrencyValueInChaos == 1)
  4447. {
  4448. ValueInChaos := ConvertCurrency(ItemName, ItemDataStats)
  4449. If (ValueInChaos)
  4450. {
  4451. CurrencyDetails := ValueInChaos . "混沌石"
  4452. }
  4453. }
  4454. Else
  4455. {
  4456. RarityLevel := CheckRarityLevel(ItemDataRarity)
  4457. ItemLevel := ParseItemLevel(ItemData)
  4458. ItemLevelWord := "物品等級:"
  4459. ParseItemType(ItemDataStats, ItemDataNamePlate, ItemBaseType, ItemSubType, ItemGripType)
  4460. }
  4461. }
  4462.  
  4463. IsBow := (ItemSubType == "Bow")
  4464. IsFlask := (ItemSubType == "Flask")
  4465. IsBelt := (ItemSubType == "Belt")
  4466. IsRing := (ItemSubType == "Ring")
  4467. IsUnsetRing := (IsRing and InStr(ItemDataNamePlate, "Unset Ring"))
  4468. IsAmulet := (ItemSubType == "Amulet")
  4469. IsSingleSocket := (IsUnsetRing)
  4470. IsFourSocket := (ItemSubType == "Gloves" or ItemSubType == "Boots" or ItemSubType == "Helmet")
  4471. IsThreeSocket := ((ItemGripType == "1H" or ItemSubType == "Shield") and Not IsBow)
  4472. IsQuiver := (ItemSubType == "Quiver")
  4473. IsWeapon := (ItemBaseType == "Weapon")
  4474. IsMap := (ItemBaseType == "Map")
  4475.  
  4476. If (Not ItemName)
  4477. {
  4478. return
  4479. }
  4480.  
  4481. If (IsFlask or IsUnique)
  4482. {
  4483. ; uniques as well as flasks have descriptive text as last item,
  4484. ; so decrement item index to get to the item before last one
  4485. ItemDataPartsIndexAffixes := ItemDataPartsIndexLast - 1
  4486. }
  4487. Else
  4488. {
  4489. ItemDataPartsIndexAffixes := ItemDataPartsIndexLast
  4490. }
  4491.  
  4492. If (ItemDataPartsIndexAffixes = 0)
  4493. {
  4494. ; ItemDataParts doesn't have the parts/text we need. Bail.
  4495. ; This might be because the clipboard is completely empty.
  4496. return
  4497. }
  4498.  
  4499. ; hopefully this should now hold the part of the text that
  4500. ; deals with affixes
  4501. ItemDataAffixes := ItemDataParts%ItemDataPartsIndexAffixes%
  4502.  
  4503. ItemDataStats := ItemDataParts%ItemDataParts%2
  4504.  
  4505. If (RarityLevel > 1)
  4506. {
  4507. ParseAffixes(ItemDataAffixes, ItemLevel, ItemQuality, NumPrefixes, NumSuffixes)
  4508. TotalAffixes := NumPrefixes + NumSuffixes
  4509. }
  4510.  
  4511. ; Start assembling the text for the tooltip
  4512. TT := ItemName
  4513. If (ItemTypeName)
  4514. {
  4515. TT := TT . "`n" . ItemTypeName
  4516. }
  4517.  
  4518. If (ShowItemLevel == 1 and Not IsMap)
  4519. {
  4520. TT := TT . "`n"
  4521. TT := TT . ItemLevelWord . " " . StrPad(ItemLevel, 3, Side="left")
  4522. If (Not IsFlask)
  4523. {
  4524. BaseLevel := CheckBaseLevel(ItemTypeName)
  4525. If (BaseLevel)
  4526. {
  4527. TT := TT . "`n" . "Base Level: " . StrPad(BaseLevel, 3, Side="left")
  4528. }
  4529. }
  4530. }
  4531.  
  4532. If (ShowMaxSockets == 1 and Not (IsFlask or IsGem or IsCurrency or IsBelt or IsQuiver or IsMap or IsAmulet))
  4533. {
  4534. If (ItemLevel >= 50)
  4535. {
  4536. ItemMaxSockets = 6
  4537. }
  4538. Else If (ItemLevel >= 35)
  4539. {
  4540. ItemMaxSockets = 5
  4541. }
  4542. Else If (ItemLevel >= 28)
  4543. {
  4544. ItemMaxSockets = 4
  4545. }
  4546. Else If (ItemLevel >= 15)
  4547. {
  4548. ItemMaxSockets = 3
  4549. }
  4550. Else
  4551. {
  4552. ItemMaxSockets = 2
  4553. }
  4554.  
  4555. If(IsFourSocket and ItemMaxSockets > 4)
  4556. {
  4557. ItemMaxSockets = 4
  4558. }
  4559. Else If(IsThreeSocket and ItemMaxSockets > 3)
  4560. {
  4561. ItemMaxSockets = 3
  4562. }
  4563. Else If(IsSingleSocket)
  4564. {
  4565. ItemMaxSockets = 1
  4566. }
  4567.  
  4568. If (Not IsRing or IsUnsetRing)
  4569. {
  4570. TT := TT . "`n"
  4571. TT := TT . "最大詞綴數: "
  4572. TT := TT . ItemMaxSockets
  4573. }
  4574. }
  4575.  
  4576. If (IsGem and ShowGemEvaluation == 1)
  4577. {
  4578. SepAdded := False
  4579. If (ItemQuality > 0)
  4580. {
  4581. TT = %TT%`n--------
  4582. SepAdded := True
  4583. TT = %TT%`n+%ItemQuality%`%
  4584. }
  4585. If (ItemQuality >= GemQualityValueThreshold or GemIsValuable(ItemName))
  4586. {
  4587. If (Not SepAdded)
  4588. {
  4589. TT = %TT%`n--------
  4590. SepAdded := True
  4591. }
  4592. TT = %TT%`nValuable
  4593. }
  4594. If (GemIsDropOnly(ItemName))
  4595. {
  4596. If (Not SepAdded)
  4597. {
  4598. TT = %TT%`n--------
  4599. SepAdded := True
  4600. }
  4601. TT = %TT%`nDrop Only
  4602. }
  4603. }
  4604.  
  4605. If (IsCurrency)
  4606. {
  4607. TT = %TT%%CurrencyDetails%
  4608. }
  4609.  
  4610. If (IsWeapon and ShowDamageCalculations == 1)
  4611. {
  4612. TT := TT . AssembleDamageDetails(ItemData)
  4613. }
  4614.  
  4615. If (IsMap)
  4616. {
  4617. Global mapList
  4618. Global uniqueMapList
  4619. if (IsUnique)
  4620. {
  4621. MapDescription := uniqueMapList[ItemSubType]
  4622. }
  4623. else
  4624. {
  4625. MapDescription := mapList[ItemSubType]
  4626. }
  4627.  
  4628. TT = %TT%`n%MapDescription%
  4629. }
  4630.  
  4631. ; Append affix info if rarity is greater than normal (white)
  4632. ; Affix total statistic
  4633. If (ShowAffixTotals = 1)
  4634. {
  4635. If (RarityLevel > 1 and RarityLevel < 4)
  4636. {
  4637. If (NumPrefixes = 1)
  4638. {
  4639. WordPrefixes = 前綴
  4640. }
  4641. Else
  4642. {
  4643. WordPrefixes = 前綴
  4644. }
  4645. If (NumSuffixes = 1)
  4646. {
  4647. WordSuffixes = 後綴
  4648. }
  4649. Else
  4650. {
  4651. WordSuffixes = 後綴
  4652. }
  4653.  
  4654. PrefixLine =
  4655. If (NumPrefixes > 0)
  4656. {
  4657. PrefixLine = `n %NumPrefixes% %WordPrefixes%
  4658. }
  4659.  
  4660. SuffixLine =
  4661. If (NumSuffixes > 0)
  4662. {
  4663. SuffixLine = `n %NumSuffixes% %WordSuffixes%
  4664. }
  4665.  
  4666. AffixStats =
  4667. If (TotalAffixes > 0 and Not IsUnidentified)
  4668. {
  4669. AffixStats = 目前詞綴數 (%TotalAffixes%):%PrefixLine%%SuffixLine%
  4670. TT = %TT%`n--------`n%AffixStats%
  4671. }
  4672. }
  4673. Else
  4674. {
  4675. If (ItemDataRarity == "Unique")
  4676. {
  4677. If (ParseUnique(ItemName))
  4678. {
  4679. AffixDetails := AssembleAffixDetails()
  4680. TT = %TT%`n--------%AffixDetails%
  4681. }
  4682. Else If(Not IsMap)
  4683. {
  4684. If (IsUnidentified)
  4685. {
  4686. TT = %TT%`n--------`nUnidentified
  4687. }
  4688. Else
  4689. {
  4690. TT = %TT%`n--------`nUnique item currently not supported
  4691. }
  4692. }
  4693. }
  4694. }
  4695. }
  4696.  
  4697. ; Detailed affix range infos
  4698. If (ShowAffixDetails = 1)
  4699. {
  4700. If (Not IsFlask AND Not IsUnidentified)
  4701. {
  4702. If (RarityLevel > 1 AND RarityLevel < 4)
  4703. {
  4704. AffixDetails := AssembleAffixDetails()
  4705. TT = %TT%`n--------%AffixDetails%
  4706. }
  4707. Else If ((ItemDataRarity == "Unique"))
  4708. {
  4709. If (Not ShowAffixTotals)
  4710. {
  4711. ParseUnique(ItemName)
  4712. TT = %TT%`n--------%AffixDetails%
  4713. }
  4714. }
  4715. }
  4716. }
  4717.  
  4718. If ((IsUnique AND (ShowUniqueEvaluation == 1) AND UniqueIsValuable(ItemName)) OR (MarkHighLinksAsValuable = 1 AND (IsUnique OR IsRare) AND ItemDataLinks >= 5))
  4719. {
  4720. TT = %TT%`n--------`nValuable
  4721. }
  4722.  
  4723. ;msgbox, %TT%
  4724. return TT
  4725. }
  4726.  
  4727. ; Show tooltip, with fixed width font
  4728. ShowToolTip(String)
  4729. {
  4730. ; Get position of mouse cursor
  4731. Global X
  4732. Global Y
  4733. MouseGetPos, X, Y
  4734.  
  4735. ToolTip, %String%, X - 135, Y + 35
  4736. Global FixedFont
  4737. SetFont(FixedFont)
  4738.  
  4739. ; Set up count variable and start timer for tooltip timeout
  4740. Global ToolTipTimeout := 0
  4741. SetTimer, ToolTipTimer, 100
  4742. }
  4743.  
  4744. ; ############## TESTS #################
  4745.  
  4746. TestCaseSeparator := "####################"
  4747.  
  4748. RunRareTestSuite(Path, SuiteNumber)
  4749. {
  4750. Global TestCaseSeparator
  4751.  
  4752. NumTestCases := 0
  4753. Loop, Read, %Path%
  4754. {
  4755. ; msgbox, % TestCaseText
  4756. IfInString, A_LoopReadLine, %TestCaseSeparator%
  4757. {
  4758. NumTestCases += 1
  4759. Continue
  4760. }
  4761. TestCaseText := A_LoopReadLine
  4762. TestCases%NumTestCases% := TestCases%NumTestCases% . TestCaseText . "`r`n"
  4763. }
  4764.  
  4765. ; msgbox, NumTestCases: %NumTestCases%
  4766. Failures := 0
  4767. Successes := 0
  4768. FailureNumbers =
  4769. TestCase =
  4770. Loop, %NumTestCases%
  4771. {
  4772. TestCase := TestCases%A_Index%
  4773.  
  4774. NumPrefixes := 0
  4775. NumSuffixes := 0
  4776. RarityLevel := 0
  4777. TestCaseResult := ParseItemData(TestCase, RarityLevel, NumPrefixes, NumSuffixes)
  4778.  
  4779. StringReplace, TempResult, TestCaseResult, --------, ``, All
  4780. StringSplit, TestCaseResultParts, TempResult, ``
  4781.  
  4782. NameAndDPSPart := TestCaseResultParts1
  4783. TotalAffixStatsPart := TestCaseResultParts2
  4784. AffixCompositionPart := TestCaseResultParts3
  4785.  
  4786. ; failure conditions
  4787. TotalAffixes := 0
  4788. TotalAffixes := NumPrefixes + NumSuffixes
  4789. InvalidTotalAffixNumber := (TotalAffixes > 6)
  4790. BracketLookupFailed := InStr(TestCaseResult, "n/a")
  4791. CompositeRangeCalcFailed := InStr(TestCaseResult, " - ")
  4792.  
  4793. Prefixes := 0
  4794. Suffixes := 0
  4795. CompPrefixes := 0
  4796. CompSuffixes := 0
  4797. ExtractTotalAffixBalance(AffixCompositionPart, Prefixes, Suffixes, CompPrefixes, CompSuffixes)
  4798.  
  4799. HasDanglingComposites := False
  4800. If (Mod(CompPrefixes, 2)) ; True, if not evenly divisible by 2
  4801. {
  4802. HasDanglingComposites := True
  4803. }
  4804. If (Mod(CompSuffixes, 2))
  4805. {
  4806. HasDanglingComposites := True
  4807. }
  4808.  
  4809. TotalCountByAffixTypes := (Floor(CompPrefixes / 2) + Floor(CompSuffixes / 2) + Prefixes + Suffixes)
  4810.  
  4811. ; msgbox, TotalAffixes: %TotalAffixes%`, TotalCountByAffixTypes: %TotalCountByAffixTypes%
  4812. AffixTypesCountedIncorrectly := (Not (TotalCountByAffixTypes == TotalAffixes))
  4813. If (InvalidTotalAffixNumber or BracketLookupFailed or CompositeRangeCalcFailed or HasDanglingComposites or AffixTypesCountedIncorrectly)
  4814. {
  4815. Failures += 1
  4816. FailureNumbers := FailureNumbers . A_Index . ","
  4817. }
  4818. Else
  4819. {
  4820. Successes += 1
  4821. }
  4822. ; needed so global variables can be yanked from memory and reset between calls
  4823. ; (if you reload the script really fast globals vars that are out of date can
  4824. ; cause failures when there are none)
  4825. Sleep, 1
  4826. }
  4827.  
  4828. Result := "Suite " . SuiteNumber . ": " . StrPad(Successes, 5, "left") . " OK" . ", " . StrPad(Failures, 5, "left") . " Failed"
  4829. If (Failures > 0)
  4830. {
  4831. FailureNumbers := SubStr(FailureNumbers, 1, -1)
  4832. Result := Result . " (" . FailureNumbers . ")"
  4833. }
  4834. return Result
  4835. }
  4836.  
  4837. RunUniqueTestSuite(Path, SuiteNumber)
  4838. {
  4839. Global TestCaseSeparator
  4840.  
  4841. NumTestCases := 0
  4842. Loop, Read, %Path%
  4843. {
  4844. IfInString, A_LoopReadLine, %TestCaseSeparator%
  4845. {
  4846. NumTestCases += 1
  4847. Continue
  4848. }
  4849. TestCaseText := A_LoopReadLine
  4850. TestCases%NumTestCases% := TestCases%NumTestCases% . TestCaseText . "`r`n"
  4851. }
  4852.  
  4853. Failures := 0
  4854. Successes := 0
  4855. FailureNumbers =
  4856. TestCase =
  4857. Loop, %NumTestCases%
  4858. {
  4859. TestCase := TestCases%A_Index%
  4860. TestCaseResult := ParseItemData(TestCase)
  4861.  
  4862. FailedToSepImplicit := InStr(TestCaseResult, "@") ; failed to properly seperate implicit from normal affixes
  4863. ; TODO: add more unique item test failure conditions
  4864.  
  4865. If (FailedToSepImplicit)
  4866. {
  4867. Failures += 1
  4868. FailureNumbers := FailureNumbers . A_Index . ","
  4869. }
  4870. Else
  4871. {
  4872. Successes += 1
  4873. }
  4874. ; needed so global variables can be yanked from memory and reset between calls
  4875. ; (if you reload the script really fast globals vars that are out of date can
  4876. ; cause failures where there are none)
  4877. Sleep, 1
  4878. }
  4879.  
  4880. Result := "Suite " . SuiteNumber . ": " . StrPad(Successes, 5, "left") . " OK" . ", " . StrPad(Failures, 5, "left") . " Failed"
  4881. If (Failures > 0)
  4882. {
  4883. FailureNumbers := SubStr(FailureNumbers, 1, -1)
  4884. Result := Result . " (" . FailureNumbers . ")"
  4885. }
  4886. return Result
  4887. }
  4888.  
  4889. RunAllTests()
  4890. {
  4891. ; change this to the number of available test suites
  4892. TestDataBasePath = %A_WorkingDir%\extras\tests
  4893.  
  4894. NumRareTestSuites := 4
  4895. RareResults := "Rare Items"
  4896. Loop, %NumRareTestSuites%
  4897. {
  4898. If (A_Index > 0) ; change condition to only run certain tests
  4899. {
  4900. TestSuitePath = %TestDataBasePath%\Rares%A_Index%.txt
  4901. TestSuiteResult := RunRareTestSuite(TestSuitePath, A_Index)
  4902. RareResults := RareResults . "`n " . TestSuiteResult
  4903. }
  4904. }
  4905.  
  4906. NumUniqueTestSuites := 1
  4907. UniqResults := "Unique Items"
  4908. Loop, %NumUniqueTestSuites%
  4909. {
  4910. If (A_Index > 0) ; change condition to only run certain tests
  4911. {
  4912. TestSuitePath = %TestDataBasePath%\Uniques%A_Index%.txt
  4913. TestSuiteResult := RunUniqueTestSuite(TestSuitePath, A_Index)
  4914. UniqResults := UniqResults . "`n " . TestSuiteResult
  4915. }
  4916. }
  4917.  
  4918. msgbox, %RareResults%`n`n%UniqResults%
  4919. }
  4920.  
  4921. If (RunTests)
  4922. {
  4923. RunAllTests()
  4924. }
  4925.  
  4926. ; ########### TIMERS ############
  4927.  
  4928. ; Tick every 100 ms
  4929. ; Remove tooltip if mouse is moved or 5 seconds pass
  4930. ToolTipTimer:
  4931. ToolTipTimeout += 1
  4932. MouseGetPos, CurrX, CurrY
  4933. MouseMoved := (CurrX - X)**2 + (CurrY - Y)**2 > MouseMoveThreshold**2
  4934. If (MouseMoved or ((UseTooltipTimeout = 1) and (ToolTipTimeout >= ToolTipTimeoutTicks)))
  4935. {
  4936. SetTimer, ToolTipTimer, Off
  4937. ToolTip
  4938. }
  4939. return
  4940.  
  4941. OnClipBoardChange:
  4942. Global OnlyActiveIfPOEIsFront
  4943. If (OnlyActiveIfPOEIsFront)
  4944. {
  4945. ; do nothing if Path of Exile isn't the foremost window
  4946. IfWinActive, Path of Exile ahk_class Direct3DWindowClass
  4947. {
  4948. ParseClipBoardChanges()
  4949. }
  4950. }
  4951. Else
  4952. {
  4953. ; if running tests parse clipboard regardless if PoE is foremost
  4954. ; so we can check individual cases from test case text files
  4955. ParseClipBoardChanges()
  4956. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement